如何在OpenGL中围绕局部轴旋转对象?

时间:2009-11-04 01:27:46

标签: opengl

我正在进行一个正在进行的项目,我希望对齐链条的链接,使其遵循贝塞尔曲线的轮廓。我目前正在执行以下步骤。

  1. 绘制曲线。
  2. 使用显示列表创建链的一个链接。
  3. 使用FOR循环重复调用计算曲线上两点之间角度的函数,返回角度以及链接应绕其旋转的轴。
  4. 以角度“a”旋转并转换到新位置,将链接置于新位置。
  5. 编辑:我还应该说,两个半圆环的中心必须位于贝塞尔曲线上。 另外我知道我用来绘制圆环的方法我很乏味,稍后我将使用TRIANGLE_FAN或QUAD_STRIP以更有效的方式绘制圆环。

    虽然乍一看这个逻辑看起来会正确地渲染链条,但最终的结果并不是我想象的那样。这是链条看起来像什么的图片。

    gold_chain

    我读过你必须在旋转之前将对象转换为原点?我是否只需要调用glTranslate(0,0,0)然后按照上面的步骤4进行操作?

    我已经包含了迄今为止我所做的相关代码,如果有任何建议让我的代码正常工作,我将不胜感激。

    /* this function calculates the angle between two vectors oldPoint and new point contain the x,y,z coordinates of the two points,axisOfRot is used to return the x,y,z coordinates of the rotation axis*/
    double getAxisAngle(pointType oldPoint[],
    pointType newPoint[],pointType axisOfRot[]){
    
    float tmpPoint[3];   
    
    float normA = 0.0,normB = 0.0,AB = 0.0,angle=0.0;
    int i;
    
    axisOfRot->x= oldPoint->y * newPoint->z - oldPoint->z * newPoint->y;
    axisOfRot->y= oldPoint->z * newPoint->x - oldPoint->x * newPoint->z;
    axisOfRot->z= oldPoint->x * newPoint->y - oldPoint->y * newPoint->x; 
    
    
    normA=sqrt(oldPoint->x * oldPoint->x + oldPoint->y * oldPoint->y + oldPoint->z * 
    oldPoint->z);
    normB=sqrt(newPoint->x * newPoint->x + newPoint->y * newPoint->y + newPoint->z *    
    newPoint->z);
    
    tmpPoint[0] =  oldPoint->x * newPoint->x;
    tmpPoint[1] =  oldPoint->y * newPoint->y;
    tmpPoint[2] =  oldPoint->z * newPoint->z;   
    
    for(i=0;i<=2;i++)
     AB+=tmpPoint[i];  
    
    AB /= (normA * normB);  
    
    
        return angle = (180/PI)*acos(AB);  
     }
    
     /* this function calculates and returns the next point on the curve give the 4 initial points for the curve, t is the tension of the curve */
        void bezierInterpolation(float t,pointType cPoints[],
        pointType newPoint[]){
    
    newPoint->x = pow(1 - t, 3) * cPoints[0].x +3 * pow(1 - t , 2) * t * cPoints[1].x + 3 
    * pow(1 - t, 1) * pow(t, 2) * cPoints[2].x + pow(t, 3) * cPoints[3].x;
    
    newPoint->y = pow(1 - t, 3) * cPoints[0].y +3 * pow(1 - t , 2) * t * cPoints[1].y + 3 
    * pow(1 - t, 1) * pow(t, 2) * cPoints[2].y + pow(t, 3) * cPoints[3].y;
    
    newPoint->z = pow(1 - t, 3) * cPoints[0].z +3 * pow(1 - t , 2) * t * cPoints[1].z + 3 
    * pow(1 - t, 1) * pow(t, 2) * cPoints[2].z + pow(t, 3) * cPoints[3].z;
    
    }
    
    /* the two lists below are used to create a single link in a chain, I realize that creating a half torus using cylinders is a bad idea, I will use GL_STRIP or TRIANGLE_FAN once I get the alignment right 
    */
    torusList=glGenLists(1);   
    
    glNewList(torusList,GL_COMPILE);
    for (i=0; i<=180; i++)
    {
      degInRad = i*DEG2RAD;
      glPushMatrix();
      glTranslatef(cos(degInRad)*radius,sin(degInRad)*radius,0);
      glRotated(90,1,0,0);
      gluCylinder(quadric,Diameter/2,Diameter/2,Height/5,10,10);
      glPopMatrix();      
    }
    
     glEndList();
    
        /*! create a list for the link , 2 half torus and 2 columns */
    
     linkList = glGenLists(1);
    
     glNewList(linkList, GL_COMPILE); 
     glPushMatrix();
     glCallList(torusList); 
     glRotatef(90,1,0,0);
     glTranslatef(radius,0,0);
     gluCylinder(quadric, Diameter/2, Diameter/2, Height,10,10); 
     glTranslatef(-(radius*2),0,0);
     gluCylinder(quadric, Diameter/2, Diameter/2, Height,10,10); 
     glTranslatef(radius,0, Height);
     glRotatef(90,1,0,0);
     glCallList(torusList); 
     glPopMatrix();
     glEndList();
    

    最后,这里是用于在链中创建三个链接的代码

    t=0.031; 
    bezierInterpolation(t,cPoints,newPoint);  
    a=getAxisAngle(oldPoint,newPoint,axisOfRot);
     glTranslatef(newPoint->x,newPoint->y,newPoint->z); 
       glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);     
        glCallList(DLid);
       glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
     glTranslatef(-newPoint->x,-newPoint->y,-newPoint->z);  
    
    oldPoint[0]=newPoint[0];
    bezierInterpolation(t+=GAP,cPoints,newPoint);  
    a=getAxisAngle(oldPoint,newPoint,axisOfRot);
     glTranslatef(newPoint->x,newPoint->y,newPoint->z); 
      glRotatef(90,0,1,0);
       glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);     
        glCallList(DLid);
       glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
      glRotatef(90,0,1,0);  
     glTranslatef(-newPoint->x,-newPoint->y,-newPoint->z);  
    
     oldPoint[0]=newPoint[0];
     bezierInterpolation(t+=GAP,cPoints,newPoint);    
      a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
       glTranslatef(newPoint->x,newPoint->y,newPoint->z);       
        glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
         glCallList(DLid);
        glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
       glTranslatef(-newPoint->x,-newPoint->y,newPoint->z); 
    

