Как заставить один объект «вращаться» вокруг другого объекта?

#c #opengl #matrix #vector #rotation

#c #opengl #матрица #вектор #вращение

Вопрос:

В настоящее время я работаю над проектом, включающим два куба. Первый куб должен был быть статичным, в то время как второй будет вращаться или вращаться по орбите вокруг первого. Я совсем новичок в программировании на OpenGL, поэтому у меня возникают немалые трудности с тем, чтобы заставить это работать. Кто-нибудь может указать мне правильное направление? Пока у меня есть только два куба, но я не могу заставить их двигаться, как если бы они были анимированы. Вот мой код, если вы хотите внести предложения. Большое вам спасибо!

Главная:

 #include "vgl.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
#include "Box.h"
#include "Camera.h"
#include "VertexBufferData.h"
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

using namespace std;
using namespace glm;

#define SPACEBAR_KEY 32
#define ESCAPE_KEY 033

Camera* camera;
vector<Box * > gameObjects;
bool keyDown[255];

void CheckKeyboard(){

    if (keyDown['a'])
        camera->RotateLeft();
    if (keyDown['d'])
        camera->RotateRight();
    if (keyDown['w'])
        camera->MoveForward();
    if (keyDown['s'])
        camera->MoveBackWard();
    if (keyDown['e'])
        camera->StrafeRight();
    if (keyDown['q'])
        camera->StrafeLeft();
}

void closeApp()
{
    delete camera;
    for (auto it = gameObjects.begin(); it != gameObjects.end();   it) {
        delete (*it);
    }
}


void keyboard(unsigned char key, int x, int y)
{
    switch (key) 
    {
        case ESCAPE_KEY:  // ASCII Escape Key Code
            closeApp();
            exit(EXIT_SUCCESS);
            break;
        default:
            keyDown[key] = true;
    }

    glutPostRedisplay();
}

void keyboardUp(unsigned char key, int x, int y)
{
    keyDown[key] = false;
}

void mouseWheel(int button, int direction, int x, int y)
{

    if (button == 16)
        camera->ResetFOV();
    else if (direction > 0)
        camera->ZoomIn();
    else
        camera->ZoomOut();
}

void mouseMovement(int x, int y)
{
    static bool warp = true;

    if (warp)
    {
        if (x>glutGet(GLUT_WINDOW_WIDTH) / 2)
            camera->RotateRight();
        else if (x<glutGet(GLUT_WINDOW_WIDTH) / 2)
            camera->RotateLeft();

        if (y>glutGet(GLUT_WINDOW_HEIGHT) / 2)
            camera->RotateUp();
        else if (y<glutGet(GLUT_WINDOW_HEIGHT) / 2)
            camera->RotateDown();

        glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
        warp = false;
    }
    else
        warp = true;
}

void timer(int value)
{
    glutPostRedisplay();
    glutTimerFunc(25, timer, 0);
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    CheckKeyboard();
    camera->Update();
    for (auto it = gameObjects.begin(); it != gameObjects.end();   it) {
        (*it)->shaderProgram->bindShader();
        glm::mat4 MVP = camera->ProjectionMatrix *  camera->ViewMatrix * (*it)->getModelMatrix();
        (*it)->shaderProgram->sendUniform4x4("MVP", glm::value_ptr(MVP));
        (*it)->Draw();
    }
    glutSwapBuffers();
}

void init()
{
    int i = 0, forever = 0;

    camera = new Camera();
    memset(keyDown, false, sizeof(keyDown));

    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
    glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
    glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);

    VertexBufferData vertexBufferData = VertexBufferData("Data\Models\Objects.xml");

    gameObjects.push_back(new Box(vertexBufferData, glm::vec3(-2.0f, 0.0f, 0.0f), "Data\Shaders\Vertex.shader", "Data\Shaders\Fragment.shader"));

    gameObjects.push_back(new Box(vertexBufferData, glm::vec3(2.0f, 0.0f, 0.0f), "Data\Shaders\Vertex.shader", "Data\Shaders\Fragment.shader"));

    gameObjects[1]->setRotation(45.0f, vec3(0.0f, 0.0f, 1.0f));
    gameObjects[0]->setScaleMatrix(vec3(2, 2, 2));
}



