How to move objects after rotation in Qt? - c++

I have several planes(2 for example). I need to rotate each of them around share center and then translate it to different coordinates. For example, i have two planes
Mesh CreateMeshPlane(Vector3D bottomleft, size_t numvertices_x,
size_t numvertices_y, size_t max_x,
size_t max_y)
{
Just generation VBO for plane.
}
planeZY = CreateMeshPlane({0.0, 0.0, 0.0}, 100, 100, 2, 2);
planeZY1 = CreateMeshPlane({0.0, 0.0, 0.0}, 100, 100, 2, 2);
i need to rotate them around some origin, then i need to move them in some point.
What do i do?
planeZY.setupMesh();
planeZY.position = QVector3D(0.0, 0.0, 2.0);
planeZY.origin = QVector3D(1, 1, 1);
planeZY.rotation = QVector3D(0.0f, -90.0f, 0.0f);
planeZY.updateModelMatrix();
planeZY1.setupMesh();
planeZY.origin = QVector3D(1, 1, 1);
planeZY1.position = QVector3D(2.0, 0.0, 0.0);
planeZY1.rotation = QVector3D(0.0f, -90.0f, 0.0f);
planeZY1.updateModelMatrix();
void updateModelMatrix()
{
this->modelMatrix.setToIdentity();
this->modelMatrix.translate(this->origin);
this->modelMatrix.rotate(this->rotation.z(), QVector3D(0.f, 0.f, 1.f));
this->modelMatrix.rotate(this->rotation.y(), QVector3D(0.f, 1.f, 0.f));
this->modelMatrix.rotate(this->rotation.x(), QVector3D(1.f, 0.f, 0.f));
this->modelMatrix.translate(this->position - this->origin);
}
There is a problem, local axis changes their direction after rotation and my plane move in a wrong direction. How to rotate objects in opengl and move them along global axes?

Related

How to change the view perspective in OpenGL?

I draw many lines to form a grid. I want to see the grid rotated on its X-axis, but I never get the intended result. I tried glRotatef and gluLookAt which does not work the way I want. Please see the pictures below.
this is the grid
this is how I want to see it
Edit: geez, posting the code here is also hard, lol, anyway here it is.
Edit2: removed, only leave the code that has issues.
Please find the code below, no matter how I set the gluLookAt, the grid result won't be in the perspective I want.
#include <GL/glut.h>
void display() {
...
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
for (int i = 0; i < 720; i += 3)
{
glColor3f(0, 1, 1);
glVertex3f(linePoints[i], linePoints[i + 1], linePoints[i + 2]);
}
glEnd();
glFlush();
}
void init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -2, 1.25, 0, 0, 0, 0, 1, 0);
}
Lets assume, that you have a grid in the xy plane of the world:
glColor3f(0, 1, 1);
glBegin(GL_LINES);
for (int i = 0; i <= 10; i ++)
{
// horizontal
glVertex3f(-50.0f + i*10.0f, -50.0f, 0.0f);
glVertex3f(-50.0f + i*10.0f, 50.0f, 0.0f);
// vertical
glVertex3f(-50.0f, -50.0f + i*10.0f, 0.0f);
glVertex3f( 50.0f, -50.0f + i*10.0f, 0.0f);
}
glEnd();
Ensure that the distance of to the far plane of the projection is large enough (see gluPerspective). All the geometry which is not in between the near an far plane of the Viewing frustum is clipped.
Further more ensure that the aspect ratio (4.0 / 3.0) match the ratio of the viewport rectangle (window).
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 200);
For the use of gluLookAt, the up vector of the view has to be perpendicular to the grid. If the grid is arranged parallel to the xy plane, then the up vector is z axis (0, 0, 1).
The target (center) is the center of the grid (0, 0, 0).
The point of view (eye position) is ought to be above and in front of the grid, for instance (0, -55, 50). Note the point of view is used for a grid with the bottom left of (-50, -50, 0) and a top right of (50, 50, 0).
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -55.0, 50.0, 0, 0, 0, 0, 0, 1);

