# Vertex shader billboard towards camera position (for VR)

Does anyone have sample vertex shader code for billboarding towards the camera position? To note: this is different that regular billboarding which normally billboards against the cameras view direction- for VR pointing towards the camera produces the desired effect I’m after.

I was able to get it working, sharing solution here for others.

You would need to pass in the `modelMatrixInverse` to be able to transform the `cameraPosition` into local model space and create a local lookAtMatrix to transform vertices.

In the code example below, I am using the shader on an `InstancedBufferGeometry` of a Quad to create a number of particles to look at the camera.

To note: `position` is the quads vertices’ positions (-1,-1),(1,-1) … and `aPosition` is the instance attribute to define the local position of each quad/particle in the geometry.

``````var lookAtMat = new THREE.ShaderMaterial({
uniforms: {
"modelMatrixInverse": { value : new THREE.Matrix4() }
},
`
uniform mat4 modelMatrixInverse;
attribute vec3 aPosition;

void main(){

vec4 camLocalPosition = modelMatrixInverse*vec4(cameraPosition, 1);
vec3 localUpVector = vec3(0, 1, 0);

// Create LookAt matrix. (target is cam, from is instance center)
vec3 camVec = camLocalPosition.xyz - aPosition;

vec3 zaxis = normalize(camVec);
vec3 xaxis = normalize(cross(localUpVector, zaxis));
vec3 yaxis = cross(zaxis, xaxis);

mat3 lookAtMatrix = mat3(xaxis, yaxis, zaxis);

// LONG FORM:
// mat3 lookAtMatrix = mat3(
//   xaxis.x, xaxis.y, xaxis.z,
//   yaxis.x, yaxis.y, yaxis.z,
//   zaxis.x, zaxis.y, zaxis.z
// );

vec3 transformLocal = lookAtMatrix * position + aPosition;

gl_Position = projectionMatrix * modelViewMatrix * vec4(transformLocal, 1);
}
`,
});`
``````

To update the matrix inverse, you can update the `modelMatrixInverse` uniform in `onBeforeRender` for the mesh.

``````var updateUniforms = function( renderer, scene, camera, geometry, material, group ) {
// by default this happens automatically : mesh.updateMatrixWorld(true);
var u = material.uniforms;
u.modelMatrixInverse.value.getInverse(mesh.matrixWorld);
u.uniformsNeedUpdate = true; // Only works for ShaderMaterial
}

mesh.onBeforeRender = updateUniforms;``````
1 Like