• Advertisement
Sign in to follow this  

Billboard geometry shader

This topic is 2348 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm writing my first geometry shader in glsl. I want to extrude points uploaded to the gpu to two triangles facing the camera (spherical billboards). The idea is to calculate the three axes of the billboard (typical lookat() function) and then position the vertices along these axes. What i've got somehow works but the billboards start rotating in the wrong direction when the camera moves close and/or spin around their z axis. Any ideas what i'm missing? What bothers me is that the camera's rotation is not considered; shouldn't the billboards' rotation have to be influenced by that?

Thanks!

#version 330 core

layout (points) in;
layout (triangle_strip) out;
layout (max_vertices = 4) out;

layout(std140) uniform;

uniform Transform
{
mat4 view;
mat4 model;

vec4 animate;
mat4 bones[64];
} transform;

uniform Projection
{
mat4 perspective;
mat4 orthographic;
} projection;

uniform vec3 cameraPosition;

out vec2 textureCoords;

void main()
{
mat4 mvp = projection.perspective*transform.view*transform.model;

vec3 center = gl_in[0].gl_Position.xyz;

vec3 zAxis = normalize( cameraPosition-center );
vec3 yAxis = vec3( 0.0, 1.0, 0.0 );
vec3 xAxis = normalize( cross(zAxis, yAxis) );

yAxis = normalize( cross(xAxis, zAxis) );

vec3 x = xAxis*0.5;
vec3 y = yAxis*0.5;

gl_Position = mvp*vec4( center-x-y, 1.0 );
textureCoords = vec2( 0.0, 0.0 );
EmitVertex();

gl_Position = mvp*vec4( center-x+y, 1.0 );
textureCoords = vec2( 0.0, 1.0 );
EmitVertex();

gl_Position = mvp*vec4( center+x-y, 1.0 );
textureCoords = vec2( 1.0, 0.0 );
EmitVertex();

gl_Position = mvp*vec4( center+x+y, 1.0 );
textureCoords = vec2( 1.0, 1.0 );
EmitVertex();

EndPrimitive();
}


This is what it looks like atm:

billboards.jpg

Share this post


Link to post
Share on other sites
Advertisement
I think the difference in what you are getting and what you want is that you are doing the expansion in world space instead of in view space. Your input point should already be in view space (from a previous pipeline stage), then you create your new vertices and offset them (in view space), and finally transform them only with the projection matrix. Then they will appear to be aligned with the viewing plane, which I think is what you are after.

Share this post


Link to post
Share on other sites
Thanks for the input! What you're saying makes perfect sense. I've changed my shaders (see below) but the billboards are still not always facing the camera.. rather, they seem to be rotated in the wrong direction along the y-axis, and I'm not sure why.

Vertex shader:
#version 330 core

layout(location = 0) in vec4 in_vertexPos;

uniform Transform
{
mat4 view;
mat4 model;

vec4 animate;
mat4 bones[64];
} transform;

void main()
{
mat4 modelViewMatrix = transform.view*transform.model;
gl_Position = modelViewMatrix*vec4( in_vertexPos.xyz, 1.0 );
}


Geometry shader:
#version 330 core

layout (points) in;
layout (triangle_strip) out;
layout (max_vertices = 4) out;

layout(std140) uniform;

uniform Projection
{
mat4 perspective;
mat4 orthographic;
} projection;

uniform vec3 cameraPosition;

out vec2 textureCoords;

void main()
{
mat4 p = projection.perspective;

vec3 center = gl_in[0].gl_Position.xyz;

vec3 zAxis = normalize( cameraPosition-center );
vec3 yAxis = vec3( 0.0, 1.0, 0.0 );
vec3 xAxis = normalize( cross(zAxis, yAxis) );

yAxis = normalize( cross(xAxis, zAxis) );

vec3 x = xAxis*0.5;
vec3 y = yAxis*0.5;

gl_Position = p*vec4( center-x-y, 1.0 );
textureCoords = vec2( 0.0, 0.0 );
EmitVertex();

gl_Position = p*vec4( center-x+y, 1.0 );
textureCoords = vec2( 0.0, 1.0 );
EmitVertex();

gl_Position = p*vec4( center+x-y, 1.0 );
textureCoords = vec2( 1.0, 0.0 );
EmitVertex();

gl_Position = p*vec4( center+x+y, 1.0 );
textureCoords = vec2( 1.0, 1.0 );
EmitVertex();

EndPrimitive();
}

Share this post


Link to post
Share on other sites
I used a very different approach in the end; someone gave me a good tip on the OpenGL forums:

#version 330 core

layout (points) in;
layout (triangle_strip) out;
layout (max_vertices = 4) out;

layout(std140) uniform;

uniform Display
{
vec2 area;
vec2 oneOverArea;
} display;

uniform Projection
{
mat4 perspective;
mat4 orthographic;
} projection;

uniform Transform
{
mat4 view;
mat4 model;

vec4 animate;
mat4 bones[64];
} transform;

uniform bool forceSize = false;
uniform ivec2 spriteSize = ivec2( 128, 128 );

out Vertex
{
vec2 textureCoords;
} vertex;

void main()
{
vec3 pos = gl_in[0].gl_Position.xyz;

mat4 modelView = transform.view*transform.model;
mat4 modelViewProjection = projection.perspective*modelView;

vec4 clip = modelViewProjection*vec4( pos, 1.0 );

float dx = spriteSize.x*display.oneOverArea.x;
float dy = spriteSize.y*display.oneOverArea.y;

if( forceSize )
{
dx *= 0.5*clip.w;
dy *= 0.5*clip.w;
}

gl_Position = vec4( clip.x-dx, clip.y-dy, clip.z, clip.w );
vertex.textureCoords = vec2( 0.0, 0.0 );
EmitVertex();

gl_Position = vec4( clip.x-dx, clip.y+dy, clip.z, clip.w );
vertex.textureCoords = vec2( 0.0, 1.0 );
EmitVertex();

gl_Position = vec4( clip.x+dx, clip.y-dy, clip.z, clip.w );
vertex.textureCoords = vec2( 1.0, 0.0 );
EmitVertex();

gl_Position = vec4( clip.x+dx, clip.y+dy, clip.z, clip.w );
vertex.textureCoords = vec2( 1.0, 1.0 );
EmitVertex();

EndPrimitive();
}

Share this post


Link to post
Share on other sites
glad to see you got there in the end, its actually quite simple, as is good as a first algorythm with the geometry shader. :-)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement