WPF:3D正八面体自动旋转

一、坐标系

  • WPF 的 3D 坐标系原点通常位于对象中心,X 轴向右,Y 轴向上,Z 轴朝向观察者(右手定则)。
    正四面体旋转以原点为中心,绕Z 轴自动旋转。

二、正八面体的坐标

  • 正八面体有6个顶点,12条边,8个面。
    取六个顶点为:(0,0,0),(-1,0,0),(0,1,0),(0,-1,0),(0,0,1),(0,0,-1) ,可以验证所有六条棱长均为 2\sqrt{2}2 ,所以这是一个棱长为 2\sqrt{2}2 的正四面体,且四个顶点全是整数。
    这些点的坐标全是整数。它们构成一个正八面体:六个顶点到原点距离都等于 1,任意两个相邻顶点之间的距离都是 2\sqrt{2}2 ,相对顶点之间距离为2。这个多面体有 8 个全等的等边三角形面,因此是正八面体。

三、设计

  • 正八面体有 6 个顶点、8 个等边三角形面。
    利用之前得到的整数顶点坐标,我们可以把它们放大到合适的尺寸

    ( 5, 0, 0), (-5, 0, 0),
    ( 0, 5, 0), ( 0,-5, 0),
    ( 0, 0, 5), ( 0, 0,-5)

  • 8 个面分别由这些顶点中的三个组成(每个面是连接原点相邻轴端点形成的三角形)。
    具体面的顶点索引(从 0 到 5)如下:

    面1: 0,2,4 ( 5,0,0), (0,5,0), (0,0,5) 三角形索引:0,1,2 法线朝外
    面2: 0,4,3 ( 5,0,0), (0,0,5), (0,-5,0) 三角形索引:0,1,2 法线朝外
    面3: 0,3,5 ( 5,0,0), (0,-5,0), (0,0,-5) 三角形索引:0,1,2 法线朝外
    面4: 0,5,2 ( 5,0,0), (0,0,-5), (0,5,0) 三角形索引:0,1,2 法线朝外
    面5: 1,2,4 (-5,0,0), (0,5,0), (0,0,5) 三角形索引:0,2,1 法线朝外
    面6: 1,4,3 (-5,0,0), (0,0,5), (0,-5,0) 三角形索引:0,2,1 法线朝外
    面7: 1,3,5 (-5,0,0), (0,-5,0), (0,0,-5) 三角形索引:0,2,1 法线朝外
    面8: 1,5,2 (-5,0,0), (0,0,-5), (0,5,0) 三角形索引:0,2,1 法线朝外

(索引顺序按逆时针方向,保证法线朝外。也可以调整顺序或启用双面渲染。)

也可以将这些面放在一个 MeshGeometry3D 中,并用一个颜色(或每个面不同颜色)。

为了保持原有的多色风格,继续使用 8 个独立的 GeometryModel3D,每个赋予不同的颜色(如红、橙、黄、绿、青、蓝、紫、粉等)。

四、MainWindow.xaml

