在旧的 opengl 中绘制具有定义中心和轴的圆柱体

Draw cylinder with defined center and axis in old opengl

我正在尝试在我给定的位置和轴上使用 freeglut 的 glutSolidCylinder 绘制一个圆柱体。

我想要的是这样的函数:

void DrawCylinder(float radius,float height,Vector3 center,Vector3 axis)

这样

DrawCylinder(0.5,0.5, Vector3(0.5,0.5,0), Vector3(0,1,0)) 

将绘制一个圆心为(0.5,0.5,0)且轴沿y轴的圆柱体。

我需要这个功能是通用的,也就是说,无论我给它什么位置和轴,我都找到了非常具体的 this 相关问题。

这是我卡住的地方:

#include <iostream>
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cmath>
#define PI 3.141592653589f
#define PIdiv180 (PI/180.0f)
class Vector3
{
private:
    float x,y,z;
public:
    Vector3(float coordx=0,float coordy=0,float coordz=0) 
            : x(coordx),y(coordy),z(coordz){}
    Vector3(const Vector3 &v) : x(v.x),y(v.y),z(v.z){}
    float X() const { return x; }
    float Y() const { return y; }
    float Z() const { return z; }
    float length() const { return sqrt(x*x+y*y+z*z); }
    
    float operator*(const Vector3 &v) const 
    { 
        return x*v.x+y*v.y+z*v.z; 
    }
    
    static float anglebetweeninradian(const Vector3 &v1,const Vector3 &v2)
    {
        return acos((v1*v2)/(v1.length()*v2.length()));
    }


    Vector3 operator-(const Vector3 &other) const
    {
        return Vector3(x-other.x,y-other.y,z-other.z);
    }


    Vector3 &operator =(const Vector3& other)
    {
        x=other.x;
        y=other.y;
        z=other.z;
        return *this;
    }


    Vector3 &operator -=(const Vector3& other)
    {
        x-=other.x;
        y-=other.y;
        z-=other.z;
        return *this;
    }

    Vector3 Rotate(Vector3 v,const float &theta1)  const
    {
        float a = 0, b = 0, c = 0;

        float theta=(float)(theta1*PIdiv180);

        a=(cos(theta)+(v.x*v.x)*(1-cos(theta)))*x;
        a+=(v.x*v.y*(1-cos(theta))-v.z*sin(theta))*y;
        a+=(v.x*v.z*(1-cos(theta))+v.y*sin(theta))*z;

        b=(v.y*v.x*(1-cos(theta))+v.z*sin(theta))*x;
        b+=(cos(theta)+v.y*v.y*(1-cos(theta)))*y;
        b+=(v.y*v.z*(1-cos(theta))-v.x*sin(theta))*z;

        c=(v.z*v.x*(1-cos(theta))-v.y*sin(theta))*x;
        c+=(v.z*v.y*(1-cos(theta))+v.x*sin(theta))*y;
        c+=(cos(theta)+v.z*v.z*(1-cos(theta)))*z;
        return Vector3(a, b, c);
    }
};
using namespace std;
void DrawCylinder(float radius,float height,Vector3 center,Vector3 axis)
{    
    Vector3 pos=Vector3(0,0,height/2);
    float theta=Vector3::anglebetweeninradian(axis,Vector3(0,0,1))/PIdiv180;
    pos=pos.Rotate(Vector3(axis.Y(),axis.X(),0),theta);
    glPushMatrix();
    glRotatef(theta,axis.Y(),axis.X(),0);
    center-=pos;
    glTranslatef(center.X(),center.Y(),center.Z());
    glutSolidCylinder(radius,height,50,50);
    glPopMatrix();
}

void idle(void)
{
    glutPostRedisplay();
}
void display()
{      
    glClear(GL_DEPTH_BUFFER_BIT);
    glColor3f(1,0,0);
    glLoadIdentity();
    DrawCylinder(0.5,0.5,Vector3(0,0,0),Vector3(0,-1,0));
    glutSwapBuffers();
}

void init()
{
    glClearColor(1, 1, 1, 1);

    glEnable(GL_LIGHTING);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHT0);
    const GLfloat light_ambient[] = { 1.0f, 1.0f, 1.0f, 0.0f };
    const GLfloat light_diffuse[] = { 1.0f, 1,1, 1.0f };
    const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    const GLfloat light_position[] = { 0.0f, 1, 0.0f, 1.0f };
    const GLfloat light_shininess[] = { 50.0f };
    const GLfloat light_emissive[] = { 1, -1, 1, 0 };

    glEnable(GL_COLOR_MATERIAL);

    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_EMISSION, light_emissive);

    glMaterialfv(GL_FRONT, GL_SPECULAR, light_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, light_shininess);
}
int main(int argc,char *argv[])
{
    glutInit(&argc,argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(300,200);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutCreateWindow("FoosBall");
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    init();
    glutMainLoop();
    return 0;
}

编辑

我在这里做的是围绕指定轴和 z 轴的叉积旋转圆柱体,角度等于两个向量之间的角度,旋转后我将圆柱体从位置平移旋转到指定中心后的中心。

不幸的是,这没有用,当我尝试沿 y 轴在 (0,0,0) 处绘制它时,它被定位在 (0,0,0) 上方(可能是 (0,0.25,0 )), 旋转部分按预期工作,只是平移部分不起作用。

那我该怎么办?

备注

现在我必须使用旧的 opengl。

我的问题解决了,这是函数:

void DrawCylinder(float radius,float height,Vector3 center,Vector3 axis)
{    
    Vector3 pos=Vector3(0,0,height/2);
    float theta=Vector3::anglebetweeninradian(axis,Vector3(0,0,1))/PIdiv180;
    pos=pos.Rotate(Vector3(axis.Y(),axis.X(),0),theta);
    center-=pos;
    glPushMatrix();
    glTranslatef(center.X(),center.Y(),center.Z());
    glRotatef(theta,axis.Y(),axis.X(),0);
    glutSolidCylinder(radius,height,50,50);
    glPopMatrix();
}

我只需要将 glTranslatef 放在 glRotatef 之前。