2 个答案:

答案 0 :(得分:3)

需要注意的一点是,glTranslate功能建立在以前的翻译之上。 I.E.一个glTranslatef(0.0,0.0,0.0);不会去原点,它只会移动“笔”无处可去。幸运的是,“笔”从原点开始。如果你转换为1.0,1.0,1.0然后尝试glTranslatef(0.0,0.0,0.0);你仍然会在1.0,1.0,1.0;

画画

另外,你似乎已经掌握了openGL后增加matricies的事实。为此,您在绘制后正确“撤消”矩阵运算。我只看到一个你可能会离开这里的地方,这就是这句话:

glRotatef(90,0,1,0);
   glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);     
    glCallList(DLid);
   glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
  glRotatef(90,0,1,0);  

这里你正确地撤消了第二次旋转,但是第一次旋转似乎围绕y轴旋转得更多。最后一个glRotatef需要读取glRotatef(-90,0,1,0);如果你想撤消那个轮换。

答案 1 :(得分:1)

我查看了你的代码并假设代码执行bezierInterp和轴角度是正确的。基于代码,我有以下建议:

  1. 您创建单个链接的方式看起来非常昂贵。正如您使用gluCylinder 180次。这将为小链接生成许多顶点。您可以创建一个圆环并应用比例,使其看起来像一个链接!

  2. 无论何时进行矩阵运算,最好先设置模式。这在推送和弹出之前很重要。在您的显示列表中,您可以在不设置任何模式的情况下进行推送和弹出,也不会在调用者中设置。这不是好的做法,会导致很多错误/问题。您可以从通话清单中删除推送和弹出,并仅保留几何图形。

  3. 您听说过建议在轮换前作为翻译*轮换进行原点翻译的建议! =轮换*翻译。因此,编写渲染循环的方式是:

    // Set matrix mode
    glMatrixMode(GL_MODELVIEW);
    
    for(number of links) {
    
    glLoadIdentity();     // makes model view matrix identity - default location`
    glTranslatef(x,y,z);  // Translate to a point on beizer curve
    glRotatef(..);        // Rotate link
    glCallList(link);     // can be simple torus, only geometry centered at origin
    }
    
  4. 以上代码呈现在指定位置重复的链接。阅读OpenGL红皮书的chapter 3 - 示例3.6(行星系统)示例,了解如何正确地将每个链接放置在不同的位置。