Cube doesn't render as expected when rotated - c++

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.

Related

I have a list of world points(XYZ) and I want to show them in a openGL window

my points in x are between 0.25 and 1.21 , my points in y are between 3 and 4 and my points in z are between 99 and 101.
here is my vertex shader
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexColor;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
}
and here is the code in c++
glm::mat4 Projection = glm::ortho(0.0f, 2.0f, 2.0f, 5.0f, 0.0f, 200.0f);
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(4, 3, -3), // Camera is at (4,3,-3), in World Space
glm::vec3(0, 0, 0), // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 Model = glm::mat4(1.0f);
// Our ModelViewProjection : multiplication of our 3 matrices
glm::mat4 MVP = Projection * View * Model; // Remember, matrix multiplication is the other way around
glm::mat4 modelview = MVP;
I can also add that I am able to print a rectangle that I hard code the vertices with -1 and 1 using that Projection (note here the perspective instead of ortho)
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
You don't look towards your point cloud. The first argument of glm::lookAt is the position of the camera and the second argument is the point you are looking at.
Hence the direction of the view is (0, 0, 0) - (4, 3, 3) = (-4, -3, 3).
If the points are in range x: [0.25, 1.21], y: [3, 4], z: [99, 101]. The line of sight doesn't intersect this volume.
Change the target of the view (center):
glm::mat4 View = glm::lookAt(
glm::vec3(4, 3, -3),
glm::vec3(0.73f, 3.5f, 100.0f),
glm::vec3(0, 1, 0));
glm::vec3(0.73f, 3.5f, 100.0f) is the center of your point cloud.
And you need to make sure that the center of the projection is on the line of sight:
glm::ortho(-2.0f, 2.0f, 2.0f, -2.0f, 0.0f, 200.0f);

Triangle Vertexes in wrong place with GLM Orthographic Projection Matrix

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];
}

OpenGL Matrices and Shaders Confusion

I've been following a tutorial on modern OpenGL with the GLM library
I'm on a segment where we introduce matrices for transforming models, positioning the camera, and adding perspective.
I've got a triangle:
const GLfloat vertexBufferData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
I've got my shaders:
GLuint programID = loadShaders("testVertexShader.glsl",
"testFragmentShader.glsl");
I've got a model matrix that does no transformations:
glm::mat4 modelMatrix = glm::mat4(1.0f); /* Identity matrix */
I've got a camera matrix:
glm::mat4 cameraMatrix = glm::lookAt(
glm::vec3(4.0f, 4.0f, 3.0f), /*Camera position*/
glm::vec3(0.0f, 0.0f, 0.0f), /*Camera target*/
glm::vec3(0.0f, 1.0f, 0.0f) /*Up vector*/
);
And I've got a projection matrix:
glm::mat4 projectionMatrix = glm::perspective(
90.0f, /*FOV in degrees*/
4.0f / 3.0f, /*Aspect ratio*/
0.1f, /*Near clipping distance*/
100.0f /*Far clipping distance*/
);
Then I multiply all the matrices together to get the final matrix for the triangle I want to draw:
glm::mat4 finalMatrix = projectionMatrix
* cameraMatrix
* modelMatrix;
Then I send the matrix to GLSL (I think?):
GLuint matrixID = glGetUniformLocation(programID, "MVP");
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &finalMatrix[0][0]);
Then I do shader stuff I don't understand very well:
/*vertex shader*/
#version 330 core
in vec3 vertexPosition_modelspace;
uniform mat4 MVP;
void main(){
vec4 v = vec4(vertexPosition_modelspace, 1);
gl_Position = MVP * v;
}
/*fragment shader*/
#version 330 core
out vec3 color;
void main(){
color = vec3(1, 1, 0);
}
Everything compiles and runs, but I see no triangle. I've moved the triangle and camera around, thinking maybe the camera was pointed the wrong way, but with no success. I was able to successfully get a triangle on the screen before we introduced matrices, but now, no triangle. The triangle should be at origin, and the camera is a few units away from origin, looking at origin.
Turns out, you need to send the matrix to the shader after you've bound the shader.
In other words, you call glUniformMatrix4fv() after glUseProgram()
Lots of things could be your problem - try outputting a vec4 color instead, with alpha explicitly set to 1. One thing I often do as a sanity check is to have the vertex shader ignore all inputs, and to just output vertices directly, e.g. something like:
void main(){
if (gl_VertexID == 0) {
gl_Position = vec4(-1, -1, 0, 1);
} else if (gl_VertexID == 1) {
gl_Position = vec4(1, -1, 0, 1);
} else if (gl_VertexID == 2) {
gl_Position = vec4(0, 1, 0, 1);
}
}
If that works, then you can try adding your vertex position input back in. If that works, you can add your camera or projection matrices back in, etc.
More generally, remove things until something works, and you understand why it works, and then add parts back in until you stop understanding why things don't work. Quite often I've been off by a sign, or in the order of multiplication.

OpenGL Orthographic Projections

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.

Draw 2 cubes in OpenGL using GLM

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?