Modern Opengl: Rotate a cuboid with pivot at one end of the cuboid

So, I drew a Yellow cuboid using this
glm::mat4 yellow_bone_obj_mat = m_bone_animation->get_yellow_mat();
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE,
glm::value_ptr(yellow_bone_obj_mat));
bone_obj->obj_color = m_bone_animation->colors[1];
draw_object(shader, *bone_obj);
witth the scale factor { 0.5f,4.0f,0.5f } and position { 2.0f,3.0f,2.0f }
I want my yellow cuboid to rotate 90 degrees towards right, while the end position of the yellow cuboid to stick the red cube
It should look like this
I tried
m_yellow_mat = glm::translate(m_yellow_mat, glm::vec3(0.0, -0.5, 0.0)); //0.5f is just random number to check if pivot changed
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(angle), glm::vec3(0, 0, 1));
m_yellow_mat = glm::translate(m_yellow_mat, glm::vec3(0.0, 0.5, 0.0));
Got this as output
Next i tried
m_yellow_mat = glm::translate(m_yellow_mat, glm::vec3(0.0, -0.5, 0.0)); //0.5f is just random number to check if pivot changed
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(angle), glm::vec3(1, 0, 0)); //changed axis
m_yellow_mat = glm::translate(m_yellow_mat, glm::vec3(0.0, 0.5, 0.0));
Got this as output. No matter what I do, the cuboid isn't falling at the right side. I am not sure why
What you actually do is to rotate a perfect cube and to scale the rotated cube. The cube is rotated, but the scale is applied after, so it appears to be always orientated to the same direction.
You've to scale the cube and then you've to rotated the cuboid:
m_yellow_mat = translate(pivot) * rotate * translate(-pivot) * scale
Note, operations like rotate, scale and translate create a new matrix and multiply the current matrix by the new matrix. e.g:
vec3 scale = glm::vec3(0.5f, 4.0f, 0.5f);
vec3 pivot = glm::vec3(0.0f, 0.5f, 0.0f);
m_yellow_mat = glm::mat4(1.0f);
m_yellow_mat = glm::translate(m_yellow_mat, pivot);
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(angle), glm::vec3(0, 0, 1));
m_yellow_mat = glm::translate(m_yellow_mat, -pivot);
m_yellow_mat = glm::scale(m_yellow_mat, scale);

Rendering visually perfect squares in OpenGL?

