Billboarding restricted to an axis (cylindrical)

I have succesfully created a GLSL shader for a billboarding effect. I want to tweak this to restrict the billboarding to an arbitrary axis, i.e. a billboarded quad only rotates itself about the y-axis. I use the y-axis as an example, but essentially I would like this to be an arbitrary axis. Can anyone show me how to modify my existing shader below, or if I need to start from scratch, point me towards some resources that could be helpful?

precision mediump float;

uniform mat4 u_modelViewProjectionMat;
uniform mat4 u_modelMat;
uniform mat4 u_viewTransposeMat;

uniform vec3 u_axis; // <------------ !!! the arbitrary axis to restrict rotation around

attribute vec3 a_position0;
attribute vec2 a_texCoord0;

varying vec2 v_texCoord0;

void main()
{
vec3 pos = (a_position0.x * u_viewTransposeMat[0] + a_position0.y * u_viewTransposeMat[1]).xyz;
vec4 position = vec4(pos, 1.0);

v_texCoord0 = a_texCoord0;

gl_Position = u_modelViewProjectionMat *  position;
}


EDIT - The modified shader for cylindrical billboarding. Its very straight forward! Just swap out the up vector for the axis to restrict rotation about.

precision mediump float;

uniform mat4 u_modelViewProjectionMat;
uniform mat4 u_modelMat;
uniform mat4 u_viewTransposeMat;

uniform vec3 u_axis; // <------------ !!! the arbitrary axis to restrict rotation around

attribute vec3 a_position0;
attribute vec2 a_texCoord0;

varying vec2 v_texCoord0;

void main()
{
vec3 pos = (a_position0.x * u_viewTransposeMat[0] + a_position0.y * vec4(normalize(u_axis), 0.0)).xyz;
vec4 position = vec4(pos, 1.0);

v_texCoord0 = a_texCoord0;

gl_Position = u_modelViewProjectionMat *  position;
}


While I ended up with a similar approach to yours, I can tell you about an implementation I went through on my way there. It's probably a bit simpler to understand, so it should be easier to modify.

Basically, I use the normal of the vertex to tell the vertices which way to shift in the view plane. More specifically, that can be done like this:

float xVal = Position.x - ((CameraRight.x * Normal.x) + (CameraUp.x * Normal.y));
float yVal = Position.y - ((CameraRight.y * Normal.x) + (CameraUp.y * Normal.y));
float zVal = Position.z - ((CameraRight.z * Normal.x) + (CameraUp.z * Normal.y));
vec4 vertexPos = vec4(xVal, yVal, zVal, 1.0);
gl_Position = ProjectionMatrix * ModelViewMatrix * vertexPos;


Where I'm setting the camera up and camera right as uniforms at the beginning of each frame. The normal positions are set like so:

//position x, y and z, then normal x, y, and z then float2 texture coords, then color
billboards.add(pos.x, pos.y, pos.z, bbhs, -bbhs, 0, texture[0], backColor);
billboards.add(pos.x, pos.y, pos.z, bbhs, bbhs, 0, texture[1], backColor);
billboards.add(pos.x, pos.y, pos.z, -bbhs, -bbhs, 0, texture[2], backColor);
billboards.add(pos.x, pos.y, pos.z, -bbhs, bbhs, 0, texture[3], backColor);


You could easily modify the axis being modified by changing the normal coordinates. Or if you only wanted the y axis, you always pass the camera up as (0,1,0).

• Ahhh, its so simple! Just need to change the up vector to my direction vector. Thanks for putting me on the right track! – user8709 Oct 23 '12 at 5:06