GLSL ES shader based camera question

Started by
10 comments, last by DividedByZero 8 years, 2 months ago
Hi Guys,

I am in the process of trying to make a GLSL ES based camera system but have run in to a little snag (coming from a basic HLSL background).

This is what I have so far. It is incomplete as I haven't accounted for View and Projection yet (that will come when I get past this hiccup).

The problem that I am having is that the return type of gl_Position (as required in GameMaker) is a type of vec4 but the matrices I am using are of mat4 type. Thus, resulting in a compilation error.



attribute vec3 in_Position;                  // Vertex position in its own local space

uniform float xx;
uniform float yy;
uniform float zz;

void main()
{
    mat4 identity;
    mat4 world;
    mat4 view;
    mat4 projection;
   
    identity = mat4(
       1.0, 0.0, 0.0, 0.0,  // first column (not row!)
       0.0, 1.0, 0.0, 0.0,  // second column
       0.0, 0.0, 1.0, 0.0,  // third column
       0.0, 0.0, 0.0, 1.0   // third column
    );
   
    // Translation matrix (world matrix)
    world = mat4(
        1.0, 0.0, 0.0, in_Position.x + xx,
        0.0, 1.0, 0.0, in_Position.y + yy,
        0.0, 0.0, 1.0, in_Position.z + zz,
        0.0, 0.0, 0.0, 1.0
    );
   
    gl_Position = identity * world;     // This results in an error of vec4 not being compatible with mat4 (which is fair enough)
    //gl_Position = vec4(identity * world);     // This results in a hang eventually resulting in a generic error - with no other explanation
}

Could you please advise if I am on the right track?

And any help is always greatly appreciated.

Thanks in advance smile.png
Advertisement
Trying this: gl_Position = identity * world * vec4(in_Position,1);
Thanks Ashaman73, seems to be compiling happier now.

I'll plug away and see if I can now get this camera working properly smile.png
I now have this (along with a blank screen - LOL).

If you guru's could shed a glance over this and see if anything stands out, that would be awesome! smile.png


attribute vec3 in_Position;                  // Vertex position in its own local space
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    mat4 identity;
    mat4 world;
    mat4 view;
    mat4 projection;
    
    float xx=0.0;
    float yy=0.0;
    float zz=10.0;
    
    float camX = 0.0;
    float camY = 0.0;
    float camZ = 0.0;
    
    identity = mat4(
       1.0, 0.0, 0.0, 0.0,  // first column (not row!)
       0.0, 1.0, 0.0, 0.0,  // second column
       0.0, 0.0, 1.0, 0.0,  // third column
       0.0, 0.0, 0.0, 1.0   // third column
    );
    
    // Translation matrix (world matrix)
    world = mat4(
        1.0, 0.0, 0.0, xx,
        0.0, 1.0, 0.0, yy,
        0.0, 0.0, 1.0, zz,
        0.0, 0.0, 0.0, 1.0
    );
    
    view = mat4(
        0.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0,
        camX, camY, camZ, 1.0
    );
    
    float near_plane = 1.0;
    float far_plane = 1000.0;
    
    float aspectRatio = 1024.0 / 768.0;
    float DEG2RAD = 3.14159 / 180.0;
    float fov = 60.0/DEG2RAD;
    float h = cos(0.5*fov)/sin(0.5*fov);
    float w = h * aspectRatio;
    float a =  - (near_plane+far_plane)/(near_plane - far_plane);
    float b = - ((2.0*far_plane*near_plane)/(far_plane-near_plane));

    projection = mat4(
        w, 0, 0, 0,
        0, h, 0, 0,
        0, 0, a, 1,
        0, 0, b, 0
    );
    
    gl_Position = identity * world * view * projection * vec4(in_Position,1);


    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}

Your translation matrix is wrong, it is transposed.

Instead of


world = mat4(
        1.0, 0.0, 0.0, xx,
        0.0, 1.0, 0.0, yy,
        0.0, 0.0, 1.0, zz,
        0.0, 0.0, 0.0, 1.0
    );

It should be


world = mat4(
        1.0, 0.0, 0.0, 0,
        0.0, 1.0, 0.0, 0,
        0.0, 0.0, 1.0, 0,
        xx, yy, zz, 1.0
    );

Since the matrices are column major in GLSL.

Don't take my word on this but I do believe the camera's translation needs to be negative too.


 view = mat4(
        1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        -camX, -camY, -camZ, 1.0
    );