In OpenGL's fixed pipeline, by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space. Therefore, given a set of 4 perfectly adjacent screen-space vertices using GL_TRIANGLE_STRIP (or even GL_QUADS), and unless your window is already perfectly square, you will always render a rectangle instead of a perfect square...
Knowing the width, height and aspect ratio of a window, is there some way to correct this?
I have tried multiplying the vertex coordinates by the aspect ratio, which unfortunately seemed to achieve the same visual effect.
Here's the full source code I'm currently using:
#include "main.h"
#pragma comment(lib, "glut32.lib")
int g_width = 800;
int g_height = 600;
int g_aspectRatio = double(g_width) / double(g_height);
bool g_bInitialized = false;
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(g_width, g_height);
glutCreateWindow("OpenGL Test App");
glutDisplayFunc(onRender);
glutReshapeFunc(onSize);
glutIdleFunc(onRender);
glutMainLoop();
return 0;
}
void onInit()
{
glFrontFace(GL_CW);
}
void onRender()
{
if(!g_bInitialized)
onInit();
static float angle = 0.0f;
const float p = 0.5f * g_aspectRatio;
glLoadIdentity();
gluLookAt(
0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glScalef(1, -1, 1); // Flip the Y-axis
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLE_STRIP);
{
glColor4f(1.0, 0.0, 0.0, 1.0); // Red
glVertex3f(-p, -p, 0.0); // Top-Left
glColor4f(0.0, 1.0, 0.0, 1.0); // Green
glVertex3f(p, -p, 0.0); // Top-Right
glColor4f(0.0, 0.0, 1.0, 1.0); // Blue
glVertex3f(-p, p, 0.0); // Bottom-Left
glColor4f(1.0, 1.0, 0.0, 1.0); // Yellow
glVertex3f(p, p, 0.0); // Bottom-Left
}
glEnd();
angle += 0.6f;
glutSwapBuffers();
}
void onSize(int w, int h)
{
g_width = max(w, 1);
g_height = max(h, 1);
g_aspectRatio = double(g_width) / double(g_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45, g_aspectRatio, 1, 1000);
glMatrixMode(GL_MODELVIEW);
}
EDIT:
This has been solved... In the above code, I had defined g_aspectRatio as an int instead of a floating-point value. Therefore, it's value was always 1...
In my (old) experience, that's just why you have an aspect ratio argument to gluPerspective().
The manual page says:
In general, the aspect ratio in gluPerspective should match
the aspect ratio of the associated viewport. For example, aspect = 2.0
means the viewer's angle of view is twice as wide in x as it is in y.
If the viewport is twice as wide as it is tall, it displays the image
without distortion.
Check your g_aspectRatio value.
by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space
Wrong. Coordinates passed to OpenGL through glVertex or a glVertexPointer vertex array are in model space. The transformation to screen space happens by transforming into view space by the modelview matrix and from view space to clip space by the projection matrix. Then clipping is applied and the perspective divide applied to reach normalized coordinate space.
Hence the value range for glVertex can be whatever you like it to be. By applying the right projection matrix you get your view space to be in [-aspect; aspect]×[-1, 1] if you like that.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1);

Apply transformations to Bounding Box

I am trying to make a tank game. I have successfully loaded an OBJ model, and calculated its bounding box for the model at the origin.
I am now trying to apply the transformations done to my model in the game logic to the original coordinates for the bounding box. For this, I grab the modelview matrix right before drawing my model, then multiply this matrix for the two vectors that define the BBox.
Here is the code that draws my tank:
void drawTank()
{
bBox = calcBBox(modelo, 1);
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, texTank);
glScalef(0.2, 0.2, 0.2);
glTranslatef(posTank.x,posTank.y,posTank.z);
glRotatef(anguloTanque, 0, 1, 0); // rotate around Y (horizontal)
glRotatef(90, 0, 1, 0);
glRotatef(-90, 1, 0, 0);
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
glmDraw(modelo, GLM_TEXTURE | GLM_MATERIAL);
glColor3f(1,0,0);
drawBBox(bBox);
glPopMatrix();
}
With this snippet, my bbox is properly drawn over the tank model (transformations are applied in rendering by the glTranslate & glRotate functions). As you can see I also grab here my ModelView matrix.
Then I apply this matrix as follows (this is my entire display function):
void Display(void) {
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
camera();
glEnable(GL_TEXTURE_2D);
//glTranslatef(0,-40,150);
//PLANE
glBindTexture(GL_TEXTURE_2D, texArena);
glBegin(GL_POLYGON);
glTexCoord2f( 0.0f, 0.0f );
glVertex3f(-500, 0, -500);
glTexCoord2f( 5.0f, 5.0f );
glVertex3f(500, 0, -500);
glTexCoord2f(5.0f, 0.0f );
glVertex3f(500, 0, 500);
glTexCoord2f( 0.0f, 5.0f );
glVertex3f(-500, 0, 500);
glEnd();
drawTank();
glPopMatrix();
point3D max = bBox.max;
point3D min = bBox.min;
point3D resultMax;
point3D resultMin;
//Transformacion
multVectorByMatrix(matrix, max, resultMax);
multVectorByMatrix(matrix, min, resultMin);
bBox.max.x = resultMax.x; bBox.max.y = resultMax.y; bBox.max.z = resultMax.z;
bBox.min.x = resultMin.x; bBox.min.y = resultMin.y; bBox.min.z = resultMin.z;
glPushMatrix();
glColor3f(1,1,1);
drawBBox(bBox);
glPopMatrix();
glFlush();
glutSwapBuffers();
}
The function that multiplies a vector by a matrix:
void multVectorByMatrix(float* matrix, point3D vector, point3D &result)
{
result.x = (matrix[0] * vector.x) +
(matrix[4] * vector.y) +
(matrix[8] * vector.z) +
matrix[12];
result.y = (matrix[1] * vector.x) +
(matrix[5] * vector.y) +
(matrix[9] * vector.z) +
matrix[13];
result.z = (matrix[2] * vector.x) +
(matrix[6] * vector.y) +
(matrix[10] * vector.z) +
matrix[14];
}
If I draw the bounding box with this render loop, then my bounding box gets drawn but transformations are not applied properly. I can see the bounding box moving correctly with translations, but rotations are not done right.
What might be the problem here?
edit: some screenshots
Your problem is in this code.
point3D max = bBox.max;
point3D min = bBox.min;
point3D resultMax;
point3D resultMin;
//Transformacion
multVectorByMatrix(matrix, max, resultMax);
multVectorByMatrix(matrix, min, resultMin);
bBox.max.x = resultMax.x; bBox.max.y = resultMax.y; bBox.max.z = resultMax.z;
bBox.min.x = resultMin.x; bBox.min.y = resultMin.y; bBox.min.z = resultMin.z;
glPushMatrix();
glColor3f(1,1,1);
drawBBox(bBox);
glPopMatrix();
You take two vertices from your box and then apply transformations to them, then you use this transformed vertices to display a box, which of course will be axis aligned, because that's the only box you can get from just two opposite vertices. And you can see on your screenshot, that you bbox and the correct bbox have common vertices - these are exactly the vertices you applied your transformations to. So, in order to get a correct bbox, you need to get all vertices of the bbox and apply these transformations to all of them. Then you'll get exactly what you want.

