Почему модель моего цилиндра не может вращаться по оси Z? - PullRequest
1 голос
/ 09 октября 2011

Я попытался написать следующий код, чтобы нарисовать цилиндр. Цилиндр был нарисован в C ++ с помощью OpenGL. И в школе мне дали небольшой инструмент, который я мог бы скомпилировать с помощью файла cpp моей модели, а затем поворачивать модель с помощью мыши. Инструмент не влияет на вращение моей модели, потому что он работает для других демонстрационных моделей. Однако по какой-то причине, которую я не понимаю, я не могу повернуть цилиндр по оси Z, чтобы увидеть его в горизонтальном положении. Таким образом, цилиндр можно вращать и видеть только в следующих направлениях:

enter image description here

Почему я не могу повернуть цилиндр, чтобы увидеть его в этом направлении? Следующее изображение было повернуто вручную в Photoshop, чтобы показать направление обзора, на которое модель не смогла повернуть:

enter image description here

Я не понимаю, по какой причине не вращаться в этом направлении, потому что демонстрация, показанная для других моделей (написанных другими), может вращаться свободно во всех направлениях.

Это код, который я написал, чтобы попробовать в mymodel.cpp:

void drawCylinderObject() {
    float topRadius = 5;
    float bottomRadius = 5;
    float height = 10;
    int numOfPolygons = 50;
    float basisvec1[3] = {1, 0, 0};
    float basisvec2[3] = {0, 0, -1};
    float topPosition[3] = {0, height/2.0, 0};
    float bottomPosition[3] = {0, -height/2.0, 0};


    for(int i=0; i<numOfPolygons; i++) {
        float angle1 = (float)i/(float)numOfPolygons*2.0*M_PI;
        float angle2 = ((float)i+1.0)/(float)numOfPolygons*2.0*M_PI;
        vector<float> point1(3), point2(3), point3(3), point4(3);
        for(int j=0; j<3; j++) {
            point1[j] = topPosition[j] + topRadius * cos(angle1) * basisvec1[j] + topRadius * sin(angle1) * basisvec2[j];
        }


        for(int j=0; j<3; j++) {
            point2[j] = bottomPosition[j] + bottomRadius * cos(angle1) * basisvec1[j] + bottomRadius * sin(angle1) * basisvec2[j];

        }

        for(int j=0; j<3; j++) {
            point3[j] = bottomPosition[j] + bottomRadius * cos(angle2) * basisvec1[j] + bottomRadius * sin(angle2) * basisvec2[j];
        }

        for(int j=0; j<3; j++) {
            point4[j] = topPosition[j] + topRadius * cos(angle2) * basisvec1[j] + topRadius * sin(angle2) * basisvec2[j];
        }

        float crossvec1[3] = {point4[0]-point1[0], point4[1]-point1[1], point4[2]-point1[2]};
        float crossvec2[3] = {point2[0]-point1[0], point2[1]-point1[1], point2[2]-point1[2]};
        float normalVector1[3];

        crossProduct(crossvec2, crossvec1, normalVector1);

        glBegin(GL_POLYGON);

        glNormal3fv(normalVector1);

        glVertex3f(point1[0], point1[1], point1[2]);
        glVertex3f(point2[0], point2[1], point2[2]);
        glVertex3f(point3[0], point3[1], point3[2]);
        glVertex3f(point4[0], point4[1], point4[2]);

        glEnd();
    }
}

И перезаписанная функция у меня такая же, как и в mymodel.cpp:

void CRenderView::drawScene()
{
    //calls the above function
    drawCylinderObject();
}

Что я сделал в основном, так это просто определил 2 перпендикулярных вектора базисных единиц, а затем расширил их наружу со значением величины. И я повторяю эти 360 градусов, чтобы нарисовать многоугольники для формирования цилиндра. Но что плохого в том, что этот способ рисования не позволяет мне свободно вращать модель?

Edit:

Следующее является частью кода того, как инструмент рисует сцену. Так или иначе, у инструмента есть огромный кусок классов. Большинство его классов просто настраивают GUI инструмента, и затем единственная часть, которая рисует его, это та, что ниже в CRenderView.cpp:

void CRenderView::OnPaint() 
{
    // Device context for painting
    CPaintDC dc(this); 

    // Model is stored in Document
    CToolDoc *pDoc = (CToolDoc *)GetDocument();
    ASSERT_VALID(pDoc);

    // Useful in multidoc templates
    HWND hWnd = GetSafeHwnd();
    HDC hDC = ::GetDC(hWnd);
    wglMakeCurrent(hDC,m_hGLContext);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glClearColor(m_ClearColorRed,m_ClearColorGreen,m_ClearColorBlue,1.0f);

    glPushMatrix();

    // Position / translation / scale
    glTranslated(m_xTranslation,m_yTranslation,m_zTranslation);
    glRotatef(m_xRotation, 1.0, 0.0, 0.0);
    glRotatef(m_yRotation, 0.0, 1.0, 0.0);
    glScalef(m_xScaling,m_yScaling,m_zScaling);

    // Start rendering...
    drawScene();

    glPopMatrix();

    // Double buffer
    SwapBuffers(dc.m_ps.hdc);
}

protected:
    void drawScene();

void CRenderView::OnMouseMove(UINT nFlags, 
                                                            CPoint point) 
{
    if(m_LeftButtonDown)
    {
        m_yRotation -= (float)(m_LeftDownPos.x - point.x)/3.0f;
        m_xRotation -= (float)(m_LeftDownPos.y - point.y)/3.0f;
        m_LeftDownPos = point;
        InvalidateRect(NULL,FALSE);
    }
    CView::OnMouseMove(nFlags, point);
}

1 Ответ

1 голос
/ 09 октября 2011

Могу я спросить, почему вы вращаете цилиндр, пересчитывая его вершины? Просто сгенерируйте модель цилиндра один раз , затем выполните любые последующие преобразования в матрице вида модели. Также я думаю, что вы хотите вращаться вокруг Z, а не Y.

Обновление

Этот «инструмент» выглядит как слегка расширенная версия учебника «MFC OpenGL CView». * Тьфу *

Самая большая проблема, которую я вижу, в том, что функция CRenderView :: OnPaint была написана кем-то, кто не знает, как правильно использовать OpenGL.

void CRenderView::OnPaint() 
{
    // Device context for painting
    CPaintDC dc(this); 

    // Model is stored in Document
    CToolDoc *pDoc = (CToolDoc *)GetDocument();
    ASSERT_VALID(pDoc);

    // Useful in multidoc templates
    HWND hWnd = GetSafeHwnd();
    HDC hDC = ::GetDC(hWnd);
    wglMakeCurrent(hDC,m_hGLContext);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    
    glClearColor(m_ClearColorRed,m_ClearColorGreen,m_ClearColorBlue,1.0f);

glClearColor должен вызываться до glClear, так как он устанавливает значение, которое будет применяться при вызове glClear. Таким образом, он будет работать при вызове glClear следующего кадра или не работать совсем.

    glPushMatrix();

Какая матрица толкается здесь? Для этого не требуется вызов glMatrixMode.

Начиная с некоторой произвольной матрицы. И кстати, где находится набор проекций (позвольте мне угадать, в обработчике OnSize, верно?).

    // Position / translation / scale
    glTranslated(m_xTranslation,m_yTranslation,m_zTranslation);
    glRotatef(m_xRotation, 1.0, 0.0, 0.0);
    glRotatef(m_yRotation, 0.0, 1.0, 0.0);

Вы подтвердили, что хотите вращаться вокруг оси Z. Так почему бы тебе не сделать это здесь? Здесь только вращение вокруг X и Y. Проблема в том, что вы используете углы Эйлера, которые имеют некоторые неприятные свойства и не одобряются людьми, работающими в области 3D-графики. Лучше использовать кватернионы для представления поворотов (просто предложение).

    glScalef(m_xScaling,m_yScaling,m_zScaling);

    // Start rendering...
    drawScene();

    glPopMatrix();

    // Double buffer
    SwapBuffers(dc.m_ps.hdc);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...