How to move, rotate or scale an Object on its local axis in Opengl?

Asked

Viewed 5,586 times

4

Hello, I have a class HTransform which stores a matrix, position, orientation and scale of each object, this class is the base class of each Object or entity. I made one function to move the Object and another to update the matrix when the position, rotation or scale is modified. But this occurs globally. But how to move, rotate or scale an object along its own axis using matrices in Opengl?

  • Which version of Opengl?

  • It has to be for Opengl 1.3

  • I strongly recommend the library glm: http://glm.g-truc.net/0.9.5/index.html

  • For 1.3, I think the glm shouldn’t be much use.

  • So, until a while ago, I tried to use the glm. But I had difficulty rotating the objects with glm. I found it a little complicated.

  • But anyway, I’d like to learn how to do this using my own matrices. I’ve done a lot of research but I can’t find an answer.

  • But you how to do with GLM?

Show 2 more comments

2 answers

3

If I understand your question correctly, how do you already perform the calculations using your own class HTransform instead of using classic Opengl functions gltranslatef(), glRotatef() , glScalef() and etc.

So basically, in order for you to move, resize, and rotate an object using your matrix, you must first load it into Opengl. For this you use:

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(matrix); 

Where matrix is a pointer to a type matrix GLfloat 4x4, containing the values already calculated.

Example for Classic Opengl

Using glfw, to create the Opengl context, and glm, to perform the matrix calculations (which in your case is HTransform).

Considering the class Quad that simply serves to draw a square (or the object in question):

#ifndef QUAD_DEFINED_HPP
#define QUAD_DEFINED_HPP

#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>

// Classe do Objeto
class Quad
{
public:
    // Construtor
    Quad(float w = 30.0f, float h = 30.0f) : m_width(w), m_height(h)
    {
        // carrega com matriz identidade.
        m_model = glm::mat4(1);

        // Define a cor padrão para vermelho.
        m_cores[0] = 1.0f; // [1] e [2] são zero.
    }

    // Move o objeto para x e y
    void moverPara(float x, float y)
    {
        m_model = glm::translate(m_model, glm::vec3(x, y, 0.0f));
    }

    // translada em relação ao eixo local
    void transladar(float x, float y)
    {
        m_model += glm::translate(m_model, glm::vec3(x, y, 0.0f));
    }

    // modifica a escala
    void setEscala(float x, float y)
    {
        m_model = glm::scale(m_model, glm::vec3(x, y, 1.0f));
    }

    // rotaciona
    void rotacionar(float angulo)
    {
        m_model = m_model * glm::rotate(angulo, glm::vec3(0.0f, 0.0f, 1.0f));
    }

    // modifica a cor do quadrado
    void setCor(int r, int g, int b)
    {
        m_cores[0] = static_cast<float>(r) / 255.0f;
        m_cores[1] = static_cast<float>(g) / 255.0f;
        m_cores[2] = static_cast<float>(b) / 255.0f;
    }

    void desenhar(void)
    {
        glPushMatrix();

        // define a cor do quadrado
        glColor3fv(m_cores);

        glMatrixMode(GL_MODELVIEW);
        const GLfloat* matrix = reinterpret_cast<const GLfloat*>(&m_model);
        glLoadMatrixf(matrix);

        // Desenha os vértices do quadrado
        glBegin(GL_TRIANGLES);
        glVertex3f(0.0f, 0.0f, 0.0f);
        glVertex3f(0.0f, m_height, 0.0f);
        glVertex3f(m_width, 0.0f, 0.0f);
        glVertex3f(m_width, m_height, 0.0f);
        glVertex3f(m_width, 0.0f, 0.0f);
        glVertex3f(0.0f, m_height, 0.0f);
        glEnd();

        glPopMatrix();
    }

private:
    // largura
    float m_width;

    // altura
    float m_height;

    // matriz
    glm::mat4 m_model;

    float m_cores[3];
};

#endif

And to create the window and etc:

#include <GLFW/glfw3.h>
#include "quad.hpp"

// Ajusta a tela para desenhar de forma ortogonal (2D).
void telaOrtogonal();

// Ponteiro para a janela atual.
GLFWwindow* window;

int main(void)
{
    // Inicializa a glfw.
    if (!glfwInit())
    {
        // falhou
        return -1;
    }

    // Cria uma janela com um contexto de opengl
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        // falhou ao criar a janela
        glfwTerminate();
        return -1;
    }

    // Define a janela criada como o contexto atual.
    // Isso é usado para casos em que há vários
    // contextos opengl em um mesmo programa.
    glfwMakeContextCurrent(window);

    // O objeto que será desenhado.