OpenGL ES 1.1 image rotation from its center

I'm trying to rotate a 2D image using OGL ES. After load it I can move it through the screen but when trying to rotate the image through its center, it has an odd behavior as the rotation center is the lower-left screen corner, not the center of the image itself.
Googling around I've read that I could push the current matrix, change whatever I need (translate the coords, rotate the image, etc) and then pop the matrix coming back to the previous matrix status... I did it but still not working as I'm looking for (but at least now seems that the original coords where it does the rotation are not the lower-left corner...)
Any thoughts? Anyone could spot where my problem is?
Any help would be much appreciated! Thanks!!
void drawImage(Image *img)
{
GLfloat fX = (GLfloat)img->x;
GLfloat fY = (GLfloat)(flipY(img->m_height+img->y));
GLfloat coordinates[] = { 0, img->m_textureHeight, img->m_textureWidth, img->m_textureHeight, 0, 0, img->m_textureWidth, 0 };
GLfloat vertices[] =
{
fX, fY, 0.0,
img->m_width+fX, fY, 0.0,
fX, img->m_height+fY, 0.0,
img->m_width+fX, img->m_height+fY, 0.0
};
//Push and change de matrix, translate coords, rotate and scale image and then pop the matrix
glPushMatrix(); //push texture matrix
glTranslatef((int)fX, (int)fY, 0.0); //translate texture matrix
// rotate
if (img->rotation != 0.0f )
glRotatef( -img->rotation, 0.0f, 0.0f, 1.0f );
// scale
if (img->scaleX != 1.0f || img->scaleY != 1.0f)
glScalef( img->scaleX, img->scaleY, 1.0f );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0, 0.0, 0.0, 1.0);
glBindTexture(GL_TEXTURE_2D, img->m_name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
Most importantly, you need to understand how to do this operation.
before doing a rotation you have to translate your self in the rotation origin and only then apply to rotation.
Check out this article which explains it well.
The simple breakdown is:
move object to origin.
Rotate.
Move object back.