复制代码
<Window x:Class="WpfA_Octahedron.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfA_Octahedron"
        mc:Ignorable="d"
        Title="正八面体" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="250"/>
        </Grid.ColumnDefinitions>

        <!-- 右侧控制面板 -->
        <StackPanel Grid.Column="1" Margin="10">
            <!-- 焦距控制 -->
            <TextBlock Text="调节相机焦距" Margin="0,0,0,5"/>
            <Slider x:Name="viewAngle" Width="200" Value="60" Minimum="10" Maximum="150" />
            <TextBox Text="{Binding ElementName=viewAngle, Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                    Width="80" Margin="0,5,0,10" HorizontalAlignment="Left"/>

            <!-- X轴旋转 -->
            <TextBlock Text="X轴旋转" Margin="0,0,0,5"/>
            <Slider x:Name="rotateX" Width="200" Value="220" Minimum="0" Maximum="360" />
            <TextBox Text="{Binding ElementName=rotateX, Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                    Width="80" Margin="0,5,0,10" HorizontalAlignment="Left"/>

            <!-- Y轴旋转 -->
            <TextBlock Text="Y轴旋转" Margin="0,0,0,5"/>
            <Slider x:Name="rotateY" Width="200" Value="40" Minimum="0" Maximum="360" />
            <TextBox Text="{Binding ElementName=rotateY, Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                    Width="80" Margin="0,5,0,10" HorizontalAlignment="Left"/>

            <!-- Z轴旋转 -->
            <TextBlock Text="Z轴旋转" Margin="0,0,0,5"/>
            <Slider x:Name="rotateZ" Width="200" Value="0" Minimum="0" Maximum="360" />
            <TextBox Text="{Binding ElementName=rotateZ, Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                    Width="80" Margin="0,5,0,10" HorizontalAlignment="Left"/>

            <!-- 按钮 -->
            <Button x:Name="btnAutoRotate" Content="启动自动旋转" Width="120" Margin="0,20,0,5" Click="BtnAutoRotate_Click"/>
            <Button x:Name="btnExit" Content="退出程序" Width="120" Click="BtnExit_Click"/>
        </StackPanel>

        <!-- 3D 视口(保持不变) -->
        <Viewport3D Grid.Column="0">
            <Viewport3D.Camera>
                <PerspectiveCamera Position="0,0,50" LookDirection="0,0,-1" 
                                  FieldOfView="{Binding Value, ElementName=viewAngle}" 
                                  UpDirection="0,1,0"/>
            </Viewport3D.Camera>


            <ModelVisual3D>
                <ModelVisual3D.Content>
                    <Model3DGroup>
                        <AmbientLight Color="Gray"/>
                         <DirectionalLight Color="Gray" Direction="-1,-1,-1"/>

                    <!-- 八个三角面,使用正八面体的顶点 -->
                    <GeometryModel3D>
                        <GeometryModel3D.Geometry>
                            <MeshGeometry3D Positions="5,0,0 0,5,0 0,0,5"
                                     TriangleIndices="0,1,2"/>
                        </GeometryModel3D.Geometry>
                        <GeometryModel3D.Material>
                            <DiffuseMaterial Brush="Red"/>
                        </GeometryModel3D.Material>
                    </GeometryModel3D>

                    <GeometryModel3D>
                        <GeometryModel3D.Geometry>
                            <MeshGeometry3D Positions="5,0,0 0,0,5 0,-5,0"
                                     TriangleIndices="0,1,2"/>
                        </GeometryModel3D.Geometry>
                        <GeometryModel3D.Material>
                            <DiffuseMaterial Brush="Orange"/>
                        </GeometryModel3D.Material>
                    </GeometryModel3D>

                    <GeometryModel3D>
                        <GeometryModel3D.Geometry>
                            <MeshGeometry3D Positions="5,0,0 0,-5,0 0,0,-5"
                                     TriangleIndices="0,1,2"/>
                        </GeometryModel3D.Geometry>
                        <GeometryModel3D.Material>
                            <DiffuseMaterial Brush="Yellow"/>
                        </GeometryModel3D.Material>
                    </GeometryModel3D>

                    <GeometryModel3D>
                        <GeometryModel3D.Geometry>
                            <MeshGeometry3D Positions="5,0,0 0,0,-5 0,5,0"
                                     TriangleIndices="0,1,2"/>
                        </GeometryModel3D.Geometry>
                        <GeometryModel3D.Material>
                            <DiffuseMaterial Brush="Green"/>
                        </GeometryModel3D.Material>
                    </GeometryModel3D>

                        <!-- 第5个面(原 Cyan):(-5,0,0) (0,5,0) (0,0,5) -->
                        <GeometryModel3D>
                            <GeometryModel3D.Geometry>
                                <MeshGeometry3D Positions="-5,0,0 0,5,0 0,0,5"
                         TriangleIndices="0,2,1"/>
                                <!-- 改为 0,2,1 -->
                            </GeometryModel3D.Geometry>
                            <GeometryModel3D.Material>
                                <DiffuseMaterial Brush="Cyan"/>
                            </GeometryModel3D.Material>
                        </GeometryModel3D>

                        <!-- 第6个面(原 Blue):(-5,0,0) (0,0,5) (0,-5,0) -->
                        <GeometryModel3D>
                            <GeometryModel3D.Geometry>
                                <MeshGeometry3D Positions="-5,0,0 0,0,5 0,-5,0"
                         TriangleIndices="0,2,1"/>
                                <!-- 改为 0,2,1 -->
                            </GeometryModel3D.Geometry>
                            <GeometryModel3D.Material>
                                <DiffuseMaterial Brush="Blue"/>
                            </GeometryModel3D.Material>
                        </GeometryModel3D>

                        <!-- 第7个面(原 Purple):(-5,0,0) (0,-5,0) (0,0,-5) -->
                        <GeometryModel3D>
                            <GeometryModel3D.Geometry>
                                <MeshGeometry3D Positions="-5,0,0 0,-5,0 0,0,-5"
                         TriangleIndices="0,2,1"/>
                                <!-- 改为 0,2,1 -->
                            </GeometryModel3D.Geometry>
                            <GeometryModel3D.Material>
                                <DiffuseMaterial Brush="Purple"/>
                            </GeometryModel3D.Material>
                        </GeometryModel3D>

                        <!-- 第8个面(原 Pink):(-5,0,0) (0,0,-5) (0,5,0) -->
                        <GeometryModel3D>
                            <GeometryModel3D.Geometry>
                                <MeshGeometry3D Positions="-5,0,0 0,0,-5 0,5,0"
                         TriangleIndices="0,2,1"/>
                                <!-- 改为 0,2,1 -->
                            </GeometryModel3D.Geometry>
                            <GeometryModel3D.Material>
                                <DiffuseMaterial Brush="Pink"/>
                            </GeometryModel3D.Material>
                        </GeometryModel3D>

                    </Model3DGroup>
            </ModelVisual3D.Content>

            <!-- 旋转变换保持不变,仍作用于整个模型 -->
            <ModelVisual3D.Transform>
                <Transform3DGroup>
                    <RotateTransform3D>
                        <RotateTransform3D.Rotation>
                            <AxisAngleRotation3D Axis="1,0,0" Angle="{Binding Value, ElementName=rotateX}"/>
                        </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                    <RotateTransform3D>
                        <RotateTransform3D.Rotation>
                            <AxisAngleRotation3D Axis="0,1,0" Angle="{Binding Value, ElementName=rotateY}"/>
                        </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                    <RotateTransform3D>
                        <RotateTransform3D.Rotation>
                            <AxisAngleRotation3D Axis="0,0,1" Angle="{Binding Value, ElementName=rotateZ}"/>
                        </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                </Transform3DGroup>
            </ModelVisual3D.Transform>
        </ModelVisual3D>
            
        </Viewport3D>
    </Grid>
