使用OpenGL绘制弹簧

已知弹簧的起点和终点坐标值,在OpenGL中绘制该弹簧。本篇介绍的弹簧分两种,分别是无粗细的(使用LineStrip绘制)和有粗细的(使用QuadStrip绘制)。程序是在C#和OpenTK环境下编译的。

 

1. 弹簧的角度

由于弹簧的位置是由起点和终点两个坐标定义的,所以需要考虑弹簧的角度问题。

程序中直接使用的OpenTK下的函数CalculateAngle和CreateFromAxisAngle。关于这两个函数的数学公式推导,参见我的另一篇文章:根据旋转前后的向量值求旋转矩阵

首先绘制沿Z轴方向的弹簧,然后根据弹簧的两端点求出旋转矩阵,最后设定该弹簧的方向和位置。

 

2. 无粗细的弹簧

代码:

/// <summary>
/// 绘制线弹簧
/// </summary>
/// <param name="ptStart">弹簧的起点</param>
/// <param name="ptEnd">弹簧的终点</param>
/// <param name="Radius">弹簧的半径</param>
/// <param name="Coils">弹簧的圈数</param>
/// <param name="Rings">弹簧每圈的段数</param>
void DrawSpring(Vector3d ptStart, Vector3d ptEnd, double Radius = 50, double Coils = 12, double Rings = 50)
{
    double springHeight;
    double ringDelta = 2.0 * Math.PI / Rings;
    double ringHeight;
    double ringAngle;
    double z;
    
    Vector3d ptOldFrame, ptNewFrame;
    Vector3d rotationAxis;
    Matrix4d rotationMatrix;
    double rotationAngle;
    

    ptOldFrame = new Vector3d(0, 0, 1);
    ptNewFrame = ptEnd - ptStart;
    springHeight = Math.Sqrt(ptNewFrame.X * ptNewFrame.X
        + ptNewFrame.Y * ptNewFrame.Y
        + ptNewFrame.Z * ptNewFrame.Z);
    ringHeight = springHeight / Coils / Rings;

    rotationAngle = Vector3d.CalculateAngle(ptOldFrame, ptNewFrame);
    rotationAxis = Vector3d.Cross(ptOldFrame, ptNewFrame);
    rotationMatrix = Matrix4d.CreateFromAxisAngle(rotationAxis, rotationAngle);

    GL.Color3(1.00f, 0.0f, 0.0f);
    GL.PushMatrix();
    GL.Translate(ptStart);
    GL.MultMatrix(ref rotationMatrix);
    GL.Begin(BeginMode.LineStrip);

    z = 0;
    for (int i = 0; i < Coils; i++)
    {
        ringAngle = 0;
        for (int j = 0; j < Rings; j++)
        {
            GL.Vertex3(Math.Cos(ringAngle) * Radius, Math.Sin(ringAngle) * Radius, z);
            ringAngle += ringDelta;
            z += ringHeight;
        }
    }
    
    GL.End();
    GL.PopMatrix();
}

 

 

3. 有粗细的弹簧

代码:

/// <summary>
/// 绘制重弹簧
/// </summary>
/// <param name="ptStart">弹簧的起点</param>
/// <param name="ptEnd">弹簧的终点</param>
/// <param name="Radius">弹簧的半径</param>
/// <param name="Coils">弹簧的圈数</param>
/// <param name="Rings">弹簧每圈的段数</param>
/// <param name="Sides">弹簧每段的侧面数</param>
/// <param name="TubeRadius">弹簧的段半径</param>
void DrawHeavySpring(Vector3d ptStart, Vector3d ptEnd, double Radius = 50, double Coils = 10, int Rings = 60, int Sides = 18, double TubeRadius = 2)
{
    double sideDelta = 2.0 * Math.PI / Sides;
    double ringDelta = 2.0 * Math.PI / Rings;
    double ringHeight;
    double theta = 0;
    double cosTheta = 1.0;
    double sinTheta = 0.0;
    double z;
    double phi, sinPhi, cosPhi;
    double dist;
    double springLength;

    Vector3d ptOldFrame, ptNewFrame;
    Vector3d rotationAxis;
    Matrix4d rotationMatrix;
    double rotationAngle;

    ptOldFrame = new Vector3d(0, 0, 1);
    ptNewFrame = ptEnd - ptStart;
    springLength = Math.Sqrt(ptNewFrame.X * ptNewFrame.X
        + ptNewFrame.Y * ptNewFrame.Y
        + ptNewFrame.Z * ptNewFrame.Z);
    ringHeight = springLength / Coils / Rings;

    rotationAngle = Vector3d.CalculateAngle(ptOldFrame, ptNewFrame);
    rotationAxis = Vector3d.Cross(ptOldFrame, ptNewFrame);
    rotationMatrix = Matrix4d.CreateFromAxisAngle(rotationAxis, rotationAngle);

    GL.Color3(1.00f, 0.0f, 0.0f);
    GL.PushMatrix();
    GL.Translate(ptStart);
    GL.MultMatrix(ref rotationMatrix);

    z = 0;
    for (int i = 0; i < Coils; i++)
    {
        for (int j = 0; j < Rings; j++)
        {
            double theta1 = theta + ringDelta;
            double cosTheta1 = Math.Cos(theta1);
            double sinTheta1 = Math.Sin(theta1);

            GL.Begin(BeginMode.QuadStrip);
            phi = 0;
            for (int k = 0; k <= Sides; k++)
            {
                phi = phi + sideDelta;
                cosPhi = Math.Cos(phi);
                sinPhi = Math.Sin(phi);
                dist = Radius + (TubeRadius * cosPhi);

GL.Vertex3(cosTheta * dist, sinTheta * dist, z + TubeRadius * sinPhi); GL.Vertex3(cosTheta1 * dist, sinTheta1 * dist, z +ringHeight+ TubeRadius * sinPhi); } GL.End(); theta = theta1; cosTheta = cosTheta1; sinTheta = sinTheta1; z += ringHeight; } } GL.PopMatrix(); }

 

posted @ 2013-02-16 17:05  马语者  阅读(2281)  评论(0编辑  收藏  举报