1
\$\begingroup\$

I am currently drawing texture in 3D space and have some problems with it's orientation.

I'd like me textures always to be oriented with front face to user.

My desirable result looks like enter image description here enter image description here

Note, that text size stay without changes when we rotating world and stay oriented with front face to user.

Now I can draw text in 3D space, but it is not oriented with front but rotating with world.

enter image description here enter image description here

Such results I got with following shaders:

Vertex Shader

uniform vec3 Position;

void main()                     
{
    gl_Position = vec4(Position, 1.0);
}

Geometry Shader

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

out vec2 fsTextureCoordinates;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform sampler2D og_texture0;
uniform float og_highResolutionSnapScale;
uniform vec2 u_originScale;

void main()
{
    vec2 halfSize = vec2(textureSize(og_texture0, 0)) * 0.5 * og_highResolutionSnapScale;
    vec4 center = gl_in[0].gl_Position;
    center.xy += (u_originScale * halfSize);

    vec4 v0 = vec4(center.xy - halfSize, center.z, 1.0);
    vec4 v1 = vec4(center.xy + vec2(halfSize.x, -halfSize.y), center.z, 1.0);
    vec4 v2 = vec4(center.xy + vec2(-halfSize.x, halfSize.y), center.z, 1.0);
    vec4 v3 = vec4(center.xy + halfSize, center.z, 1.0);

    gl_Position =  projectionMatrix * modelViewMatrix   * v0;
    fsTextureCoordinates = vec2(0.0, 0.0);
    EmitVertex();

    gl_Position =  projectionMatrix * modelViewMatrix   * v1;
    fsTextureCoordinates = vec2(1.0, 0.0);
    EmitVertex();

    gl_Position =  projectionMatrix * modelViewMatrix   * v2;
    fsTextureCoordinates = vec2(0.0, 1.0);
    EmitVertex();

    gl_Position =  projectionMatrix * modelViewMatrix  * v3;
    fsTextureCoordinates = vec2(1.0, 1.0);
    EmitVertex();
}

Fragment Shader

in vec2 fsTextureCoordinates;

out vec4 fragmentColor;

uniform sampler2D og_texture0;
uniform vec3 u_color;

void main()
{
    vec4 color = texture(og_texture0, fsTextureCoordinates);

    if (color.a == 0.0)
    {
        discard;
    }
    fragmentColor = vec4(color.rgb * u_color.rgb, color.a);    
}

Any ideas how to get my desirable result?

EDIT 1:

I make edit in my geometry shader and got part of lable drawn on screen at corner. But it is not rotating.

..........

    vec4 centerProjected = projectionMatrix * modelViewMatrix * center;
    centerProjected /= centerProjected.w;

    vec4 v0 = vec4(centerProjected.xy - halfSize, 0.0, 1.0);
    vec4 v1 = vec4(centerProjected.xy + vec2(halfSize.x, -halfSize.y), 0.0, 1.0);
    vec4 v2 = vec4(centerProjected.xy + vec2(-halfSize.x, halfSize.y), 0.0, 1.0);
    vec4 v3 = vec4(centerProjected.xy + halfSize, 0.0, 1.0);

    gl_Position =  og_viewportOrthographicMatrix * v0;

..........

enter image description here enter image description here

\$\endgroup\$
3
  • \$\begingroup\$ Do you need the text to become smaller as the camera gets farther away as well? \$\endgroup\$ Aug 21, 2014 at 12:49
  • \$\begingroup\$ no, I need constant text size as on example snapshots. \$\endgroup\$
    – frankie
    Aug 21, 2014 at 12:56
  • \$\begingroup\$ If that is the case, then what you want to do is to project center before creating the rest of the vertices \$\endgroup\$ Aug 21, 2014 at 13:02

1 Answer 1

1
\$\begingroup\$

I mostly work on GLES where we don't have geometry shaders, so don't expect my code to work as-is.

The problem is that you're creating the vertices in world space (3D), and then projecting them independently.

If you want your text to be facing the camera regardless of the camera settings, then you want to create your vertices in screen space (2D), not world space.

You already know how to project a point, so instead of projecting each of the 4 vertices, you just project the center, divide by w (important), and then you just keep x and y:

vec4 center = gl_in[0].gl_Position;
vec4 centerProjected = projectionMatrix * modelViewMatrix * center;
centerProjected /= centerProjected.w;

Once you're in screen space, you create your other vertices in screen space:

vec4 v0 = vec4(centerProjected.xy - halfSize, 0.0, 1.0);
vec4 v1 = vec4(centerProjected.xy + vec2(halfSize.x, -halfSize.y), 0.0, 1.0);
vec4 v2 = vec4(centerProjected.xy + vec2(-halfSize.x, halfSize.y), 0.0, 1.0);
vec4 v3 = vec4(centerProjected.xy + halfSize, 0.0, 1.0);

Notice that now that we're on screen space, z becomes mostly meaningless, so I set it at 0.

All that is left is to emit the vertices:

gl_Position = v0;
fsTextureCoordinates = vec2(0.0, 0.0);
EmitVertex();

gl_Position = v1;
fsTextureCoordinates = vec2(1.0, 0.0);
EmitVertex();

gl_Position = v2;
fsTextureCoordinates = vec2(0.0, 1.0);
EmitVertex();

gl_Position = v3;
fsTextureCoordinates = vec2(1.0, 1.0);
EmitVertex();

I'm not sure if the size of the sprite will be correct, because now you're working on screen space, which goes from -0.5 to 0.5, but you should get the idea.

Also notice that for this technique you don't need to have separate projection and world-view matrices, so if you want to, you can mix them into one world-view-projection matrix before you pass it to the shaders.

\$\endgroup\$
1
  • \$\begingroup\$ after your suggested modification I saw nothing on my screen :( But with my new edits I get something looks like as desirable, but my label it is static and it is not rotating. Please take a look on my edits. \$\endgroup\$
    – frankie
    Aug 21, 2014 at 19:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .