I'm attempting to set up an orthographic projection in OpenGL, but can't seem to find why this triangle is not rendering correctly (it isn't visible). I have used perspective projection with the same code (apart from my vertex coordinates and projection matrix, of course) and it works fine. I construct the triangle vertices as:
Vertex vertices[] = { Vertex(glm::vec3(0, 600, 0.0), glm::vec2(0.0, 0.0)),
Vertex(glm::vec3(300, 0, 0.0), glm::vec2(0.5, 1.0)),
Vertex(glm::vec3(800 , 600, 0.0), glm::vec2(1.0, 0.0)) };
My camera constructor is:
Camera::Camera(const glm::vec3& pos, int width, int height) {
ortho = glm::ortho(0, width, height, 0, 0, 1000);
this->position = pos;
this->up = glm::vec3(0.0f, 1.0f, 0.0f);
this->forward = glm::vec3(0.0f, 0.0f, 1.0f);
}
I call this as:
camera = Camera(glm::vec3(0, 0, 2), window->getSize().x, window->getSize().y);
Where the window is 800 by 600 pixels. I am uploading a transform to the shader via the function:
void Shader::update(const Transform& transform, const Camera& camera) {
glm::mat4 model = camera.getProjection() * transform.getModel();
glUniformMatrix4fv(uniforms[TRANSFORM_U], 1, GL_FALSE, &model[0][0]);
}
In which camera.getProjection() is:
glm::mat4 Camera::getProjection() const {
return ortho * glm::lookAt(position, glm::vec3(0, 0, 0), up);
}
And transform.getModel() is:
glm::mat4 Transform::getModel() const {
glm::mat4 posMat = glm::translate(pos);
glm::quat rotQuat = glm::quat(glm::radians(rot));
glm::mat4 rotMat = glm::toMat4(rotQuat);
glm::mat4 scaleMat = glm::scale(scl);
return posMat * rotMat * scaleMat;
}
Though I suspect the problem lies in my set up of orthographic projection rather than my transforms, as this worked fine for perspective projection. Can anyone see why the triangle rendered with these coordinates is not visible? I am binding my shader and uploading the projection matrix to it before rendering the mesh. If it helps, my vertex shader is:
#version 120
attribute vec3 position;
attribute vec2 texCoord;
varying vec2 texCoord0;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(position, 1.0);
texCoord0 = texCoord;
}
For anyone interested in the issue, it was with:
ortho = glm::ortho(0, width, height, 0, 0, 1000);
Where the arguments are supplied as integers, not floats. Therefore the integer division applied within glm::ortho was creating an incorrect orthographic projection matrix.
Related
I create a cube like normal using 8 vertex points that outline a cube and use indices to draw each individual triangle. However, when I create my camera matrix and rotate it using the lookat function with glm it rotates the entire screen positions not world positions.
glm::mat4 Projection = glm::mat4(1);
Projection = glm::perspective(glm::radians(60.0f), (float)window_width / (float)window_hight, 0.1f, 100.0f);
const float radius = 10.0f;
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
glm::mat4 View = glm::mat4(1);
View = glm::lookAt(
glm::vec3(camX, 0, camZ),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
glm::mat4 Model = glm::mat4(1);
glm::mat4 mvp = Projection * View * Model;
Then in glsl:
uniform mat4 camera_mat4
void main()
{
vec4 pos = vec4(vertexPosition_modelspace, 1.0) * camera_mat4;
gl_Position.xyzw = pos;
}
Example: GLM rotating screen coordinates not cube
Rencently, I am trying to render a triangle(as Figure 1) in my Window Content View (OSX NSView) using OpenGL, I make an "Orthographic projection" with GLM library function glm::ortho, after render, the vertexes of the triangle are all in wrong place, they seems has an offset to the Window Content View.
I have 2 questions:
Am I misunderstood about glm::ortho(base the following code)?
When the window resize(Zoom In, Zoom Out), How to keep the triangle retain the same place in the Window(i.e. the top vertex at the middle of the width, and the bottom vertexes at the corner)?
The following is the result:
my render function:
- (void)render
{
float view_width = self.frame.size.width;
float view_height = self.frame.size.height;
glViewport(0, 0, view_width, view_height);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Using Orthographic Projection Matrix, vertex position
// using view coordinate(pixel coordinate)
float positions[] = {
0.0f, 0.0f, 0.0f, 1.0f,
view_width, 0.0f, 0.0f, 1.0f,
view_width/(float)2.0, view_height, 0.0f, 1.0f,
};
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), positions);
glm::mat4 p = glm::ortho(0.0f, view_width, 0.0f, view_height);
glm::mat4 v = glm::lookAt(glm::vec3(0, 0, 1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
glm::mat4 m = glm::mat4(1.0f);
// upload uniforms to shader
glUniformMatrix4fv(_projectionUniform, 1, GL_FALSE, &p[0][0]);
glUniformMatrix4fv(_viewUniform, 1, GL_FALSE, &v[0][0]);
glUniformMatrix4fv(_modelUniform, 1, GL_FALSE, &m[0][0]);
glDrawElements(GL_TRIANGLE_STRIP, sizeof(positions) / sizeof(positions[0]),GL_UNSIGNED_SHORT, 0);
[_openGLContext flushBuffer];
}
my vertex shader:
#version 410
in vec4 position;
uniform highp mat4 projection;
uniform highp mat4 view;
uniform highp mat4 model;
void main (void)
{
gl_Position = position * projection * view * model;
}
A glm matrix is initialized in the same way as GLSL matrix. See The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 101 for further information.
A vector has to be multiplied to the matrix from the right.
See GLSL Programming/Vector and Matrix Operations:
Note that the vector has to be multiplied to the matrix from the right.
If a vector is multiplied to a matrix from the left, the result corresponds to multiplying a row vector from the left to the matrix. This corresponds to multiplying a column vector to the transposed matrix from the right.
This means you've to change the vertex transformation in the vertex shader:
gl_Position = position * projection * view * model;
gl_Position = projection * view * model * position;
#Rabbid76 has answered my first question, it works! Thanks a lot.
The second question, in OSX, when resizing a window(contain a OpenGL View), the NSOpenGLContext should be update, like this:
- (void)setFrameSize:(NSSize)newSize {
[super setFrameSize:newSize];
// update the _openGLContext object
[_openGLContext update];
// reset viewport
glViewport(0, 0, newSize.width*2, newSize.height*2);
// render
[self render];
}
I got an orthographic camera working however I wanted to try and implement a perspective camera so I can do some parallax effects later down the line. I am having some issues when trying to implement it. It seems like the depth is not working correctly. I am rotating a 2d image along the x-axis to simulate it laying somewhat down so I get see the projection matrix working. It is still showing as an orthographic perspective though.
Here is some of my code:
CameraPersp::CameraPersp() :
_camPos(0.0f,0.0f,0.0f), _modelMatrix(1.0f), _viewMatrix(1.0f), _projectionMatrix(1.0f)
Function called init to setup the matrix variables:
void CameraPersp::init(int screenWidth, int screenHeight)
{
_screenHeight = screenHeight;
_screenWidth = screenWidth;
_modelMatrix = glm::translate(_modelMatrix, glm::vec3(0.0f, 0.0f, 0.0f));
_modelMatrix = glm::rotate(_modelMatrix, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
_viewMatrix = glm::translate(_viewMatrix, glm::vec3(0.0f, 0.0f, -3.0f));
_projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast<float>(_screenWidth) / _screenHeight, 0.1f, 100.0f);
}
Initializing a texture to be loaded in with x,y,z,width,height,src
_sprites.back()->init(-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, "src/content/sprites/DungeonCrawlStoneSoupFull/monster/deep_elf_death_mage.png");
Sending in the matrices to the vertexShader:
GLint mLocation = _colorProgram.getUniformLocation("M");
glm::mat4 mMatrix = _camera.getMMatrix();
//glUniformMatrix4fv(mLocation, 1, GL_FALSE, &(mMatrix[0][0]));
glUniformMatrix4fv(mLocation, 1, GL_FALSE, glm::value_ptr(mMatrix));
GLint vLocation = _colorProgram.getUniformLocation("V");
glm::mat4 vMatrix = _camera.getVMatrix();
//glUniformMatrix4fv(vLocation, 1, GL_FALSE, &(vMatrix[0][0]));
glUniformMatrix4fv(vLocation, 1, GL_FALSE, glm::value_ptr(vMatrix));
GLint pLocation = _colorProgram.getUniformLocation("P");
glm::mat4 pMatrix = _camera.getPMatrix();
//glUniformMatrix4fv(pLocation, 1, GL_FALSE, &(pMatrix[0][0]));
glUniformMatrix4fv(pLocation, 1, GL_FALSE, glm::value_ptr(pMatrix));
Here is my vertex shader:
#version 460
//The vertex shader operates on each vertex
//input data from VBO. Each vertex is 2 floats
in vec3 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
out vec3 fragPosition;
out vec4 fragColor;
out vec2 fragUV;
//uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
void main() {
//Set the x,y position on the screen
//gl_Position.xy = vertexPosition;
gl_Position = M * V * P * vec4(vertexPosition, 1.0);
//the z position is zero since we are 2d
//gl_Position.z = 0.0;
//indicate that the coordinates are nomalized
gl_Position.w = 1.0;
fragPosition = vertexPosition;
fragColor = vertexColor;
// opengl needs to flip the coordinates
fragUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
I can see the image "squish" a little because it is still rendering the perspective as orthographic. If I remove the rotation on the x-axis, it is not longer squished because it isn't laying down at all. Any thoughts on what I am doing wrong? I can supply more info upon request but I think I put in most of the meat of things.
Picture:
You shouldn't modify gl_Position.w
gl_Position = M * V * P * vec4(vertexPosition, 1.0); // gl_Position is good
//indicate that the coordinates are nomalized < not true
gl_Position.w = 1.0; // Now perspective divisor is lost, projection isn't correct
I'm developing an application in C++ using OpenGL. My problem is that when I render a cube to screen which has a rotation, it appears out of proportion (see the images).
I'm using the following NuGet packages:
When the cube is rotated at 0 degrees:
When the cube is rotated at 45 degrees:
When the cube is rotated at 90 degrees:
When the cube is rotated at 180 degrees:
When the cube is rotated at 360 degrees:
The following code is where the matrix is calculated:
glm::mat4 DrawnEntity::getMatrix() const
{
glm::mat4 translate = glm::translate(glm::mat4(1.0f), position);
glm::mat4 rotation = glm::toMat4(glm::quat(glm::radians(360.0f), 0, 1, 0));
glm::mat4 matrix = translate * rotation;
return matrix;
}
When the entity is drawn, this is called:
void DrawnEntity::render()
{
if (enabled)
mesh->render(getMatrix());
}
Which subsequently calls this:
void Mesh::render(glm::mat4 matrix)
{
glUseProgram(shaderID);
vao->render(matrix);
}
vao is a VertexArrayObject, and this is the function:
void VertexArrayObject::render(glm::mat4 matrix)
{
GLuint uModel = glGetUniformLocation(shaderID, "uModel");
glUniformMatrix4fv(uModel, 1, GL_TRUE, &matrix[0][0]);
glBindVertexArray(vao[0]);
glDrawArrays(GL_TRIANGLES, 0, mesh->vertexCount());
glBindVertexArray(0);
}
Ignoring the rotation, it appears all the vertices are being correctly loaded. For what it's worth, this is the class which generates the cube:
#include "CubeMesh.h"
#include "../VertexArrayObject.h"
CubeMesh::CubeMesh(GLuint shader)
{
shaderID = shader;
glUseProgram(shaderID);
generateFaces();
vao = new VertexArrayObject(this);
}
void CubeMesh::generateFaces()
{
// Front face
generateFace(glm::vec3(-0.5, 0.5, 0.5), glm::vec3(0.5, -0.5, 0.5));
// Left face
generateFace(glm::vec3(-0.5, -0.5, 0.5), glm::vec3(-0.5, 0.5, -0.5));
// Back face
generateFace2(glm::vec3(0.5, -0.5, -0.5), glm::vec3(-0.5, 0.5, -0.5));
// Right face
generateFace2(glm::vec3(0.5, -0.5, 0.5), glm::vec3(0.5, 0.5, -0.5));
}
void CubeMesh::generateFace(glm::vec3 point1, glm::vec3 point2)
{
glm::vec3 tl = point1;
glm::vec3 br = point2;
glm::vec3 tr = glm::vec3(br.x, tl.y, br.z);
glm::vec3 bl = glm::vec3(tl.x, br.y, tl.z);
Vertex f1v1(glm::vec3(tl.x, tl.y, tl.z));
Vertex f1v2(glm::vec3(bl.x, bl.y, bl.z));
Vertex f1v3(glm::vec3(br.x, br.y, br.z));
Triangle f1(f1v1, f1v2, f1v3);
Vertex f2v1(glm::vec3(tr.x, tr.y, tr.z));
Vertex f2v2(glm::vec3(tl.x, tl.y, tl.z));
Vertex f2v3(glm::vec3(br.x, br.y, br.z));
Triangle f2(f2v1, f2v2, f2v3);
addData(f1);
addData(f2);
}
void CubeMesh::generateFace2(glm::vec3 point1, glm::vec3 point2)
{
glm::vec3 tl = point1;
glm::vec3 br = point2;
glm::vec3 tr = glm::vec3(br.x, tl.y, br.z);
glm::vec3 bl = glm::vec3(tl.x, br.y, tl.z);
Vertex f1v1(glm::vec3(tl.x, tl.y, tl.z));
Vertex f1v2(glm::vec3(br.x, br.y, br.z));
Vertex f1v3(glm::vec3(bl.x, bl.y, bl.z));
Triangle f1(f1v1, f1v2, f1v3);
Vertex f2v1(glm::vec3(tr.x, tr.y, tr.z));
Vertex f2v2(glm::vec3(br.x, br.y, br.z));
Vertex f2v3(glm::vec3(tl.x, tl.y, tl.z));
Triangle f2(f2v1, f2v2, f2v3);
addData(f1);
addData(f2);
}
The vertex shader is as follows:
#version 430 core
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
in vec3 vPosition;
in vec3 vNormal;
out vec4 oColour;
void main(void)
{
oColour = vec4(vPosition, 1);
gl_Position = vec4(vPosition, 1) * uModel * uView * uProjection;
}
uModel is the matrix representing the individual model translation, rotation etc. uView is the position of the camera, and uProjection is the projection matrix. The first is fed to the shader in the VertexArrayObject shown previously, while the last two are fed to the shader in the camera object as below:
void Camera::initialise()
{
glUseProgram(shaderID);
view = glm::translate(glm::mat4(1), position);
int uView = glGetUniformLocation(shaderID, "uView");
glUniformMatrix4fv(uView, 1, GL_TRUE, &view[0][0]);
int uProjection = glGetUniformLocation(shaderID, "uProjection");
glm::mat4 projection = glm::perspective(1.0, (double)1024 / (double)1024, 0.01, 10.0);
glUniformMatrix4fv(uProjection, 1, GL_TRUE, &projection[0][0]);
}
The position of the model is 0 0 0 and the position of the camera is 0 0 -5. When the uModel position is changed, the cube is rendered where it is expected, however with the rotation it doesn't act as it should.
Can anybody see anything that I might be doing wrong? Is there anymore code you need to see?
I found that changing the following line:
glm::mat4 rotation = glm::toMat4(glm::quat(glm::radians(360.0f), 0, 1, 0));
to this:
glm::mat4 rotation = glm::rotate(translate, (float)glm::radians(0.0), glm::vec3(0.0f, 1.0f, 0.0f));
solves the issue. I can't really offer an explanation for why the first one didn't work, as I don't know enough about Quaternion's to comment on it. If anyone can explain it better, please edit my answer. Regardless, this was the best fix I could find.
So I can draw a spinning cube using OpenGL3.2+ and translate it away from the 0,0,0 and to the left, but when I try and draw a second one (towards the right), it doesn't render...
This is my display function:
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(myShader.handle());
GLuint matLocation = glGetUniformLocation(myShader.handle(), "ProjectionMatrix");
glUniformMatrix4fv(matLocation, 1, GL_FALSE, &ProjectionMatrix[0][0]);
spinY+=0.03;
if(spinY>360) spinY = 0;
glm::mat4 viewMatrix;
viewMatrix = glm::translate(glm::mat4(1.0),glm::vec3(0,0,-100)); //viewing matrix
ModelViewMatrix = glm::translate(viewMatrix,glm::vec3(-30,0,0)); //translate object from the origin
ModelViewMatrix = glm::rotate(ModelViewMatrix,spinY, glm::vec3(0,1,0)); //rotate object about y axis
glUniformMatrix4fv(glGetUniformLocation(myShader.handle(), "ModelViewMatrix"), 1, GL_FALSE, &ModelViewMatrix[0][0]); //pass matrix to shader
//Add the following line just before the line to draw the cube to
//check that the origin of the cube in eye space is (-30, 0, -100);
result = glm::vec3(ModelViewMatrix * glm::vec4(0,0,0,1));
std::cout<<glm::to_string(result)<<std::endl; //print matrix to get coordinates.
myCube.render();
glUseProgram(0);
}
I want to be able to use the same Cube class / size etc, but just render it again (I assume that's the most efficient / best way to do it).
I tried this
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(myShader.handle());
GLuint matLocation = glGetUniformLocation(myShader.handle(), "ProjectionMatrix");
glUniformMatrix4fv(matLocation, 1, GL_FALSE, &ProjectionMatrix[0][0]);
spinY+=0.03;
if(spinY>360) spinY = 0;
glm::mat4 viewMatrix;
viewMatrix = glm::translate(glm::mat4(1.0),glm::vec3(0,0,-100)); //viewing matrix
ModelViewMatrix = glm::translate(viewMatrix,glm::vec3(-30,0,0)); //translate object from the origin
ModelViewMatrix = glm::rotate(ModelViewMatrix,spinY, glm::vec3(0,1,0)); //rotate object about y axis
glUniformMatrix4fv(glGetUniformLocation(myShader.handle(), "ModelViewMatrix"), 1, GL_FALSE, &ModelViewMatrix[0][0]); //pass matrix to shader
//Add the following line just before the line to draw the cube to
//check that the origin of the cube in eye space is (-30, 0, -100);
result = glm::vec3(ModelViewMatrix * glm::vec4(0,0,0,1));
std::cout<<glm::to_string(result)<<std::endl; //print matrix to get coordinates.
myCube.render();
glm::mat4 viewMatrix_TWO;
viewMatrix_TWO = glm::translate(glm::mat4(1.0),glm::vec3(0,0,-100)); //viewing matrix
ModelViewMatrix_TWO = glm::translate(viewMatrix_TWO,glm::vec3(30,0,0)); //translate object from the origin
ModelViewMatrix_TWO = glm::rotate(ModelViewMatrix_TWO,spinY, glm::vec3(0,1,0)); //rotate object about y axis
glUniformMatrix4fv(glGetUniformLocation(myShader.handle(), "ModelViewMatrix_TWO"), 1, GL_FALSE, &ModelViewMatrix[0][0]); //pass matrix to shader
myCube.render();
glUseProgram(0);
}
Obviously, I've implemented it wrong... How can I get a cube either side of the screen? Thanks.
UPDATE
I realised, I hadn't created a second cube object, but with that now implemented, it still doesn't work... Am I confusing how the view/model matrices interact? I've created a new one for each object....
New Code:
myCube.render();
spinX+=0.03;
if(spinX>360) spinX = 0;
glm::mat4 viewMatrix_Two,ModelViewMatrix_Two;
viewMatrix_Two = glm::translate(glm::mat4(1.0),glm::vec3(0,0,-100)); //viewing matrix
ModelViewMatrix_Two = glm::translate(viewMatrix_Two,glm::vec3(30,0,0)); //translate object from the origin
ModelViewMatrix_Two = glm::rotate(ModelViewMatrix_Two,spinX, glm::vec3(0,1,0)); //rotate object about y axis
glUniformMatrix4fv(glGetUniformLocation(myShader.handle(), "ModelViewMatrix_Two"), 1, GL_FALSE, &ModelViewMatrix_Two[0][0]); //pass matrix to shader
myCube_Two.render();
UPDATE
Shader:
uniform mat4 ModelViewMatrix;
//uniform mat4 ModelViewMatrix_Two; //NOT NEEDED - USED SAME SHADER OBJECT
uniform mat4 ProjectionMatrix;
in vec3 in_Position; // Position coming in
in vec3 in_Color; // colour coming in
out vec3 ex_Color; // colour leaving the vertex, this will be sent to the fragment shader
void main(void)
{
gl_Position = ProjectionMatrix * ModelViewMatrix * vec4(in_Position, 1.0);
//gl_Position = ProjectionMatrix * ModelViewMatrix_Two * vec4(in_Position, 1.0);
ex_Color = in_Color;
}
In the end, I created a second Cube object, second viewing matrix and used them with the already established model matrix in my shader seems both cubes are called/rendered individually.
The correct code is:
glm::mat4 viewMatrix_Two, ModelViewMatrix_Two;
viewMatrix_Two = glm::translate(glm::mat4(1.0),glm::vec3(0,0,-200));
ModelViewMatrix = glm::translate(viewMatrix_Two,glm::vec3(30,0,0));
ModelViewMatrix = glm::rotate(ModelViewMatrix,spinX, glm::vec3(1,0,0));
glUniformMatrix4fv(glGetUniformLocation(myShader.handle(), "ModelViewMatrix"), 1, GL_FALSE, &ModelViewMatrix[0][0]); //pass matrix to shader
myCube_Two.render();
Unless your shader has a uniform called ModelViewMatrix_Two, this won't work. I don't see a reason why your shader would need another uniform for the model view since you are not drawing both cube on the same call. If it's not the problem, can you post your shader code?