Sign in to follow this  
Pateman

OpenGL [OpenGL 3.x] Camera Matrix Problem

Recommended Posts

Pateman    184
Hello to all members of Gamedev.net! :D My name is Patryk and I'm new here. I started programming in OGL 3.x and encountered a problem with the camera matrix. Here's the code I'm using to calculate the matrix (in Delphi):
{ .: TMainForm.Render :. }
procedure TMainForm.Render;
var
  ProjMat, Cam, ModelView: TMatrix;
begin
  glViewport(0, 0, ClientWidth, ClientHeight);
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  //  Projection update
  if (ClientHeight <= 0) then
    ClientHeight := 1;
  ProjMat := MatrixProjection(40.0, ClientWidth / ClientHeight, 0.1, 1000.0);

  //  Camera transformations
  Cam := MatrixTransform(VectorNegate(Camera.Pos), VectorCreate(Camera.Pitch,
    Camera.Yaw, 0.0), VectorUniform(1.0));
  ModelView := MatrixTransform(VectorCreate(0.0, 0.0, 0.0),
    VectorCreate(0.0, TriangleRot, 0.0), VectorUniform(0.5));
  ModelView := MatrixMultiply(ModelView, Cam);
  ModelView := MatrixMultiply(ModelView, ProjMat);

  //  Update the shader
  glUniformMatrix4fv(glGetUniformLocation(ShaderManager.GLSLPrograms['minimal'].
    ProgramHandle, 'mvpmatrix'), 1, ByteBool(GL_FALSE), @ModelView);

  //  Render the triangle
  glBindVertexArray(TriangleVAO);
	glDrawArrays(GL_TRIANGLES, 0, 3);
  glBindVertexArray(0);
end;
And here's the code of my vertex shader:
#version 150

precision highp float;

uniform mat4 mvpmatrix;

in vec3 in_Position;
in vec3 in_Color;

out vec3 ex_Color;
void main(void) {
	gl_Position = mvpmatrix * vec4(in_Position, 1.0);

	ex_Color = in_Color;
}
The thing is that whenever I change either the Camera.Pitch or Camera.Yaw values, the object rotates instead of the camera. How do I change the code so that I have a Quake-like FPS camera?

Share this post


Link to post
Share on other sites
jyk    2094
Does the math library that you're using assume the use of column vectors, or row vectors? It looks like your code assumes row vectors, so you might double-check and make sure this matches the convention that the math library uses. (Another thing to double-check is that the matrix layout in memory matches what OpenGL is expecting.)

I'm not sure what the MatrixTransform() function does internally, but it looks like you might be setting up your 'Cam' matrix incorrectly as well (simply negating the translation vector won't necessarily create the inverse transform you're looking for). Assuming you have a matrix inversion function available, try something like this instead:
Cam := MatrixTransform(
Camera.Pos, VectorCreate(Camera.Pitch, Camera.Yaw, 0.0), VectorUniform(1.0));
Cam := MatrixInvert(Cam);

Share this post


Link to post
Share on other sites
Pateman    184
Oh right, I should've posted the math code, too.

Here's the definition of my vector and matrix type:

{ .: TVector :. }
PVector = ^TVector;
TVector = packed record
case Integer of
0:
(X: Single;
Y: Single;
Z: Single; );
1:
(V: array [0 .. 2] of Single);
end;

{ .: TMatrix :. }
PMatrix = ^TMatrix;
TMatrix = packed record
case Integer of
0:
(_11, _12, _13, _14: Single;
_21, _22, _23, _24: Single;
_31, _32, _33, _34: Single;
_41, _42, _43, _44: Single);
1:
(M: array [0 .. 3, 0 .. 3] of Single);
2:
(V: array [0 .. 15] of Single);
end;

As you can see, both records are unions.

The MatrixTransform function code is as follows:

{ .: MatrixTransform :. }
function MatrixTransform(const Position, Rotation, Scale: TVector): TMatrix;
var
CosRx, CosRy, CosRz: Single;
SinRx, SinRy, SinRz: Single;
begin
CosRx := Cos(Rotation.X); // Used 6x
CosRy := Cos(Rotation.Y); // Used 4x
CosRz := Cos(Rotation.Z); // Used 4x
SinRx := Sin(Rotation.X); // Used 5x
SinRy := Sin(Rotation.Y); // Used 5x
SinRz := Sin(Rotation.Z); // Used 5x
Result := MatrixIdentity;

