C# 三维变换WPF

C# 三维变换WPF,c#,wpf,3d,C#,Wpf,3d,我在3d WPF中画了两个球体,它有点像点3D0,0,0和点3d-1.0,1.0,2.0,半径为0.10 现在我想画一个连接这些球体的圆柱体,唯一的结果是半径0.02。我想知道如何计算这个圆柱体的三维点、高度、方向等 我试图找到中点BTW球面点,将圆柱放在这两个球体的中间,但不是在正确的方向上。我想把圆柱体旋转成直角。我用Vector3D.angleweenv1,v2来找到它给我的角度NaN。我把我正在使用的代码放在下面 Vector3D v1 = new Vector3D(0, 0,

我在3d WPF中画了两个球体,它有点像点3D0,0,0和点3d-1.0,1.0,2.0,半径为0.10

现在我想画一个连接这些球体的圆柱体,唯一的结果是半径0.02。我想知道如何计算这个圆柱体的三维点、高度、方向等

我试图找到中点BTW球面点,将圆柱放在这两个球体的中间,但不是在正确的方向上。我想把圆柱体旋转成直角。我用Vector3D.angleweenv1,v2来找到它给我的角度NaN。我把我正在使用的代码放在下面

    Vector3D v1 = new Vector3D(0, 0, 0);
    Vector3D v2 = new Vector3D(1.0, -1.0, 2.0);

    Vector3D center = v1+ v2/2;
    Vector3D axis = Vector3D.CrossProduct(v1, v2);
    double angle = Vector3D.AngleBetween(v1, v2);
    AxisAngleRotation3D axisAngle = new AxisAngleRotation3D(axis, angle);
    RotateTransform3D myRotateTransform = new RotateTransform3D(axisAngle, center);
    center.X = myRotateTransform.CenterX;
    center.Y = myRotateTransform.CenterY;
    center.Z = myRotateTransform.CenterZ;
[编辑]

首先,非常感谢您的回复。我对这段代码有一些问题,它与您的示例配合得很好。但我的观点是 它并没有画出两个圆点在正确方向的圆柱体,也没有画到终点,它只是连接到第二个点,还有一件事, 如果Z轴的中点是中点。Z=0,则它甚至不会绘制圆柱体

我只是想知道,是不是因为我画圆圈的方式。请看一看

public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
{
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleModel(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleModel(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

  private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {                
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D( p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }
我想画气缸btw p1到p2,p1到p3,p1到p4 p2至p3,p2至p4

请让我知道,如果你需要任何更多的澄清,我必须得到这个了。
谢谢你花了这么多时间。

我不知道这对你是否有用,但是你对我最近发布的一些类似代码发表了评论,请求帮助-所以我想我应该将这些代码转换成两个对象,由一个在3D空间旋转的圆柱体连接-Init方法需要两点,在点处创建10x10个立方体,然后将其与圆柱体连接

我想这大概就是你想要达到的,虽然我承认我的例子有点做作,但你只能在两个点上改变Z轴!!!,但希望你能从中有所收获

很抱歉,代码有点乱,但我已经从我的许多类中编译了它,使其成为一个易于剪切和粘贴的块

不管怎样,希望这有帮助

这是XAML。。。这只是设置视口和光源

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>

    <Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="300">
        <Viewport3D.Camera>
            <PerspectiveCamera 
                  LookDirection="0,0,-20"
                  UpDirection="0,1,0"
                  Position="0,0,100" 
                  />
        </Viewport3D.Camera>
        <ModelVisual3D>
            <ModelVisual3D.Content>
                <Model3DGroup x:Name="group3d">

                    <SpotLight Position="30,30,30" x:Name="mySpotLight" Color="Yellow"  InnerConeAngle="100" OuterConeAngle="1000" Range="100" />
                </Model3DGroup>
            </ModelVisual3D.Content>

        </ModelVisual3D>
    </Viewport3D>

</StackPanel>
。。。这是背后的代码

 using System;
 using System.Collections.Generic;
 using System.Timers;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media.Media3D;
 using System.Windows.Threading;

namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init(new Point3D(0, 0, 30), new Point3D(0,0,-30));
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;



    public void Init(Point3D firstPoint, Point3D secondPoint)
    {
        var midPoint = firstPoint - secondPoint;
        var size = new Size3D(10,10,10);
        _models.Add(GetCube(GetSurfaceMaterial(Colors.Green), firstPoint, size));
        _models.Add(GetCube(GetSurfaceMaterial(Colors.Green), secondPoint, size));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;

        var rotateTransform3D = new RotateTransform3D {CenterX = 0, CenterZ = 0};
        var axisAngleRotation3D = new AxisAngleRotation3D {Axis = new Vector3D(1, 1, 1), Angle = _angle};
        rotateTransform3D.Rotation = axisAngleRotation3D;
        var myTransform3DGroup = new Transform3DGroup();
        myTransform3DGroup.Children.Add(rotateTransform3D);
        _models.ForEach(x => x.Transform = myTransform3DGroup);
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D {Content = cylinder};
        return model;
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }



}
}
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init(new Point3D(0, 0, 30), new Point3D(0, 0, -30));
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;



    public void Init(Point3D firstPoint, Point3D secondPoint)
    {
        var midPoint = firstPoint - secondPoint;

        _models.Add(CreateSphere(firstPoint, 10, 10, 10, Colors.AliceBlue ));
        _models.Add(CreateSphere(secondPoint, 10, 10, 10, Colors.AliceBlue));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;

        var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        var axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
        rotateTransform3D.Rotation = axisAngleRotation3D;
        var myTransform3DGroup = new Transform3DGroup();
        myTransform3DGroup.Children.Add(rotateTransform3D);
        _models.ForEach(x => x.Transform = myTransform3DGroup);
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D { Content = cylinder };
        return model;
    }



    public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
    {
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(
            new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(
            mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }

}
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init();
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;
    private Transform3DGroup _transform3DGroup;
    private AxisAngleRotation3D _axisAngleRotation3D;
    private Transform3DGroup _altTransform;

    public void Init()
    {
        _models.Add(CreateSphere(new Point3D(0,0,0), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(CreateSphere(new Point3D(0,0,2), 0.1, 10, 10, Colors.AliceBlue));
        //notice that the following two spheres are created in the same place
        _models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0,0,0), 0.02, 2));
        //notice that the following to cylinders are also created in the same place
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0, 0, 0), 0.02, -2));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Green), new Point3D(0, 0, 0), 0.02, -2));

        _transform3DGroup = new Transform3DGroup();


        _models.ForEach(x => x.Transform = _transform3DGroup);

        //heres my alt transform that i'm just using for the duplicate sphere and cylinder
        _altTransform = new Transform3DGroup();
        _models[3].Transform = _altTransform;
        _models[6].Transform = _altTransform;

        var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        _axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
        rotateTransform3D.Rotation = _axisAngleRotation3D;

        //i'm adding the animation rotation to both groups so that all my models spin
        _transform3DGroup.Children.Add(rotateTransform3D);
        _altTransform.Children.Add(rotateTransform3D);

        //but my alt transform gets an extra transformation
        var altRotate = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        var altAxis = new AxisAngleRotation3D { Axis = new Vector3D(0, 1, 1), Angle = 90 };
        altRotate.Rotation = altAxis;
        _altTransform.Children.Add(altRotate);

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;
        _axisAngleRotation3D.Angle = _angle;
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D { Content = cylinder };
        return model;
    }



    public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
    {
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(
            new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(
            mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }



}
}

我已经将您的球体代码与我的示例集成在一起,效果很好-圆柱体连接两个球体

这是密码

干杯,安迪

和以前一样的视口

<Window x:Class="wpfspin.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>

    <Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="300">
        <Viewport3D.Camera>
            <PerspectiveCamera 
              LookDirection="0,0,-20"
              UpDirection="0,1,0"
              Position="0,0,100" 
              />
        </Viewport3D.Camera>
        <ModelVisual3D>
            <ModelVisual3D.Content>
                <Model3DGroup x:Name="group3d">

                    <SpotLight Position="30,30,30" x:Name="mySpotLight" Color="Yellow"  InnerConeAngle="100" OuterConeAngle="1000" Range="100" />
                </Model3DGroup>
            </ModelVisual3D.Content>

        </ModelVisual3D>
    </Viewport3D>

</StackPanel>
。。。这是背后的代码

 using System;
 using System.Collections.Generic;
 using System.Timers;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media.Media3D;
 using System.Windows.Threading;

namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init(new Point3D(0, 0, 30), new Point3D(0,0,-30));
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;



    public void Init(Point3D firstPoint, Point3D secondPoint)
    {
        var midPoint = firstPoint - secondPoint;
        var size = new Size3D(10,10,10);
        _models.Add(GetCube(GetSurfaceMaterial(Colors.Green), firstPoint, size));
        _models.Add(GetCube(GetSurfaceMaterial(Colors.Green), secondPoint, size));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;

        var rotateTransform3D = new RotateTransform3D {CenterX = 0, CenterZ = 0};
        var axisAngleRotation3D = new AxisAngleRotation3D {Axis = new Vector3D(1, 1, 1), Angle = _angle};
        rotateTransform3D.Rotation = axisAngleRotation3D;
        var myTransform3DGroup = new Transform3DGroup();
        myTransform3DGroup.Children.Add(rotateTransform3D);
        _models.ForEach(x => x.Transform = myTransform3DGroup);
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D {Content = cylinder};
        return model;
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }



}
}
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init(new Point3D(0, 0, 30), new Point3D(0, 0, -30));
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;



    public void Init(Point3D firstPoint, Point3D secondPoint)
    {
        var midPoint = firstPoint - secondPoint;

        _models.Add(CreateSphere(firstPoint, 10, 10, 10, Colors.AliceBlue ));
        _models.Add(CreateSphere(secondPoint, 10, 10, 10, Colors.AliceBlue));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;

        var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        var axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
        rotateTransform3D.Rotation = axisAngleRotation3D;
        var myTransform3DGroup = new Transform3DGroup();
        myTransform3DGroup.Children.Add(rotateTransform3D);
        _models.ForEach(x => x.Transform = myTransform3DGroup);
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D { Content = cylinder };
        return model;
    }



    public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
    {
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(
            new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(
            mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }

}
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init();
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;
    private Transform3DGroup _transform3DGroup;
    private AxisAngleRotation3D _axisAngleRotation3D;
    private Transform3DGroup _altTransform;

    public void Init()
    {
        _models.Add(CreateSphere(new Point3D(0,0,0), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(CreateSphere(new Point3D(0,0,2), 0.1, 10, 10, Colors.AliceBlue));
        //notice that the following two spheres are created in the same place
        _models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0,0,0), 0.02, 2));
        //notice that the following to cylinders are also created in the same place
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0, 0, 0), 0.02, -2));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Green), new Point3D(0, 0, 0), 0.02, -2));

        _transform3DGroup = new Transform3DGroup();


        _models.ForEach(x => x.Transform = _transform3DGroup);

        //heres my alt transform that i'm just using for the duplicate sphere and cylinder
        _altTransform = new Transform3DGroup();
        _models[3].Transform = _altTransform;
        _models[6].Transform = _altTransform;

        var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        _axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
        rotateTransform3D.Rotation = _axisAngleRotation3D;

        //i'm adding the animation rotation to both groups so that all my models spin
        _transform3DGroup.Children.Add(rotateTransform3D);
        _altTransform.Children.Add(rotateTransform3D);

        //but my alt transform gets an extra transformation
        var altRotate = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        var altAxis = new AxisAngleRotation3D { Axis = new Vector3D(0, 1, 1), Angle = 90 };
        altRotate.Rotation = altAxis;
        _altTransform.Children.Add(altRotate);

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;
        _axisAngleRotation3D.Angle = _angle;
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D { Content = cylinder };
        return model;
    }



    public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
    {
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(
            new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(
            mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }



}
}

}这里还有一些代码-我想我已经为您找到了解决方案

同样,这是一个拼凑而成的例子,你必须加以改进

请注意,转换代码发生了巨大的变化,我自己才刚刚开始掌握WPF 3D,我意识到我做了很多错事。我每次都在重新创建Transform3DGroup,而不是仅仅更改已经应用的变换的角度

看一下代码并注意altTransform组-我正在做的是向这个alt组添加一个额外的transformation。然后我在圆柱体和球体上使用了altTransform,否则它将与其他圆柱体和球体处于相同的位置。我把这个圆筒标为绿色,这样你就可以看到它是哪一个了

我的建议是,在同一轴上创建所有球体和圆柱体,然后将它们变换到所需的位置

