I have 25 cubes that i want to rotate each one differently this is my code on both x and y axis
i tried using rand() but it kept rotating them weirdly and all of them rotate in the same directions
this is in the game loop
for (unsigned int i = 0; i < 25; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
view = glm::translate(model, glm::vec3(0.0f, 0.0f, -10.0f));
float angle = 20.0f * i;
angle = glfwGetTime() * 20.0f;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.0f, 0.5f));
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
glUniformMatrix4fv(projLoc, 1, GL_FALSE,
glm::value_ptr(projection));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
Since there is no actual question, I try to give some comments on the posted code
that could explain the unexpected behavior of the resulting program.
The angle variable is initialised, then assigned immediately with a new
value ; only this new value is relevant, then the cubes should all rotate
at the rate of 20 degrees per second. (this is not a problem)
The view matrix is reassigned with a new value for each object! It is
extremely unlikely that this is what you want.
It's like if, while drawing a single frame, you move the camera in front of
each object being drawn ; if you move the camera and the object the same way,
then everything is displayed at the same place in the rendered frame.
(I think this is the main problem)
You should choose once for all the view matrix (as well as the projection
matrix) for the whole frame.
Some other comments, not directly related:
You should retrieve the uniform locations once for all before the loop
(and even at the beginning of the program) since they won't change as long
as you use the same shader program.
The glUniformMatrix4fv() calls for projection and view should
occur once for all before the loop; only the model matrix changes from
one object to another.
That could look like this
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
glm::mat4 projection = ... already known ...
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 view = glm::mat4(1.0f);
// adjust to the layout of your scene
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -10.0f));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
for(unsigned int i = 0; i < 25; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
// the same rotation rate but a different offset for each object
float angle = 20.0f * i;
angle += std::fmod(glfwGetTime() * 20.0f, 360.0f);
// choose x or y rotation axis
auto axis=(i%2) ? glm::vec3(1.0f, 0.0f, 0.0f) : glm::vec3(0.0f, 1.0f, 0.0f);
model = glm::rotate(model, glm::radians(angle), axis);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
Related
I'm trying to setup an orthographic camera in C++ and I have some problems getting the rotation correctly.
When I try to rotate the camera around the z axis by 45 degrees, everything works as expected (model is defined from -0.5f to 0.5f).
However, when trying to rotate around x axis, the angle gets really amplified (i.e. rotation around 1 radian makes it almost disappear).
Here is the related code:
int main(int argc, char** argv)
{
sdl2::Context context;
sdl2::Window window("myWindow", 800, 600);
sdl2::GLContext glContext(window);
//make the shader
Shader shader("shaders/quad.vert", "shaders/quad.frag");
Quad quad;
//create a orthographic projection
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f);
auto zAxis = glm::vec3(0.0f, 0.0f, 1.0f);
glUseProgram(shader.getID());
auto projectionLoc = glGetUniformLocation(shader.getID(), "projection");
glUniformMatrix4fv(projectionLoc, 1, false, glm::value_ptr(projection));
auto viewLoc = glGetUniformLocation(shader.getID(), "view");
auto viewTransform = glm::mat4(1.0f);
auto zRot = glm::quat(glm::vec3(glm::radians(1.0f), glm::radians(0.0f), glm::radians(0.0f)));
viewTransform *= glm::toMat4(zRot);
glUniformMatrix4fv(viewLoc, 1, true, glm::value_ptr(viewTransform));
bool quit = false;
SDL_Event e;
while (!quit)
{
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
quit = true;
}
}
glClear(GL_COLOR_BUFFER_BIT);
quad.render(shader);
SDL_GL_SwapWindow(window());
}
SDL_Delay(3000);
return 0;
}
#version 430 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 uv;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main()
{
gl_Position = projection * view * model * vec4(pos, 1.0);
}
Quad::Quad() :
_position(0, 0, 0)
{
glCreateBuffers(1, &_vbo);
glCreateVertexArrays(1, &_vao);
glGenBuffers(1, &_ebo);
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
uint32_t indices[] = {
0, 1, 3,
1, 2, 3
};
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
glEnableVertexAttribArray(0);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
}
Quad::~Quad()
{
glDeleteVertexArrays(1, &_vao);
glDeleteBuffers(1, &_vbo);
}
void Quad::render(const Shader& shader)
{
glBindVertexArray(_vao);
glUseProgram(shader.getID());
auto modelView = glm::mat4(1.0f);
//modelView = glm::translate(modelView, glm::vec3(400.0f, 300.0f, 0.0f));
modelView = glm::scale(modelView, glm::vec3(400.0f, 400.0f, 1.0f));
//modelView = glm::scale(modelView, glm::vec3(800, 600, 0));
auto modelLoc = glGetUniformLocation(shader.getID(), "model");
auto viewLoc = glGetUniformLocation(shader.getID(), "view");
auto projectionLoc = glGetUniformLocation(shader.getID(), "projection");
glUniformMatrix4fv(modelLoc, 1, false, glm::value_ptr(modelView));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
When you rotate a round the x or y axis, then the objects is clipped by the near and far plane of the Orthographic projection. By default near is -1.0 and far is 1.0. Increase the distance to the near and far plane (see glm::ortho). For instance:
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f);
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, -500.0f, 500.0f);
The output of this code is 25 cubs rotating .
The problem that I'm facing is the location of each cubes I don not know how to make them be in one line , Like for example every 5 cubes in one line and so on.
Note : I have added the Positions of cubes.
glm::vec3 cubePositions[] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
while (!glfwWindowShouldClose(mainWindow))
{
glfwPollEvents();
glClearColor(0.0f, 0.1f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Camera transformation
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
//Get uniform locations
GLint viewlLoc = glGetUniformLocation(ourShader.Program, "view");
glUniformMatrix4fv(viewlLoc, 1, GL_FALSE, glm::value_ptr(view));
GLint projlLoc = glGetUniformLocation(ourShader.Program, "projection");
glUniformMatrix4fv(projlLoc, 1, GL_FALSE, glm::value_ptr(projection));
// Call Shader Program
ourShader.Use();
glBindVertexArray(VAO);
for(unsigned int i = 0; i < 25; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
angle = glfwGetTime() * 25.0f;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glBindVertexArray(0);
glfwSwapBuffers(mainWindow);
glfwPollEvents();
}
Use glm::translate to add a translation to the model matrix of each individual cube, dependent on the index of the cube. e.g.:
for(unsigned int i = 0; i < 25; i++)
{
float dist = ; // distance between the cubes
float x = (i % 5) * dist;
float y = (i / 5) * dist;
float angle = 20.0f * i;
angle = glfwGetTime() * 25.0f;
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vector3(x, y, 0.0f));
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
Note, you've to define the distance (dist) between the cubes.
Note, the concatenation (multiplication *) of matrices is not Commutative.
If you want to rotate the entire block of cubes, then you've to do the translation before the rotation:
model = rotate * translate
Since glm::rotate respectively glm::translate, define a matrix and multiply the input matrix by the new matrix, glm::rotate has to be done before glm::translate:
glm::mat4 model = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
model = glm::translate(model, glm::vector3(x, y, 0.0f));
You can use the algorithm to calculate the cubePositions:
#include <vector>
std::vector<glm::vec3> cubePositions;
for(unsigned int i = 0; i < 25; i++)
{
float dist = 5.0f; // distance between the cubes
float x = (i % 5) * dist;
float y = (i / 5) * dist;
cubePositions.push_back(glm::vec3(x, y, 0.0f));
}
I am trying to display two cubes using modern opengl (https://preview.ibb.co/hif8t6/Screenshot_2017_10_31_09_59_27.png). The first cube is displayed by orthographic projection (left) and the second by perspective projection (right). That is working fine but i am unable to get the left cube to go behind the right cube.
Here is the relavant snippet of code
ourShader_ortho.Use();
ourShader_persp.Use();
glm::mat4 model_ortho, model1, model2, model;
glm::mat4 view_ortho, view_persp;
glm::mat4 orthographic;
glm::mat4 perspective;
model1 = glm::rotate(model, (GLfloat)glfwGetTime()*1.0f, glm::vec3(0.5f, 1.0f, 0.0f));
model2 = glm::rotate(model, (GLfloat)glfwGetTime()*1.0f, glm::vec3(0.0f, 1.0f, 0.5f));
model = model1 * model2;
view_ortho = glm::translate(view_ortho, glm::vec3(200.0f, 200.0f, -150.0f));
orthographic = glm::ortho(0.0f, (GLfloat)width, 0.0f, (GLfloat)height, 0.1f, 200.0f);
view_persp = glm::translate(view_persp, glm::vec3(1.0f, 0.0f, -3.0f));
perspective = glm::perspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 200.0f);
GLint modelLoc_ortho = glGetUniformLocation(ourShader_ortho.Program, "model");
GLint viewLoc_ortho = glGetUniformLocation(ourShader_ortho.Program, "view");
GLint projLoc_ortho = glGetUniformLocation(ourShader_ortho.Program, "orthographic");
glUniformMatrix4fv(modelLoc_ortho, 1, GL_FALSE, glm::value_ptr(model_ortho));
glUniformMatrix4fv(viewLoc_ortho, 1, GL_FALSE, glm::value_ptr(view_ortho));
glUniformMatrix4fv(projLoc_ortho, 1, GL_FALSE, glm::value_ptr(orthographic));
glBindVertexArray(VAO_O);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
GLint modelLoc_persp = glGetUniformLocation(ourShader_persp.Program, "model");
GLint viewLoc_persp = glGetUniformLocation(ourShader_persp.Program, "view");
GLint projLoc_persp = glGetUniformLocation(ourShader_persp.Program, "perspective");
glUniformMatrix4fv(modelLoc_persp, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc_persp, 1, GL_FALSE, glm::value_ptr(view_persp));
glUniformMatrix4fv(projLoc_persp, 1, GL_FALSE, glm::value_ptr(perspective));
glBindVertexArray(VAO_P);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
What do i do to get the cube with orthographic projection to go behind the cube with perspective projection?
I'm not a OpenGL programmer but this is what I think.
You are drawing the object twice using the glDrawArrays lines. For the projection matrices they are using your orthographic and perspective matrices.
However these matrices are created using different parameters:
view_ortho = glm::translate(view_ortho, glm::vec3(200.0f, 200.0f, -150.0f));
view_persp = glm::translate(view_persp, glm::vec3(1.0f, 0.0f, -3.0f));
My guess is that you want to unify the translation parameters so that the cubes lie exactly on top of each other.
E.g.
view_ortho = glm::translate(view_ortho, glm::vec3(200.0f, 200.0f, -150.0f));
view_persp = glm::translate(view_persp, glm::vec3(200.0f, 200.0f, -150.0f));
This is my game loop. I know I don't need to declare these variables twice, but I did them just in case:
while (!glfwWindowShouldClose(window))
{
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
glm::mat4 view;
view = glm::rotate(view, 50.0f, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 projection;
projection = glm::perspective(-45.0f, float(WIDTH / HEIGHT), 0.1f, 100.0f);
GLint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLint projLoc = glGetUniformLocation(shaderProgram, "projection");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
glm::mat4 model;
model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5f));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glUseProgram(shaderProgram2);
glm::mat4 view2;
view2 = translate(view2, glm::vec3(0.0f, 0.0f, -0.6f));
GLint modelLoc2 = glGetUniformLocation(shaderProgram2, "lightmodel");
GLint viewLoc2 = glGetUniformLocation(shaderProgram2, "lightview");
GLint projLoc2 = glGetUniformLocation(shaderProgram2, "lightprojection");
glm::mat4 model2;
model2 = glm::scale(model2, glm::vec3(0.5f, 0.5f, 0.5f));
glUniformMatrix4fv(viewLoc2, 1, GL_FALSE, glm::value_ptr(view2));
glUniformMatrix4fv(projLoc2, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(modelLoc2, 1, GL_FALSE, glm::value_ptr(model2));
glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
And this the output:
https://imgur.com/a/arEd7
I'm not clear if glm::perspective() input should be radians or degrees, but I tried both and they all gave the same zoomed-in, non-3D result. I don't know what I'm doing wrong here. I'm doing these according to this tutorial. My body of code looks exactly like the tutorial's save for a few classes that I created myself. What could be the problem here?
I created a sphere floating above a ground. The sphere is centered around (0,0,0). I have set up a camera with a twist, elevation, azimuth as well as moving in closer and farther from the sphere. The problem I have is that the sphere is always drawn on top of the ground. For example, if I move the camera below the ground I should see the ground be drawn on top of the sphere but that's not the case. Here are my ground and draw functions.
void init_ground()
{
GLfloat x = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
GLfloat z = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
for(int i=0; i<NUM_GROUND_LINES*2; i += 2)
{
GLfloat x = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(-x, -4.0, z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
z += 1.0;
}
for(int i=NUM_GROUND_LINES*2; i<NUM_GROUND_LINES*4; i += 2)
{
GLfloat z = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(x, -4.0, -z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
x += 1.0;
}
}
glm::vec3 cameraPos = glm::vec3(0.0, 0.0, 3.0);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
void draw()
{
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
view = glm::rotate(view, glm::radians(GLfloat(twist)), glm::vec3(0.0, 0.0, 1.0));
view = glm::rotate(view, glm::radians(GLfloat(elevation)), glm::vec3(1.0, 0.0, 0.0));
view = glm::rotate(view, glm::radians(GLfloat(azimuth)), glm::vec3(0.0, 0.0, 1.0));
projection = glm::perspective(45.0f, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
glUseProgram(program_ground);
GLint ground_proj_loc = glGetUniformLocation(program_ground, "projection");
GLint ground_view_loc = glGetUniformLocation(program_ground, "view");
GLint ground_model_loc = glGetUniformLocation(program_ground, "model");
glUniformMatrix4fv(ground_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(ground_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(ground_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_ground);
glDrawArrays(GL_LINES, 0, NUM_GROUND_LINES*2*4);
glBindVertexArray(0);
glUseProgram(program_sphere);
GLint sphere_model_loc = glGetUniformLocation(program_sphere, "model");
GLint sphere_view_loc = glGetUniformLocation(program_sphere, "view");
GLint sphere_proj_loc = glGetUniformLocation(program_sphere, "projection");
glUniformMatrix4fv(sphere_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(sphere_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(sphere_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_sphere);
glDrawArrays(GL_LINE_LOOP, 0, 342);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
To be able to remove hidden superficies, you need to enable the Depth Test.
To do that, first you must ask, at the context creation time, a buffer to store the relative z positional value of a vertex, in relation to the camera. If you are using GLFW library, this creation is done automatically.
The second step is to enable the depth test itself. To do that, you need to call:
glEnable(GL_DEPTH_TEST);
somewhere before you call your draw functions.
And, at last, at every frame draw, you must clear you depth buffer, calling:
glClear(GL_DEPTH_BUFFER_BIT);
but usually it is called as:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
to clear the color buffer as well.