int main(int argc, char** argv)
{
    glutInit(amp;argc, argv);

    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(1024, 768);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutCreateWindow("Satterwhite_Project_3");


    if (glewInit())
    {
        cerr << "Unable to init glew" << endl;
        exit(EXIT_FAILURE);
    }

    init();
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutKeyboardUpFunc(keyboardUp);
    glutPassiveMotionFunc(mouseMovement);
    glutMouseWheelFunc(mouseWheel);
    glutTimerFunc(25, timer, 0);
    glutMainLoop();
    return 0;
}
  

Box.cpp

 #include "Box.h"

Box::Box(VertexBufferData amp;vbd,  vec3 initialPosition,const string vertexShader, const string fragmentShader):GameObject(vertexShader, fragmentShader)
{   
    Position=initialPosition;
    vertexBufferData =vbd;

    RotationMatrix=mat4(1.0f);
    OrbitMatrix = mat4(1.0f);
    ScaleMatrix=mat4(1.0f);
    TranslationMatrix =translate(glm::mat4(1.0f), Position);

    if (!shaderProgram->initialize())
    {
        std::cerr << "Could not initialize the shaders" << std::endl;
    }

    shaderProgram->bindShader();

    glGenVertexArrays(1, amp;VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, amp;vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertexBufferData.verticiesSize, amp;vertexBufferData.verticies[0], GL_STATIC_DRAW);

    glGenBuffers(1, amp;fragmentBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertexBufferData.colorSize, amp;vertexBufferData.colors[0], GL_STATIC_DRAW);

    shaderProgram->linkProgram();
}
void Box::setRotation(float degrees, vec3 axis)
{
    RotationMatrix=rotate(glm::mat4(1.0f), degrees, axis);
    RotationMatrix=rotate(RotationMatrix, degrees, vec3(1.0f,0.0f,0.0f));
}

void Box::setScaleMatrix(vec3 scale)
{
    ScaleMatrix = glm::scale(mat4(1.0f), scale);
}

/*void Box::setOrbitMatrix(vec3 Position, vec3 axis)
{
    OrbitMatrix = 
}*/

void Box::Draw()
{
    shaderProgram->bindShader();

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));

    glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
    glVertexAttribPointer(1, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));    

    glDrawArrays(GL_TRIANGLES, 0, vertexBufferData.verticies.size());

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
}
  

Box.h

 #pragma once
#include "GameObject.h"

class Box :  public GameObject
{

private:
    mat4 ModelMatrix;
    mat4 RotationMatrix;
    mat4 OrbitMatrix;
    mat4 TranslationMatrix;
    mat4 ScaleMatrix;
public:

    void Draw();
    virtual ObjectType getType() const { return BOX; }

    mat4 getModelMatrix() {return TranslationMatrix*RotationMatrix*ScaleMatrix;}
    mat4 getMRotationMatrix() {return RotationMatrix;}
    mat4 getTranslationMatrix() {return TranslationMatrix;}
    mat4 getOrbitMatrix(){ return OrbitMatrix; }
    mat4 getScaleMatrix() {return ScaleMatrix;}
    void setRotation(float degrees, vec3 axis);
    void setScaleMatrix(vec3 scale);
    void setOrbitMatrix(vec3 Position, vec3 axis);

    Box(VertexBufferData amp;vertexBufferData, vec3 initialPosition, const string vertexShader, const string fragmentShader);

    vec3 Position;
    mat4 rot;
    mat4 scale;
};
  

Комментарии:

1. В этом видео рассматривается подход с использованием радианов, расстояния и произвольного значения времени. Это на C #, но это наверняка поможет вам двигаться в правильном направлении! Видео на YouTube, посвященное вращению по орбите и созданию галактики

2. Я ценю это, и я попробовал, но у меня все еще много трудностей. Может быть, вы могли бы привести мне другой пример или что-то в этомроде?