Skip to main content

Vertex Stage

The gsplatModifyVS chunk customizes splats in the vertex stage. It runs once per splat, making it the right place to move, rotate, scale, hide or tint whole splats.

View Live Example - See shader chunk customization in action with animated splats.

Multi Splat

Overridable Functions

The gsplatModifyVS chunk lets you override three functions:

FunctionPurpose
modifySplatCenterTransform the splat center position (model space)
modifySplatRotationScaleAdjust the splat rotation quaternion and scale
modifySplatColorTransform the splat color and opacity
void modifySplatCenter(inout vec3 center);
void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale);
void modifySplatColor(vec3 center, inout vec4 color);

You only need to implement the functions you want to change.

How the Example Works

The live example above animates every splat with a sine-wave displacement and a golden color pulse. It comes together in three steps.

1. Write the shader chunk, overriding the functions you need. The example animates using a uTime uniform:

uniform float uTime;

void modifySplatCenter(inout vec3 center) {
float heightIntensity = center.y * 0.2;
center.x += sin(uTime * 5.0 + center.y) * 0.3 * heightIntensity;
}

void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale) {
// no modification
}

void modifySplatColor(vec3 center, inout vec4 clr) {
float sineValue = abs(sin(uTime * 5.0 + center.y));
vec3 gold = vec3(1.0, 0.85, 0.0);
float blend = smoothstep(0.9, 1.0, sineValue);
clr.xyz = mix(clr.xyz, gold, blend);
}

2. Apply the chunk to the scene gsplat material, then update the material so it recompiles. Setting both the GLSL and WGSL chunk covers WebGL and WebGPU devices:

const sceneMat = app.scene.gsplat.material;

sceneMat.getShaderChunks('glsl').set('gsplatModifyVS', glslVertShader);
sceneMat.getShaderChunks('wgsl').set('gsplatModifyVS', wgslVertShader);
sceneMat.update();

3. Drive any uniforms each frame:

let currentTime = 0;
app.on('update', (dt) => {
currentTime += dt;
sceneMat.setParameter('uTime', currentTime);
sceneMat.update();
});

See Also