with Result do
begin
_11 := CosRy * CosRz * Scale.X;
_12 := CosRy * SinRz * Scale.X;
_13 := -SinRy * Scale.X;

_21 := (CosRz * SinRx * SinRy * Scale.Y) - (CosRx * SinRz * Scale.Y);
_22 := (CosRx * CosRz * Scale.Y) + (SinRx * SinRy * SinRz * Scale.Y);
_23 := CosRy * SinRx * Scale.Y;

_31 := (CosRx * CosRz * SinRy * Scale.Z) + (SinRx * SinRz * Scale.Z);
_32 := (-CosRz * SinRx * Scale.Z) + (CosRx * SinRy * SinRz * Scale.Z);
_33 := CosRx * CosRy * Scale.Z;

_41 := Position.X;
_42 := Position.Y;
_43 := Position.Z;
end;
end;

Share this post


Link to post
Share on other sites
jyk    2094
I can't remember off the top of my head if GLSL expects matrix basis vector elements to be contiguous in memory, so if you're not sure yourself you might double check and make sure you're not missing a transpose somewhere. Other than that though, your code looks correct for row-major, row-basis matrices (which is what you have there).

Also, as I mentioned previously it looks like you may be constructing your view matrix incorrectly, so you might take another look at that as well.

Share this post


Link to post
Share on other sites
Pateman    184
Quote:

I can't remember off the top of my head if GLSL expects matrix basis vector elements to be contiguous in memory, so if you're not sure yourself you might double check and make sure you're not missing a transpose somewhere.

I tried inverting the camera matrix, transposing it, and both together, and it still doesn't work.

Quote:

Also, as I mentioned previously it looks like you may be constructing your view matrix incorrectly, so you might take another look at that as well.

The code was used before in a different project and it worked. The same thing is with sending the matrices to GLSL - I carefully followed the examples on the official OpenGL's website. Still, the code doesn't work.

Can you please suggest anything else?

Share this post


Link to post
Share on other sites
Pateman    184
Finally, after weeks of struggling, the code works! :D

And here is a step-by-step guide:
1. First of all, I disposed of all my matrix code and rewrote it. Here are the functions you will need to compile the code: http://www.nopaste.pl/Source/mhc.txt
2. Use the following shaders: http://www.nopaste.pl/Source/mhd.txt
3. Your rendering code should look like this:

procedure TMainForm.RenderWorld;
var
Model, View, Proj, MVP: TBrainMatrix;
begin
// Clear the frame buffer
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

// Compute the model-view-projection matrix
Proj := Mat4CreatePerspective(60.0, ClientWidth / ClientHeight, 0.1, 1000.0);
Model := Mat4Translate(Mat4CreateRotationEuler(ModelRotation), Vec3Negate(ModelPosition));
View := Mat4Translate(Mat4CreateRotationEuler(CameraRotation), Vec3Negate(CameraPosition));
View := Mat4Inverse(View);

MVP := Mat4Multiply(Model, Mat4Multiply(View, Proj));

// Update the shader
glUniformMatrix4fv(ShaderManager.ActiveProgram.GetUniformLocation('mvpmatrix'),
1, False, @MVP);

// Rendering code here...
end;

Hope this helps. :)

Share this post


Link to post
Share on other sites
Pateman    184
Unfortunately, there's another problem. I noticed the code I posted doesn't take the direction vector into consideration. It's better explained in the video here: http://www.youtube.com/watch?v=lOL8sqR5fQ0

It seems like the transformation matrix doesn't rotate the axes of an object, so it still moves at the same direction, even though it was rotated. Here's how I wanted to fix that bug:

function TBrainObject.GetMatrix: TBrainMatrix;
var
M: TBrainMatrix;
V: TBrainVector;
begin
if UpdateNeeded then
begin
M := Mat4CreateRotationEuler(FRotation);
V := Mat4ApplyToVector(M, Vec3(0.0, 0.0, -1.0));
V := Vec3Normalize(V);

CachedMatrix := Mat4Scale(Mat4Translate(M,
Vec3Negate(Vec3Add(FPosition, V))), FScale);

UpdateNeeded := False;
end;
Result := CachedMatrix;
end;

But it doesn't seem to help too much.

Can you tell me what's wrong with the code? Or at least suggest some changes?

