zoukankan      html  css  js  c++  java
  • 使用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(); }
  • 相关阅读:
    数据卷Volume
    使用 Elastic Stack 分析地理空间数据 (二)
    使用 Elastic Stack 分析地理空间数据 (一)
    如何在 Docker 之上使用 Elastic Stack 和 Kafka 可视化公共交通
    Kubernetes网络模型
    举例:Network Policies
    配置Pod的 /etc/hosts
    k8s上安装安装 Ingress Controller &卸载
    logstash安装插件修改使用的gem源
    示例:Ingress通过互联网访问应用
  • 原文地址:https://www.cnblogs.com/xpvincent/p/2913537.html
Copyright © 2011-2022 走看看