我还将球体和圆柱体的尺寸更改为您在前面的评论中要求的尺寸

看看代码,看看你是怎么想的

干杯

安迪

这是背后的代码

 using System;
 using System.Collections.Generic;
 using System.Timers;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media.Media3D;
 using System.Windows.Threading;

namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init(new Point3D(0, 0, 30), new Point3D(0,0,-30));
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;



    public void Init(Point3D firstPoint, Point3D secondPoint)
    {
        var midPoint = firstPoint - secondPoint;
        var size = new Size3D(10,10,10);
        _models.Add(GetCube(GetSurfaceMaterial(Colors.Green), firstPoint, size));
        _models.Add(GetCube(GetSurfaceMaterial(Colors.Green), secondPoint, size));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;

        var rotateTransform3D = new RotateTransform3D {CenterX = 0, CenterZ = 0};
        var axisAngleRotation3D = new AxisAngleRotation3D {Axis = new Vector3D(1, 1, 1), Angle = _angle};
        rotateTransform3D.Rotation = axisAngleRotation3D;
        var myTransform3DGroup = new Transform3DGroup();
        myTransform3DGroup.Children.Add(rotateTransform3D);
        _models.ForEach(x => x.Transform = myTransform3DGroup);
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D {Content = cylinder};
        return model;
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }



}
}
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init(new Point3D(0, 0, 30), new Point3D(0, 0, -30));
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;



    public void Init(Point3D firstPoint, Point3D secondPoint)
    {
        var midPoint = firstPoint - secondPoint;

        _models.Add(CreateSphere(firstPoint, 10, 10, 10, Colors.AliceBlue ));
        _models.Add(CreateSphere(secondPoint, 10, 10, 10, Colors.AliceBlue));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;

        var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        var axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
        rotateTransform3D.Rotation = axisAngleRotation3D;
        var myTransform3DGroup = new Transform3DGroup();
        myTransform3DGroup.Children.Add(rotateTransform3D);
        _models.ForEach(x => x.Transform = myTransform3DGroup);
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D { Content = cylinder };
        return model;
    }



    public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
    {
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(
            new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(
            mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }

}
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Init();
    }

    private Timer _timer;
    private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
    private double _angle;
    private Transform3DGroup _transform3DGroup;
    private AxisAngleRotation3D _axisAngleRotation3D;
    private Transform3DGroup _altTransform;

    public void Init()
    {
        _models.Add(CreateSphere(new Point3D(0,0,0), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(CreateSphere(new Point3D(0,0,2), 0.1, 10, 10, Colors.AliceBlue));
        //notice that the following two spheres are created in the same place
        _models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0,0,0), 0.02, 2));
        //notice that the following to cylinders are also created in the same place
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0, 0, 0), 0.02, -2));
        _models.Add(GetCylinder(GetSurfaceMaterial(Colors.Green), new Point3D(0, 0, 0), 0.02, -2));

        _transform3DGroup = new Transform3DGroup();


        _models.ForEach(x => x.Transform = _transform3DGroup);

        //heres my alt transform that i'm just using for the duplicate sphere and cylinder
        _altTransform = new Transform3DGroup();
        _models[3].Transform = _altTransform;
        _models[6].Transform = _altTransform;

        var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        _axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
        rotateTransform3D.Rotation = _axisAngleRotation3D;

        //i'm adding the animation rotation to both groups so that all my models spin
        _transform3DGroup.Children.Add(rotateTransform3D);
        _altTransform.Children.Add(rotateTransform3D);

        //but my alt transform gets an extra transformation
        var altRotate = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
        var altAxis = new AxisAngleRotation3D { Axis = new Vector3D(0, 1, 1), Angle = 90 };
        altRotate.Rotation = altAxis;
        _altTransform.Children.Add(altRotate);

        _models.ForEach(x => mainViewport.Children.Add(x));
        _timer = new Timer(10);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }



    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
    }

    public MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));

        var cube = new Model3DGroup();
        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        var model = new ModelVisual3D();
        model.Content = cube;
        return model;
    }

    private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
    {
        return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
    }

    private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
        var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
        var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
        return Vector3D.CrossProduct(v0, v1);
    }

    void Transform(double adjustBy)
    {
        _angle += adjustBy;
        _axisAngleRotation3D.Angle = _angle;
    }


    public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
    {
        var cylinder = new Model3DGroup();
        var nearCircle = new CircleAssitor();
        var farCircle = new CircleAssitor();

        var twoPi = Math.PI * 2;
        var firstPass = true;

        double x;
        double y;

        var increment = 0.1d;
        for (double i = 0; i < twoPi + increment; i = i + increment)
        {
            x = (radius * Math.Cos(i));
            y = (-radius * Math.Sin(i));

            farCircle.CurrentTriangle.P0 = midPoint;
            farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
            farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);

            nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);

            if (!firstPass)
            {
                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));

                cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
                cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
            }
            else
            {
                farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
                nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
                firstPass = false;
            }

            farCircle.LastPoint = farCircle.CurrentTriangle.P2;
            nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
        }

        var model = new ModelVisual3D { Content = cylinder };
        return model;
    }



    public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
    {
        Model3DGroup spear = new Model3DGroup();

        if (u < 2 || v < 2)
            return null;
        Point3D[,] pts = new Point3D[u, v];
        for (int i = 0; i < u; i++)
        {
            for (int j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius,
                i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        Point3D[] p = new Point3D[4];
        for (int i = 0; i < u - 1; i++)
        {
            for (int j = 0; j < v - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
                spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
            }
        }
        ModelVisual3D model = new ModelVisual3D();
        model.Content = spear;
        return model;
    }

    private Point3D GetPosition(double radius, double theta, double phi)
    {
        Point3D pt = new Point3D();
        double snt = Math.Sin(theta * Math.PI / 180);
        double cnt = Math.Cos(theta * Math.PI / 180);
        double snp = Math.Sin(phi * Math.PI / 180);
        double cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
    {
        MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(p0); mesh.Positions.Add(p1); mesh.Positions.Add(p2); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);

        Vector3D normal = VectorHelper.CalcNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        Material material = new DiffuseMaterial(
            new SolidColorBrush(color));
        GeometryModel3D model = new GeometryModel3D(
            mesh, material);
        Model3DGroup group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

    private class VectorHelper
    {
        public static Vector3D CalcNormal(Point3D p0, Point3D p1, Point3D p2)
        {
            Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            return Vector3D.CrossProduct(v0, v1);
        }
    }


}

public class CircleAssitor
{

    public CircleAssitor()
    {
        CurrentTriangle = new Triangle();
    }

    public Point3D FirstPoint { get; set; }
    public Point3D LastPoint { get; set; }
    public Triangle CurrentTriangle { get; set; }

}

public class Triangle
{


    public Point3D P0 { get; set; }
    public Point3D P1 { get; set; }
    public Point3D P2 { get; set; }

    public Triangle Clone(double z, bool switchP1andP2)
    {
        var newTriangle = new Triangle();
        newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));

        var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
        var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));

        if (!switchP1andP2)
        {
            newTriangle.P1 = point1;
            newTriangle.P2 = point2;
        }
        else
        {
            newTriangle.P1 = point2;
            newTriangle.P2 = point1;
        }
        return newTriangle;
    }

    private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
    {
        var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
        newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
        return newPoint;
    }



}
}

抱歉耽搁了,我上周末出城了。这是一个很好的解决方案。请尝试使用这些点,如果可能的话,我的示例点是:p1=点3D0,0,0 p2=点3D-1.0,1.0,2.0 p3=点3D-1.0,1.0,2.0 p4=点3D1.0,-1.0,2.0想要绘制气缸btw p1到p2,p1到p3,p1到p4 p2到p3,p2到p4。对于我的点,它不是画圆柱体,沿着正确的方向画两个圆点,也不是直到终点,它只是连接到第二个点,还有一件事,如果Z轴的中点是中点。Z=0,它甚至没有画圆柱。ps-圆的半径是0.10,圆柱是0.02。在你的评论中p2和p3是一样的吗?你能重新检查一下这些分数吗?不幸的是,它们就是这样的。。一旦我们画出来,它看起来像一个圆,但实际上它们是两个,它们只是相互重叠。很抱歉打扰你,我仍然找到了解决这个问题的方法_models.addGetCylinder GetSurface材质颜色.Red,secondPoint,2,middpoint.Z;你使用中点有什么特别的原因吗。。。有没有一种方法可以通过指定起点和终点来绘制圆柱体。。。