</Window>

五、MainWindow.xaml.cs

复制代码
using System;
using System.Windows;
using System.Windows.Threading;

namespace WpfA_Octahedron
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
   
        private DispatcherTimer? _rotationTimer;  // 可为 null
        private const double RotationStep = 0.5;   // 每帧旋转角度增量

        public MainWindow()
        {
            InitializeComponent();

            // 初始化定时器
            _rotationTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(30) // 约 33 帧/秒
            };
            _rotationTimer.Tick += RotationTimer_Tick;
        }

        // 自动旋转按钮点击事件
        private void BtnAutoRotate_Click(object sender, RoutedEventArgs e)
        {
            if (_rotationTimer == null)
            {
                // 创建定时器,每 50ms 触发一次(约 20fps)
                _rotationTimer = new DispatcherTimer
                {
                    Interval = TimeSpan.FromMilliseconds(50)
                };
                _rotationTimer.Tick += RotationTimer_Tick;
                _rotationTimer.Start();
                btnAutoRotate.Content = "停止自动旋转";
            }
            else
            {
                _rotationTimer.Stop();
                _rotationTimer.Tick -= RotationTimer_Tick;
                _rotationTimer = null;
                btnAutoRotate.Content = "启动自动旋转";
            }

           
        }

        // 定时器 Tick:累加 Z 轴角度
        // 注意这里的 sender 参数类型为 object?,与 EventHandler 委托匹配
        private void RotationTimer_Tick(object sender, EventArgs e)
        {
            // 三个角度每次增加 1 度(可调整速度)
            rotateX.Value = (rotateX.Value + 1) % 360;
            rotateY.Value = (rotateY.Value + 1) % 360;
            rotateZ.Value = (rotateZ.Value + 1) % 360;
        }

        // 退出按钮点击事件
        private void BtnExit_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }
    }
}

六、源码下载

https://download.csdn.net/download/dalong10/93198552

相关推荐
迁移科技15 小时前
周转箱拆垛码垛自动化实战:3D视觉实现 ±2mm 毫米级稳定作业
3d·自动化·视觉检测
a11177618 小时前
汽车3D配置器 THreeJS 开源项目
前端·3d·html·汽车
数字新视界19 小时前
3D数字化孪生管理解决方案
物联网·3d·数字孪生·3d可视化
宇擎智脑科技1 天前
img2threejs 架构深度解析:AI 如何高效地从图片“雕刻“3D 模型
人工智能·3d·agent
柒木森1 天前
MMGS:基于多视角排序的最优传输聚合实现 10 倍压缩的 3DGS
3d
丙氨酸長鏈1 天前
WPF 引用 ASP.NET Core 的 AOT 版本
后端·asp.net·wpf
Xin_ye100861 天前
第六章:破局——WPF内存泄漏解决方案
c#·wpf
FuckPatience1 天前
WPF Button Content 的StringFormat
java·前端·wpf