How to move, rotate or scale an object on its local axis in OpenGL?

3
Hello, I have a HTransform class that stores an array, position, orientation, and scale for each object, this class is the base class of each object or entity. I made a function to move the objects and another to update the array when the position, rotation or scale are modified. But this occurs globally. But how do you move, rotate, or scale an object along its own axis using arrays in OpenGL?

    
asked by anonymous 02.04.2014 / 01:22

2 answers

1

As I understand it, the arrays that you cite allow you to correctly configure the object in the global system. Probably, you are, first, staggering, then rotating and finally translating. I'll call this global transformation

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

If for some reason you can not retrieve the object before the global transformations, you can apply the inverse of these arrays to retrieve the local system of the object. Perform local transformations and reapply global transformations again.

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

    
04.04.2014 / 21:46
3

If I have correctly understood your question, how do you do the calculations using your own HTransform class instead of using the classical classic OpenGL functions gltranslatef() , glRotatef() , glScalef() , and so on.

So, basically, so you can move, resize and rotate an object using your array, before you must load it into OpenGL. For this you use:

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(matrix); 

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

Example for Classic OpenGL

Using glfw , to create the OpenGL context, and glm , to perform the calculations of the matrices (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 arrays 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:

Being the white balls you add later to indicate the local axis of the object.

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

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

    
02.04.2014 / 03:23