Sign in to follow this  

GLSL ES shader based camera question

This topic is 687 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

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 Edited by DarkRonin

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites

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. 

Edited by Nanoha

Share this post


Link to post
Share on other sites
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 Edited by DarkRonin

Share this post


Link to post
Share on other sites


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. 

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

I expect what is going on is that the shader has decided to compile the entire expression [tt](identity * world * view * projection)[/tt], and all of the calculations that go into it, into a single constant matrix.

 

This is a pretty normal compiler optimisation, since all of your inputs are constant at that point. And then the rest of the shader boils down to a single matrix<->vector multiply, and storing a couple of values.

 

I wouldn't rely on every shader compiler to get this right, and if you make any of those input non-constant (say, to move the camera around), then you will see a massive performance hit.

Share this post


Link to post
Share on other sites

I expect what is going on is that the shader has decided to compile the entire expression [tt](identity * world * view * projection)[/tt], and all of the calculations that go into it, into a single constant matrix.
 
This is a pretty normal compiler optimisation, since all of your inputs are constant at that point. And then the rest of the shader boils down to a single matrix<->vector multiply, and storing a couple of values.
 
I wouldn't rely on every shader compiler to get this right, and if you make any of those input non-constant (say, to move the camera around), then you will see a massive performance hit.


It is interesting, because I am now moving the object (120K poly) and camera around via their own uniforms and the performance is still the same.

Having said that, the camera system isn't complete yet (fixed look at, no rotations etc..). So, maybe the performance will dive when it becomes more functional.

Share this post


Link to post
Share on other sites

This topic is 687 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this