I am working on a 3D project using vertices, i started it with a simple gluLookAt in order to have a first person camera moving in an environment, i use it this way :
gluLookAt(_position.x,_position.y,_position.z,
_target.x,_target.y,_target.z,
0,0,1);
Everything was working fine, i was calculating my target according to the position of the mouse and angles (theta and phi), my project moved on to using vertices for performance issues, so i had to use the same camera for these new objects, in order to do this i used the GLM library this way :
glm::mat4 Projection = glm::perspective(90.0f, 800.0f / 600.0f, 0.1f, 100.f);
glm::mat4 View = glm::lookAt(
glm::vec3(position.x,position.y,position.z),
glm::vec3(target.x,target.y,target.z),
glm::vec3(0,0,1)
);
glm::mat4 Model = glm::mat4(1.0f); !
// Our ModelViewProjection : multiplication of our 3 matrices
glm::mat4 MVP = Projection * View * Model;
GLuint MatrixID = glGetUniformLocation(this->shaderProgram, "MVP");
here is the shader i use :
const GLchar* default_vertexSource =
"#version 150 core\n"
"in vec2 position;"
"in vec3 color;"
"out vec3 Color;"
"uniform vec3 translation;"
"uniform mat4 rotation;"
"uniform mat4 MVP;"
"void main() {"
" Color = color;"
" gl_Position = MVP*rotation*vec4(position.x + translation.x, position.y + translation.y, 0.0 + translation.z, 1.0);"
"}";
What happens is that my my object's coordinate reference is not the same as my camera, it is drawn above it on the current x/z plan whereas it should be facing the camera on the x/y plan.
From my point of view it seems that you are missunderstanding how translation in OpenGL works.
glm::lookAt returns one modelview matrix. -> How the objects in the scene are translated according to the camera. In openGL you do not "Move" the camera, you are moving all the objects around the camera.
So if you have 2 objects in 0 0 0 (origin of you world camera system) and ur camera is at
eye(0,0,-3), center(0,0,0), up(0,1,0) and you want to move one object to the left and on object to the right you need to have a matrix stack from glm
std::stack<glm::mat4> glm_ProjectionMatrix;
Here you can push the modelview from your camera as top object.
For the object movemtn to the left side you can just use glm::translate, upload this mat4 as modelview matrix to your shader. (here do not render the scene)
Reset the top matrix to modelview (eiter pop() if you made a copy of the top element before) or just reset using glm::lookAt. Then glm::translate in the other direction.
In your vertex shader you now need no vec3 translate or rotate.
You just say
gl_Position = perspective * modelview *vec4(position,1);
This wil update the two object accordingly to you given translation.
If you want to move some objects around, just update the modelview matrix for the one object.
http://www.songho.ca/opengl/gl_transform.html
I hope you can understand my answer.
The basics of movement (rot and trans) in OpenGL is matrix multipication. You do not need to add some translation vec to your modelview in the shader. GLM can do all the stuff in you c++ code
Math:
Modelview is a 4*4 matrix
If your object should not be rotated or translated the modelview is equals to the identity.
If you want to rotate the object you miltiply the modelview matrix with the correct 4*4 rotation matrix (see homogenous coordinates)
If you want to translate the vertex you multiply the correct translation to the matrix
Lets say X = (x,y,z,w) is you vertex
T is translation and R is rotation
a valid operation may looks like this:
Modelview * rotation * translation *v = v'
v' is the new position of the point in your 3D coordinate system
Some examplecode you can find here: http://incentivelabs.de/Sourcecode/ See "Teil 13" or later. If you are able to understand german, you can find my tutorials on OpenGL with C++ on Youtube using the channel-name "incentivelabs"
Edit:
If I want to move an object/rotate an object using C++ with GLM
glm_ProjectionMatrix.top() = camera.getProjectionMat();
glUniformMatrix4fv(uniformLocations["projection"], 1, false,glm::value_ptr(glm_ProjectionMatrix.top()));
glm_ModelViewMatrix.top() = camera.getModelViewMat();
glm_ModelViewMatrix.top() = glm::translate(
glm_ModelViewMatrix.top(),
glm::vec3(0.0f, 0.0f, -Translate));
glUniformMatrix4fv(uniformLocations["modelview"], 1, false,glm::value_ptr(glm_ModelViewMatrix.top()));
In the GLSL vertex Shader:
gl_Position = projection * modelview * vec4(vertexPos,1);
vertexPos is an attribute (vec3 for the position)
This codes moves all vertices drawn after the upload of the modelview and projection to the shader with the same translation.
Related
I have a 3D world with a cube inside it. I understand that the cube's vertices are defined as coordinates about the cube's "centre of mass".
I want to place the cube at a position away from me, to the right and up above so I want to place the cube at (1,1,1). I don't have any 'camera' code at the moment so assume my viewing position is (0,0,0).
What do I need to translate to move the cube to a new location?
I am confused by the View and Model matrices. I thought View was the camera view/position and Model was the position of the vertices in the 3D world.
My code below works as I expect for x and y positions but z is negative going into the screen (further away) and positive moving towards/out of the screen. I would like z to be positive the further away an object is from the viewpoint.
What am I doing wrong?
glm::mat4 Projection = glm::perspective( 45.0f, g_AspectRatio, 0.1f, 100.0f );
glm::mat4 View = glm::mat4(1.0);
glm::mat4 Model = glm::mat4(1.0);
// Move the object within the 3D space
Model = glm::translate( Model, glm::vec3( m_X, m_Y, m_Z ) );
glm::mat4 MVP;
MVP = Projection * View * Model;
MVP is passed into the transform uniform.
My shader:
char *vs3DShader =
"#version 140\n"
"#extension GL_ARB_explicit_attrib_location : enable\n"
"layout (location = 0) in vec3 Position;"
"layout (location = 1) in vec4 color;"
"layout (location = 2) in vec3 normal;"
"out vec4 frag_color;"
"uniform mat4 transform;"
"void main()"
"{"
" gl_Position = transform * vec4( Position.x, Position.y, Position.z, 1.0 );"
" // Pass vertex color to fragment shader.. \n"
" frag_color = color;"
"}"
;
My code below works as I expect for x and y positions but z is negative going into the screen (further away) and positive moving towards/out of the screen. I would like z to be positive the further away an object is from the viewpoint.
You can achieve this by setting up a view matrix, which mirrors the Z-Axis:
glm::mat4 View = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, -1.0f));
The view matrix transforms from world space to view space. Your view matrix is the identity matrix:
glm::mat4 View = glm::mat4(1.0);
This means the world space is equal the view space. Note, in general a view matrix is set by glm::lookAt.
The Z-Axis is the cross product of the X-Axis and the Y-Axis. This means, if the X-axis points to the left, and the Y-axis points up, in a right handed system, then the Z-axis points out of the viewport.
See Understanding OpenGL’s Matrices
The coordinates I described above, are in general the view coordinates in a right handed system, because glm::glm::perspective sets up a right handed projection matrix, which transforms this cooridnates to clip sapce, in that way that the z-axis is inverted and becomes the depth.
Let's say I have the following vertex shader code below:
attribute vec4 vPos;
uniform mat4 MVP;
uniform mat4 LookAt;
void main{
gl_Position = MVP * vPos;
}
How do I use the LookAt matrix in this shader to position the eye of the camera? I have tried LookAt * MVP * vPos but that didn't seem to work as my triangle just disappeared off screen!
I would suggest move the LookAt outside the shader to prevent un-necessary calculation per vertex. The shader still do
gl_Position = MVP * vPos;
and you manipulate MVP in the application with glm. For example:
projection = glm::perspective(fov, aspect, 0.1f, 10000.0f);
view = glm::lookAt(eye, center, up);
model = matrix of the model, with all the dynamic transforms.
MVP = projection * view * model;
A LookAt matrix is in general called a View matrix and is concatenated with a model-to-world transform matrix to form the WorldView matrix. This is then multiplied by the projection matrix which is often orthographic or perspective. Vertex positions in model space are multiplied with the resulting matrix in order to be transformed to clip space (kinda...I skipped a couple of steps here that you don't have to do and is performed by the hardware/driver).
In your case, make sure that you're using the correct 'handedness' for your transformations. Also you can try and multiply the position in the reverse order with the transpose of your transformation matrices like so vPos*T_MVP*T_LookAt.
I'm trying to port an old SDL game I wrote some time ago to 3.3+ OpenGL and I'm having a few issues getting a proper orthogonal matrix and it's corresponding view.
glm::mat4 proj = glm::ortho( 0.0f, static_cast<float>(win_W), static_cast<float>(win_H), 0.0f,-5.0f, 5.0f);
If I simply use this projection and try to render say a quad inside the boundaries of win_W and win_H, it works. However, if instead I try to simulate a camera using:
glm::mat4 view = glm::lookAt(
glm::vec3(0.0f, 0.0f, 1.0f),//cam pos
glm::vec3(0.0f, 0.0f, 0.0f),//looking at
glm::vec3(0.0f, 0.0f, 1.0f)//floored
);
I get nothing. Even when positioning the quad in the center, same if instead I center the view:
glm::mat4 view = glm::lookAt(
glm::vec3(static_cast<float>(win_W), static_cast<float>(winH), 1.0f),//cam pos
glm::vec3(static_cast<float>(win_W), static_cast<float>(winH), 0.0f),//looking at
glm::vec3(0.0f, 0.0f, 1.0f)//floored
);
Considering that SDL usually subtracts the camera values from the vertices in the game to simulate a view, is it simply better to replace my MVP operation in the shader like this:
#version 150
in vec2 position;
in vec3 color;
out vec3 Color;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 camera;
void main()
{
Color = color;
//faulty view
//gl_Position = projection *view * model * vec4(position, 0.0, 1.0);
//new SDL style camera
mat4 newPosition = projection * model * vec4(position, 0.0, 1.0);
gl_Position = newPosition - camera;
}
Unfortunately the source I'm learning from (ArcSynthesis Book) doesn't cover a view that involves a coordinate system other than the default NDC. And for some reason even today most discussion about opengl is about deprecated versions.
So in short, whats the best way of setting up the view to an orthogonal projection matrix for simple 2D rendering in modern opengl?
Your lookup call actually does not make sense at all, since your up vector (0,0,1) is colinear to the viewing direction (0,0,-1). This will not produce a useable matrix.
You probably want (0,1,0) as up vector. However, even if you change that, you might be surprised about the result. In combination with the projection matrix you set up, the point you specified as the lookat target will not appear in the center, but at the corner of the screen. Your projection does not map (0,0) to the center, which one typically assumes when using some LookAt function.
I agree to Colonel Thirty Two's comment: Don't use LookAt in this scenario, unless you have a very good reason to.
I currently have 5 models displayed in a screen and what I'm trying to do. The following is my vertex shader for translating the models individually so that I can get them to move in different directions:
#version 330
layout (location = 0) Position;
uniform mat4 MVP;
uniform vec3 Translation;
uniform mat4 Rotate;
void main()
{
gl_Position = MVP * * Rotate * vec4(Position + Translation, 1.0); // Correct?
}
And to position/move my models individually within the render loop:
//MODEL ONE
glUniform3f(loc, 0.0f, 4.0f, 0.0f); // loc is "Translate"
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(rotationMatrix)); // loc is "Rotate"
_model1.render();
Also I do have a glm::mat4 rotateMatrix() that returns a rotation. but when I multiply it with the other matrices within the render loop, the whole scene (minus the camera) rotates to the set angle.
UPDATE
How would I be able to apply my rotation to the models independently of the world on their own axis? The problem now is that the model rotates, but from 0,0,0 of the world and not it's own position.
There's are a couple of syntax error in your vertex shader:
No type for the Position variable. Looks from the context like it should be a vec3.
Two * signs after MVP.
I assume that was those were just an accident while copying the code, and you actually have a vertex shader that compiles.
To apply the rotation described by the Rotate matrix before the translation from the Translation vector, you should be able to simply change the order in the vertex shader:
vec4 rotatedVec = Rotate * vec4(Position, 1.0);
gl_Position = MVP * vec4(rotatedVec.xyz + Translation, 1.0);
The whole thing would looks simpler if you defined Rotate as a 3x3 matrix, which is sufficient for a rotation.
I can successfully manipulate 3d objects on the screen in openGL.
To add a 2d effect, I thought I could simply turn off the matrix multiplication in the vertex shader (or give the identity matrix) and then the "Vertices" I provide would be screen coordinates.
But 2 simple triangles refuse to display (a square 0,0,100,100, tried various depths, but this same code works fine if I give it a rotating matrix.
Any ideas?
static const char gVertexShader[] =
"attribute vec3 coord3d;\n"
"uniform mat4 mvp;\n"
"void main() {\n"
"gl_Position = mvp*vec4(coord3d,1.0);\n"
"}\n";
->
static const char gVertexShader[] =
"attribute vec3 coord3d;\n"
"uniform mat4 mvp;\n"
"void main() {\n"
"gl_Position = vec4(coord3d,1.0);\n"
"}\n";
EDIT: I was unable to get anything to show using the identity matrix as a transformation, but I was able to do so using this one:
glm::mat4 view = glm::lookAt(glm::vec3(0.0, 0.0, -5), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 pers = glm::perspective(.78f, 1.0f*screenWidth/screenHeight, 0.1f, 10.0f);
xform = pers * view * glm::mat4(1.0f);
You'd have to adjust the -5 to fully fill the screen...
The gl_Position output of the vertex shader does expect clip space coordinates, not window space. The clip space coords will be forst transformed to normaliced device space and finally be converted to window space coords using the viewport transform.
If you want to directly work with window space coodrs for your vertices, you can simple use the inverse of the viewport transform as the projection matrix (the clip space will be identical to normalized device space when you work with orthogonal projections, so you don't need to care about that).
In NDC, (-1, -1) is the bottom left corener and (1,1) the top right one, so it is quite easy to see that all you need is a scale and a translation, you don't even need a full-blown matrix for that, these transforms will nicely end up as multiply-add operations GPUs can handle very efficiently.