Also you were missing the 1s in the diagonal of that which would end up flattening your whole world to nothing.

The order you multiply the matrices at the end looks odd too, it should be world->view->projection (remove identity, it does nothing) but since matrix multiplication is somewhat order backwards it should be:

projection*view*world*position.

I think you can multiply in your order if your matrices are transposed though so something to double check (I get confused in this myself).

Make sure your matrices are all of one form (either column or row major) since your view matrix and world matrix are currently contradicting.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Thanks for the advice. Going to play with it now. smile.png

Out of interest, performance-wise, would doing all of this in shader be worse as each matrix is calculated per vertex (rather than once and then passed to the shader?)

Either way I'll follow through with this method for now, as it is greatly helping my understanding on the subject.


[edit]
This is what I have now, but still nothing displaying unfortunately.


attribute vec3 in_Position;                  // Vertex position in its own local space
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    mat4 identity;
    mat4 world;
    mat4 view;
    mat4 projection;
    
    float xx=0.0;
    float yy=0.0;
    float zz=10.0;
    
    float camX = 0.0;
    float camY = 0.0;
    float camZ = 0.0;
    
    identity = mat4(
       1.0, 0.0, 0.0, 0.0,
       0.0, 1.0, 0.0, 0.0,
       0.0, 0.0, 1.0, 0.0,
       0.0, 0.0, 0.0, 1.0
    );
    
    world = mat4(
        1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        xx, yy, zz, 1.0
    );

    view = mat4(
        1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        -camX, -camY, -camZ, 1.0
    );
    
    float near_plane = 1.0;
    float far_plane = 1000.0;
    
    float aspectRatio = 1024.0 / 768.0;
    float DEG2RAD = 3.14159 / 180.0;
    float fov = 60.0/DEG2RAD;
    float h = cos(0.5*fov)/sin(0.5*fov);
    float w = h * aspectRatio;
    float a =  - (near_plane+far_plane)/(near_plane - far_plane);
    float b = - ((2.0*far_plane*near_plane)/(far_plane-near_plane));

    projection = mat4(
        w, 0, 0, 0,
        0, h, 0, 0,
        0, 0, a, 1,
        0, 0, b, 0
    );

   gl_Position = projection * view * world * vec4(in_Position,1);
   

    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}
Guys, your help is greatly appreciated so far smile.png

[edit]
Ooh, actually with a bit of tinkering I can now see the object on the screen! Thanks again guys, cant thank you enough. smile.png


Out of interest, performance-wise, would doing all of this in shader be worse as each matrix is calculated per vertex (rather than once and then passed to the shader?)

Your projection matrix should definitely be created once before hand and passed in as a uniform. There is probably no need to even create it more than once at the start of your game, let alone once per vertex (although sometimes you may need to rebuild it). The view matrix probably doesn't need to be updated more than once per frame. The world/model matrix will be quite happy being once per object too.

You could multiply them all before hand and just pass in the result (as a model-view-projection matrix), it will be better performance wise. You could also precompute the projection*view once per frame too which will save you a multiplication per object.

If you really need more performance (you don't sound like you do though), then you can do your own custom multiplications by exploiting all those 0s in each matrix.

To multiply two generic 4x4 matrices together takes 64 individual multiplications and 48 additions. Graphics cards are optimized to do this but it's still a lot of work for no reason.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Yeah, I wasn't too concerned about performance with all of this. It was more a task of seeing if it could be done and to enforce the learning process.

It just sparked ideas of the possibility of creating a fish eye camera or the likes of which you couldn't do without distorting a render target texture etc...

I'd imagine performance would dive dramatically with models with a high vertex count.

So far it has been a fun learning experience though smile.png
Funnily enough, I just tried a little stress test and the 'real world' performance with this shader based camera system was on par with the non shader based one when using a model with 120,000 triangles and that's with the inneficiencies I currently have in the shader, having every matrix re-calculated per vertex per frame.

Funnily enough, I just tried a little stress test and the 'real world' performance with this shader based camera system was on par with the non shader based one when using a model with 120,000 triangles and that's with the inneficiencies I currently have in the shader, having every matrix re-calculated per vertex per frame.

Interesting result. I wonder if the shader is able to hard code some of the things it does. It could be working out the view and camera matrix in advance and even doing the multiplication before hand too. I'll be interesting to see if there is a difference when you start setting the values (camera position, fov etc) through uniforms since it won't be able to optimize that stuff out then.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

This topic is closed to new replies.

Advertisement