Working on a solar system project and I’ve just implemented a billboard vertex shader. The billboard works as it should, it is pointed parallel to the camera viewing angle. However I want to make it point towards the camera.

I can get a vector from the camera position to the center of the object but from there I don’t know where to head. Maybe create a rotation matrix from that???

Here are the images showing the problem.
The first one is the viewing with the sun as the focus, however when I focus other planes, the billboard doesn’t point towards the camera.

imgurDOTcom/a/Lp0mZ ( i wish they weren’t so restrictive with links and images)

You can’t determine the rotation simply from a vertex position. You need at least the object-space position of the billboard’s centre and the position of the vertex within the billboard (i.e. which corner it is). The latter might be uvIn if the billboard maps to the complete texture (i.e. the four vertices have uvIn equal to one of (0,0), (1,0), (0,1) or (1,0))

If the billboard is aligned to the screen, then just transform the centre position to eye space and offset it by the relative vertex position.

E.g.

in vec3 centerIn;
in vec2 uvIn;
uniform mat4 proj;
uniform mat4 modelview;
uniform float scale;
void main()
{
vec4 c = modelview * vec4(centerIn, 1.0);
vec4 p = c + vec4((uvIn * 2 - 1) * scale, 0.0, 0.0);
gl_Position = proj * p;
}

If the billboard is aligned to the world, it’s slightly more complex (and you have the issue that the orientation is undefined if the up vector points directly towards the camera).

E.g.

in vec3 centerIn;
in vec2 uvIn;
uniform mat4 proj;
uniform mat4 modelview;
uniform vec3 up;
uniform float scale;
void main()
{
vec4 c = modelview * vec4(centerIn, 1.0);
vec4 u = modelview * vec4(up, 0.0); // w=0 as this is a direction, not a position
vec2 y = normalize(u.xy); // this will fail if the transformed up vector is (0,0,z)
mat2 m = mat2(y.y, -y.x, y.x, y.y);
vec4 p = c + vec4(m * (uvIn * 2 - 1) * scale, 0.0, 0.0);
gl_Position = proj * p;
}

The first shader you gave me does exactly what my current one does. However the second one seems to stick the billboard to my screen but not around the sun. So when I move to a new planet, it is still in the left hand side of the screen, and not around the sun. For the second shader, what would be the up vector? The camera up vector?

The second shader is identical to the first, except that it rotates the billboard so that the billboard’s orientation is fixed in model space rather than screen space. The up vector is a vector in model space which determines the billboard’s orientation.

The first shader is appropriate for e.g. labels which should follow a particular point in world space but be oriented in screen space. The second shader is appropriate for billboards which should also be oriented in world-space (e.g. pre-rendered objects).

[QUOTE=GClements;1280383]The second shader is identical to the first, except that it rotates the billboard so that the billboard’s orientation is fixed in model space rather than screen space. The up vector is a vector in model space which determines the billboard’s orientation.

The first shader is appropriate for e.g. labels which should follow a particular point in world space but be oriented in screen space. The second shader is appropriate for billboards which should also be oriented in world-space (e.g. pre-rendered objects).[/QUOTE]

Ok, I made a mistake using the second shader. They now both look identical. However, the billboard is still not facing the camera, but is instead parallel to it. Here is what I mean.
[ATTACH=CONFIG]1322[/ATTACH]

vec4 c = modelview * vec4(centerIn, 1.0);
vec4 u = modelview * vec4(up, 0.0); // w=0 as this is a direction, not a position
vec3 z = -c.xyz;
vec3 x = normalize(cross(u, z));
vec3 y = normalize(cross(z, y));
mat2x3 m = mat2x3(x, y);
vec4 p = c + vec4(m * (uvIn * 2 - 1) * scale, 0.0);
gl_Position = proj * p;

At vec3 x = normalize(cross(u, z)); you do the cross of a 4d vecotor(u) with a 3d vector(z), I assume you want the xyz of u. vec3 x = normalize(cross(u.xyz, z));
At vec3 y = normalize(cross(z, y)); you declare y as a normalized cross of z and y, that cant be done. Did you mean to use the y from “vec2 y = normalize(u.xy);” but if you did that would make y a 2d vector, which wouldn’t work.

[QUOTE=GClements;1280397]Yes; good catch. For some reason, AMD’s GLSL didn’t notice that.

Sorry, that should be:

vec3 y = normalize(cross(z, x));

(the compiler did pick that one up; I forgot to copy the change to my post).[/QUOTE]

It worked. Thank you very much GClements.

For anyone interested, here is the final code.

#version 330
in vec3 vertIn;
in vec2 uvIn;
uniform mat4 proj;
uniform mat4 model;
uniform mat4 view;
uniform float scale;
uniform vec3 center;
uniform vec3 up;
out vec2 uv;
void main()
{
mat4 modelview = view * model;
vec4 c = modelview * vec4(center, 1.0);
vec4 u = modelview * vec4(up, 0.0); // w=0 as this is a direction, not a position
vec3 z = -c.xyz;
vec3 x = normalize(cross(u.xyz, z));
vec3 y = normalize(cross(z, x));
mat2x3 m = mat2x3(x, y);
vec4 p = c + vec4(m * (vertIn.xy) * scale, 0.0);
gl_Position = proj * p;
uv = uvIn;
}

“center” is the center of the rectangle in world coordinates. “up” is the up vector in object coordinates. The “vertIn” are the vertices of the billboard in 2d object space. Ex. x,y,0. The position of each vertex is ultimately determined by the it’s “center” and offset by each of its “vertIn”. The “scale” is used to scale the billboard. For example the mesh of the sun is a sphere with a radius of 1 (diameter of 2), that is scaled up by 40. The other planets are the same mesh with a different scale. When I create the vertices of the billboard, I create a square the length of 2 and pass in the sun’s scale to the shader.