Quad quad1;
quad1.moverPara(20, 20);
quad1.setEscala(2.0f, 2.0f);

Quad quad2;
quad2.setCor(0, 0, 255);

quad2.moverPara(100, 80);
quad2.transladar(0, 20);
quad2.rotacionar(45);

    // Loop principal, rodado até que o usuário feche a janale.
    while (!glfwWindowShouldClose(window))
    {
        // Ajusta para tela ortogonal (2D).
        telaOrtogonal();

        // Desenha os quadrados
        quad2.desenhar();
        quad1.desenhar();

        // Atualiza os buffers
        glfwSwapBuffers(window);

        // Processa os eventos (mouse, teclado, sistema e etc).
        glfwPollEvents();
    }

    // Finaliza a glfw.
    glfwTerminate();

    return 0;
}

void telaOrtogonal()
{
    int width, height;

    glfwGetFramebufferSize(window, &width, &height);

    glViewport(0, 0, width, height);
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
}

Note that matrices are only updated in calls:

Quad quad1;
quad1.moverPara(20, 20);
quad1.setEscala(2.0f, 2.0f);

Quad quad2;
quad2.setCor(0, 0, 255);
quad2.moverPara(100, 80);
quad2.transladar(0, 20);
quad2.rotacionar(45);

The result is this:

Resultado

White balls being added later to indicate the local axis of the object.


To learn how the functions of translate, scale, rotate have been implemented you can see the source code of the glm, is pure mathematics. But, I strongly recommend that you consider using a specialized library for matrix calculations (or at least see the source code) because they are generally well optimized, tested and most use optimizations of type SSE, SSE2, SSE3 (etc) in matrix calculations.


If it is also possible instead of using Opengl 1.3, you might consider using Opengl 3.3+, as Opengl 3 has rendered several classic Opengl functions obsolete.

  • Lucas, thank you for the answer. But what I want is to move, rotate and scale an object on its own axis. This example you did only makes transformations on global axes. Example quad2.movePara((float x, float y), bool local), got it?

  • The moverPara() functions relative to the overall axis. The transladar() translation in relation to the local axis. And the rotation is already on the local axis.

  • @Walbertievaristo I added an image to illustrate the example, with the axes highlighted.

2


From what I understand, the matrices you cite allow you to configure, correctly, the object in the global system. Probably, you are, first, scaling, then rotating and finally translating. I will call this global transformation

There are several ways to solve your problem. One of them is to apply the local transformations you want, before applying the global transformations. For example, if you want the Rotacione object around its axis, apply the rotation Matrix and then apply the global transformation Matrix.

If you, for some reason, cannot recover the object before the global transformations, you can apply the inverse of these matrices to recover the local system of the object. Realize local transformations and reapply global transformations, again.

Example Mglobal = T.R.S, Mglobal_inversa = S ¹. R ¹. T ¹, therefore P' = Mglobal.Mlocal.Mgloval_inversa. P

  • Tomás Badan, pasta. Mas vamos supor que eu tenha na minha classe base HTransform as seguintes variáveis: m_Position; m_Orientation; m_Scaling; m_LocalPosition; m_LocalOrientation; m_localScaling; Eu teria que aplicar tipo exemplo: MGlobal.rotate(m_Orientation); MLocal.rotate(m_LocalOrientation); Depois. Mtotal = Mglobal * Mlocal * Mglobal.inverse(); This?. Is that I am linking my engine to Lua script so that I can access it later via script.

  • Since your mesh is already in local coordinates, it first applies local transformations and then global ones. That is, Mtotal = Mglobal.MLocal. The idea of applying the reverse is in case you no longer have the local coordinate available.

  • Tomás, thank you very much. If it’s not too much to ask, like, I still don’t know how to apply position, rotation, scale both global and local in the object matrix. It’s been a long time since I’ve been searching for something like this but I can’t find an answer.

  • The final matrix is the multiplication of the transformations read from right to left. That is, Mfinal = MtglobalMrglobalMsglobalMtlocalMrlocal*Mslocal. As it is using openGL 1.3, in the programming, vc specifies how it reads, i.e., glTranslate(global); glRotate(global); glScale(global); glTranslate(local); glRotate(local); glScale(local); I hope I have been clearer now

Browser other questions tagged

You are not signed in. Login or sign up in order to post.