Абсолютная шкала - вектор вращающейся шкалы - PullRequest
0 голосов
/ 05 ноября 2018

Необходимо получить глобальный абсолютный масштаб объекта, чтобы отобразить его с помощью OpenGL . Когда я просто умножаю масштабные векторы родителей и детей, я получаю абсолютную шкалу для пространства мировых осей. Когда я вращаю объект, он масштабируется по глобальным осям, а не по локальной.

Я решил, что мне тоже нужно повернуть вектор масштаба. Но:

  1. Когда я пытаюсь повернуть его с вектором направления - его значения иногда собираются в 0, и тоже масштабируются.

    { scale.x * forward.x , scale.y * forward.y , scale.z * forward.z }
    
  2. Когда я пытаюсь повернуть его с помощью glm::rotate, это приводит к неожиданным результатам, таким как бесконечное вращение / масштабирование, гаечный ключ и другие эффекты для сеток.

    auto globalScale = glm::vec3(scale.x, scale.y, scale.z);
    globalScale = glm::rotate(globalScale, rotation.x, {1,0,0});
    globalScale = glm::rotate(globalScale, rotation.y, {0,1,0});
    globalScale = glm::rotate(globalScale, rotation.z, {0,0,1});
    

Мой код рендеринга:

void Render(Material *mat, Transform* tr){

    glEnable(GL_COLOR_MATERIAL);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);

    // Get object transformations
    Vector3 pos = tr->globalPosition();
    Vector3 rot = tr->globalRotation();
    Vector3 scale = (tr->globalScale());
    auto globalScale = glm::vec3(scale.x, scale.y, scale.z);

    // First, scaling, then rotating, then translating in world space
    // ( Initially all objects rendering starts at (0,0,0) )
    glScaled(globalScale.x, globalScale.y, globalScale.z);
    glRotatef(rot.x, 1.0, 0.0, 0.0);
    glRotatef(rot.y, 0.0, 1.0, 0.0);
    glRotatef(rot.z, 0.0, 0.0, 1.0);
    glTranslated(pos.x, pos.y, pos.z);

    // Rendering 

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(3,GL_FLOAT,0,vertexArray);
    glNormalPointer(GL_FLOAT,0,normalArray);

    glClientActiveTexture(GL_TEXTURE0_ARB);
    glTexCoordPointer(2,GL_FLOAT,0,uvArray);

    glDrawArrays(GL_TRIANGLES,0,numVerts);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    // Rolling transformations back

    glTranslated(-pos.x, -pos.y, -pos.z);
    glRotated(-rot.z, 0.0, 0.0, 1.0);
    glRotated(-rot.y, 0.0, 1.0, 0.0);
    glRotated(-rot.x, 1.0, 0.0, 0.0);
    glScaled(1/globalScale.x, 1/globalScale.y, 1/globalScale.z);
}

Оказание звонка:

void RenderObject(GameObject* go){
    for(auto goc : go->children)
        goc->Update<MeshRenderer>();//RenderObject(goc);
}

void RenderScene(){
    auto scene = EditorInstance::GetSingleton()->currentScene;
    for(auto go : scene->hierarchy){
        RenderObject(go);
        if(auto mr = (go->GetComponent<Camera>())){
            mr->Update();
        }
    }
}

... render->setOnRender(RenderScene); ...

Основной метод рендеринга:

int render()
{
#ifdef EDITOR
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
        glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
        DrawGrid(100);
#else
    if(NukeOGL::getSingleton() != this){
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
        glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
    }
#endif

    //glClearColor(0, 0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity ();

    gluLookAt(transform->position.x,
                      transform->position.y,
                      transform->position.z,
                      transform->position.x + transform->direction().x,
                      transform->position.y + transform->direction().y,
                      transform->position.z + transform->direction().z,
                      0.0,
                      1.0,
                      0.0);

    if(_onRender.size() > 0)
        for(auto _rn : _onRender){
            _rn();
        }

#ifdef EDITOR
    glPopAttrib(); // Restore our glEnable and glViewport states
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
#else
    if(NukeOGL::getSingleton() != this){
        glPopAttrib(); // Restore our glEnable and glViewport states
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
    }
#endif
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(_onGUI.size() > 0)
        for(auto _rn : _onGUI){
            _rn();
        }

    glutSwapBuffers();
    //glutPostRedisplay();
    return 0;
}

Что я делаю не так? Что я должен сделать, чтобы сделать правильный масштаб от локального до мирового пространства?

1 Ответ

0 голосов
/ 05 ноября 2018

Масштаб и вращение линейные преобразования , их влияние зависит от расстояния до начала системы координат. Вы должны применять их в правильном порядке и с правильным происхождением.

Я объясняю в 2D, чтобы было легче понять.
Скажем, у вас есть прямоугольник размером axb, центр которого находится в {cx,cy}, и вы хотите масштабировать и вращать (в этом порядке). Затем вы сначала переводите в {0,0}, затем масштабируете, затем вращаете, затем переводите обратно в {cx,cy}. Поскольку каждое преобразование определяется матрицей, и обычно матрицы OpenGL определяются в порядке мэров столбцов, составная матрица для этого объекта может быть:

MObj_i = MObj_i_trans(cx,cy) * MObj_i_rot(cangle, caxis) * MObj_i_sca(cfactor) * MObj_i_trans(-cx,-cy)

После того, как вы выполните эти преобразования для каждого объекта (со своим собственным центром / масштабом / вращением каждого), вы захотите «глобальный» масштаб и вращение. Опять вам нужен центр масштаба / вращения:

MGlobal = MGlo_trans(gx,gy) * MGlo_rot(gangle, gaxis) * MGlo_sca(gfactor) * MGlo_trans(-gx,-gy)

Обычно мировой центр `{0,0} ', поэтому вы можете избежать переводов:

MGlobal = MGlo_rot(gangle, gaxis) * MGlo_sca(gfactor)

Хорошая новость заключается в том, что преобразования могут быть объединены в единственную матрицу. Итак, для каждого объекта вы применяете матрицу:

MObjec_i = MGlobal * MObj_i

Если вы используете glm для этой математики, не забудьте инициализировать Identity matrix :

glm::mat4 objScale(1.0);
objScale(objScale, vec3(fx, fy, fz));
glm::mat4 objRotate(1.0);
objRotate(objRotate, angle, vec3(axis.x, axis.y, axis.z));
etc.
...