Share this post


Link to post
Share on other sites

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  

  • Similar Content

    • By cebugdev
      hi all,

      i am trying to build an OpenGL 2D GUI system, (yeah yeah, i know i should not be re inventing the wheel, but this is for educational and some other purpose only),
      i have built GUI system before using 2D systems such as that of HTML/JS canvas, but in 2D system, i can directly match a mouse coordinates to the actual graphic coordinates with additional computation for screen size/ratio/scale ofcourse.
      now i want to port it to OpenGL, i know that to render a 2D object in OpenGL we specify coordiantes in Clip space or use the orthographic projection, now heres what i need help about.
      1. what is the right way of rendering the GUI? is it thru drawing in clip space or switching to ortho projection?
      2. from screen coordinates (top left is 0,0 nd bottom right is width height), how can i map the mouse coordinates to OpenGL 2D so that mouse events such as button click works? In consideration ofcourse to the current screen/size dimension.
      3. when let say if the screen size/dimension is different, how to handle this? in my previous javascript 2D engine using canvas, i just have my working coordinates and then just perform the bitblk or copying my working canvas to screen canvas and scale the mouse coordinates from there, in OpenGL how to work on a multiple screen sizes (more like an OpenGL ES question).
      lastly, if you guys know any books, resources, links or tutorials that handle or discuss this, i found one with marekknows opengl game engine website but its not free,
      Just let me know. Did not have any luck finding resource in google for writing our own OpenGL GUI framework.
      IF there are no any available online, just let me know, what things do i need to look into for OpenGL and i will study them one by one to make it work.
      thank you, and looking forward to positive replies.
    • By fllwr0491
      I have a few beginner questions about tesselation that I really have no clue.
      The opengl wiki doesn't seem to talk anything about the details.
       
      What is the relationship between TCS layout out and TES layout in?
      How does the tesselator know how control points are organized?
          e.g. If TES input requests triangles, but TCS can output N vertices.
             What happens in this case?
      In this article,
      http://www.informit.com/articles/article.aspx?p=2120983
      the isoline example TCS out=4, but TES in=isoline.
      And gl_TessCoord is only a single one.
      So which ones are the control points?
      How are tesselator building primitives?
    • By Orella
      I've been developing a 2D Engine using SFML + ImGui.
      Here you can see an image
      The editor is rendered using ImGui and the scene window is a sf::RenderTexture where I draw the GameObjects and then is converted to ImGui::Image to render it in the editor.
      Now I need to create a 3D Engine during this year in my Bachelor Degree but using SDL2 + ImGui and I want to recreate what I did with the 2D Engine. 
      I've managed to render the editor like I did in the 2D Engine using this example that comes with ImGui. 
      3D Editor preview
      But I don't know how to create an equivalent of sf::RenderTexture in SDL2, so I can draw the 3D scene there and convert it to ImGui::Image to show it in the editor.
      If you can provide code will be better. And if you want me to provide any specific code tell me.
      Thanks!
    • By Picpenguin
      Hi
      I'm new to learning OpenGL and still learning C. I'm using SDL2, glew, OpenGL 3.3, linmath and stb_image.
      I started following through learnopengl.com and got through it until I had to load models. The problem is, it uses Assimp for loading models. Assimp is C++ and uses things I don't want in my program (boost for example) and C support doesn't seem that good.
      Things like glVertexAttribPointer and shaders are still confusing to me, but I have to start somewhere right?
      I can't seem to find any good loading/rendering tutorials or source code that is simple to use and easy to understand.
      I have tried this for over a week by myself, searching for solutions but so far no luck. With tinyobjloader-c and project that uses it, FantasyGolfSimulator, I was able to actually load the model with plain color (always the same color no matter what I do) on screen and move it around, but cannot figure out how to use textures or use its multiple textures with it.
      I don't ask much: I just want to load models with textures in them, maybe have lights affect them (directional spotlight etc). Also, some models have multiple parts and multiple textures in them, how can I handle those?
      Are there solutions anywhere?
      Thank you for your time. Sorry if this is a bit confusing, English isn't my native language
    • By dpadam450
      FINALLY, upgrading my engine to openGL 4. I was having some trouble so I started with a stripped down application and was wondering if VAO's are required, because I have a sample working, but if I remove the VAO then it doesn't seem to like drawing my triangle.
  • Popular Now