为什么我的圆柱体模型无法在 Z 轴上旋转?

发布于 2024-12-09 01:11:26 字数 4065 浏览 0 评论 0原文

我尝试编写以下代码来绘制圆柱体。圆柱体是用 C++ 和 OpenGL 绘制的。学校给了我一个小工具,我可以用我自己的模型的 cpp 文件进行编译,然后可以用鼠标旋转模型。该工具不会影响我的模型的旋转,因为它适用于其他演示模型。但是,由于某种我不明白的原因,我无法在 Z 轴上旋转圆柱体以在其水平视图中查看它。因此,圆柱体只能在以下方向旋转和查看:

在此处输入图像描述

为什么我无法旋转圆柱体查看朝这个方向发展吗?以下图像在 Photoshop 中手动旋转,以说明模型无法旋转到的视图方向:

在此处输入图像描述

我不明白不向该方向旋转的原因是什么,因为其他模型(由其他人编写)显示的演示可以向各个方向自由旋转。

这是我在 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 度来绘制多边形以形成圆柱体。但是这种绘制方式不允许我自由旋转模型,这是怎么回事呢?

编辑:

以下是该工具如何绘制场景的部分代码。不知何故,该工具有大量的类。它的大多数类只是设置工具的 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);
}

I attempted to write the following code to draw a cylinder. The cylinder was drawn in C++ with OpenGL. And I'm given a little tool by the school that I could compile with my own model's cpp file and then able to rotate the model with the mouse. The tool doesn't affect the rotation of my model because it works for the other demo models. However, for some reason which I do not understand, I cannot rotate the cylinder in the Z-axis to see it in its horizontal view. So, the cylinder can only be rotated and seen in these directions:

enter image description here

Why I cannot rotate the cylinder to see it in this direction? The following image was rotated manually in Photoshop to illustrate the direction of view that the model couldn't rotate to:

enter image description here

I don't understand what is the reason for not being to rotate in that direction because the demo shown for other models(written by others) could be rotated freely in all directions.

This is the code that I have written to try in 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();
    }
}

And the overwritten function I have is like this, also in mymodel.cpp:

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

What I have done basically is just to define 2 perpendicular basis unit vectors and then extend them outwards with a magnitude value. And I loop through this 360 degrees to draw the polygons to form the cylinder. But what is wrong that this way of drawing doesn't allow me to rotate the model freely?

Edit:

The following is part of the code of how the tool draws the scene. Somehow, the tool has a huge chunk of classes. Most of its classes merely sets up the GUI of the tool and then the only part that draws it is the one below in 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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

书信已泛黄 2024-12-16 01:11:26

请问,为什么要通过重新计算圆柱体的顶点来旋转圆柱体?只需生成一个圆柱体模型一次,然后对模型视图矩阵执行任何后续转换。另外,我认为您会想要围绕 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);
}

May I ask, why you rotate the cylinder by recalculating its vertices? Just generate a cylinder model once, then perform any following transformations on the modelview matrix. Also I think you'll want to rotate about Z, not Y.

Update

That "tool" seems to be a slightly extended version of the "MFC OpenGL CView" tutorial. *yuck*

The biggest problem I see, that the CRenderView::OnPaint function has been written by someone, who doesn't know how to properly use 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 must be called before glClear, as it sets the value that will be applied upon the glClear call. This way round it will work on the glClear call of the next frame or not at all.

    glPushMatrix();

Which matrix is pushed here? This lacks a call to glMatrixMode.

Starting from some arbitrary matrix. And BTW where is the projection set (let me guess, in the OnSize handler, right?).

    // 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);

You confirmed you want to rotate about the Z axis. So why won't you do it here? There only rotation about X and Y here. Problem is: You're using euler angles here, which have some nasty properties and are frowned upon by 3D graphics people. Better use Quaternions for representing rotations (just a suggestion).

    glScalef(m_xScaling,m_yScaling,m_zScaling);

    // Start rendering...
    drawScene();

    glPopMatrix();

    // Double buffer
    SwapBuffers(dc.m_ps.hdc);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文