3

I am trying to move object depending on camera position. Here is my vertex shader

uniform mat4 osg_ViewMatrixInverse;

void main(){
vec4 position  = gl_ProjectionMatrix * gl_ModelViewMatrix *gl_Vertex;   
vec3 camPos=osg_ViewMatrixInverse[3].xyz;

if( camPos.z >1000.0 )
  position.z = position.z+1.0;
    if( camPos.z >5000.0 )
  position.z = position.z+10.0;
if (camPos.z< 300.0 )
  position.z = position.z+300.0;
gl_Position =  position;
}

But when camera's vertical position is less than 300 or more than 1000 the model simply disappears though in second case it should be moved just by one unit. I read about inside the shader coordinates are different from a world coordinates that's why i am multiplying by Projection and ModelView matrices, to get the world coordinates. Maybe I am wrong at this point? Forgive me if it's a simple question but i couldnt find the answer.

UPDATE: camPos is translated to world coordinates, but position is not. Maybe it has to do with the fact i am using osg_ViewMatrixInverse (passed by OpenSceneGraph) to get camera position and internal gl_ProjectionMatrix and gl_ModelViewMatrix to get the vertex coordinates? How do I translate position into world coordinates?

Stranger1399
  • 81
  • 2
  • 12

3 Answers3

6

The problem is that you are transforming the position into clip coordinates (by multiplying gl_Vertex by the projection and modelview matrices), then performing a world-coordinate operation on those clip coordinates, which does not give the results you want.

Simply perform your transformations before you multiply by the modelview and projection matrices.

uniform mat4 osg_ViewMatrixInverse;

void main() {
    vec4 position = gl_Vertex;   
    vec3 camPos=osg_ViewMatrixInverse[3].xyz;

    if( camPos.z >1000.0 )
        position.z = position.z+1.0;
    if( camPos.z >5000.0 )
        position.z = position.z+10.0;
    if (camPos.z< 300.0 )
        position.z = position.z+300.0;
    gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * position;
}
Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
  • position is in object space while camera is in world space. The idea is there but it's not going to work – Raxvan Mar 14 '14 at 14:03
  • 1
    Then you'll need to separate the model and view matrix, multiply the position by the model matrix, do your operation, then multiply it by the view and projection matrices. – Colonel Thirty Two Mar 14 '14 at 14:05
  • @Colonel Thirty Two I did like you suggested, now model disappears at the point below 300, and at the point above 1000 happens something strange (I changed that to position.z = position.z+200.0 so it would be easier to spot the difference). The most part of the model is elevated at more than 1000 units and some parts are just "hanging" the air separetly. Idea is there.... How do i separate the model and view matrices? gl doesnt provide them separately. – Stranger1399 Mar 14 '14 at 14:19
  • You will have do the matrix operations yourself (I recommend [GLM](http://glm.g-truc.net/0.9.5/index.html)) then upload them via uniforms. The GL matrix functions are legacy functionality anyway, and are removed in OpenGL 3.1+. – Colonel Thirty Two Mar 14 '14 at 14:26
  • @Colonel Thirty Two Thanks i will try that – Stranger1399 Mar 14 '14 at 14:29
4

gl_Position is in clip-space, the values you output for any coordinate must be >= -gl_Position.W or <= gl_Position.W or they will be clipped. If all of your coordinates for a primitive are outside this range, then nothing will be drawn. The reasoning for this is that after the vertex shader completes, OpenGL divides the clip-space coordinates by W to produce coordinates in the range [-1,1] (NDC). Anything outside this volume will not be on screen.

What you should actually do here is add these coordinates to your object-space position and then perform the transformation from object-space to clip-space. Colonel Thirty Two's answer already does a very good job of showing how to do this; I just wanted to explain exactly why you should not apply this offset to the clip-space coordinates.

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
2

Figured it out:

uniform mat4 osg_ViewMatrixInverse;
uniform mat4 osg_ViewMatrix;

void main(){
    vec3 camPos=osg_ViewMatrixInverse[3].xyz;

    vec4 position_in_view_space = gl_ModelViewMatrix * gl_Vertex;
    vec4 position_in_world_space  = osg_ViewMatrixInverse * position_in_view_space;

    if( camPos.z >1000.0 )
      position_in_world_space.z = position_in_world_space.z+700.0;
    if( camPos.z >5000.0 )
      position_in_world_space.z = position_in_world_space.z+1000.0;
    if (camPos.z< 300.0 )
      position_in_world_space.z = position_in_world_space.z+200;
    position_in_view_space = osg_ViewMatrix * position_in_world_space;
    vec4 position_in_object_space = gl_ModelViewMatrixInverse * position_in_view_space;
    gl_Position = gl_ModelViewProjectionMatrix * position_in_object_space;
}

One needs to transform gl_Vertex (which is in object space coords) into a world coordinates through view space coordinates (maybe there is direct conversion i dont see) than he can modify them and transform back into object space coordinates.

Stranger1399
  • 81
  • 2
  • 12