WPF:3D正四面体旋转改错

一、坐标系

  • WPF 的 3D 坐标系原点通常位于对象中心,X 轴向右,Y 轴向上,Z 轴朝向观察者(右手定则)。

    正四面体旋转以原点为中心,绕Z 轴自动旋转。

  • 视点坐标:

    位置(Position)0,0,50、观察方向(LookDirection)0,0,-1 和向上方向(UpDirection)0,1,0

二、问题

问题:3D正四面体自动旋转,有时候会只看到两个分离的面,有时候什么都看不到,全白色。

三、解析

  • 这个问题是 WPF 3D 的背面剔除(Back-face culling) 机制导致的。
    在 WPF 中,默认只会渲染法线朝向相机的三角形面。
    而三角形面的朝向由顶点索引顺序决定(右手定则,逆时针为正面)。如果三角形面的顶点顺序反了,会导致它们的法线指向了立方体内部(很多是指向原点)。
    法线朝向相机(即指向外边的)能够正确显示,指向内部的不会显示。三角形不渲染,所以看到的是纯白色背景。
    因为 Viewport3D 默认背景为白色(或网格背景为白色),当所有三角形都被剔除、没有任何像素被绘制时,就直接透出白色背景了。

四、计算

  • 顶点:(0,0,0), (10,10,0), (10,0,10) , (0,10,10)

    面1: (0,0,0), (10,10,0), (10,0,10) 索引 0,1,2

    面2: (0,0,0), (10,10,0), (0,10,10) 索引 0,1,2

    面3: (0,0,0), (10,0,10), (0,10,10) 索引 0,1,2

    面4: (10,0,10), (0,10,10), (10,10,0) 索引 0,1,2

    另外三个顶点是 (10,10,0), (10,0,10), (0,10,10)。这个四面体不是以原点为中心,而是以原点为一个顶点。那么背面剔除的问题可能表现在某些角度出现空白?需要检查每个面的法线方向是否朝外。由于所有面都包含原点,且其他顶点都在正象限,法线方向可能需要计算。

  • 通常为了清晰显示立体感,我们只渲染正面,但需要正确顺序。

    对于以原点为顶点的四面体,我们可以选择从外部看每个面的逆时针顺序。

    更简单的方法是将所有三角形索引改为按顺时针从外部看?

    但标准是逆时针为正面。我们可以计算每个面的法线,如果指向内部,则交换最后两个索引。

  • 面1: A,B,C:

    A=(0,0,0), B=(10,10,0), C=(10,0,10)。

    向量AB=(10,10,0), AC=(10,0,10)。法线为: 叉积 AB × AC = (10,10,0) × (10,0,10) = (100, -100, -100),指向 (1,-1,-1) 方向,这大致指向外部吗?

    这个四面体位于第一象限,A在原点,外部应该是指向远离原点的方向?但这个四面体不在原点中心,其外部方向对于每个面是不同的。

    我们通常希望模型围绕原点旋转时,外部法线指向外。但该四面体所有顶点都在x>=0,y>=0,z>=0区域,其重心在 (5,5,5) 附近。对于面A,B,C,外部应该是远离重心方向。

    重心G=( (0+10+10+0)/4, (0+10+0+10)/4, (0+0+10+10)/4 ) = (5,5,5)。

    面ABC的中心是 ( (0+10+10)/3, (0+10+0)/3, (0+0+10)/3 ) ≈ (6.67, 3.33, 3.33)。

    从重心到面中心的方向向量是 (1.67, -1.67, -1.67),即大致方向 (1,-1,-1)。

    而我们的法线 (1,-1,-1) 正好指向外部,所以该顺序 (A,B,C) 是正确的。所以面1的顺序 0,1,2 是正确的。

  • 面2: A,B,D。

    A=(0,0,0), B=(10,10,0), D=(0,10,10)。

    向量AB=(10,10,0), AD=(0,10,10)。

    叉积 AB×AD = (10 * 10-0 * 10, 0 * 0-10 * 10, 10 *1 0-10 * 0) = (100, -100, 100) 即 (1,-1,1)。

    面2中心 ( (0+10+0)/3, (0+10+10)/3, (0+0+10)/3 ) = (3.33, 6.67, 3.33)。

    重心到面中心向量: (5-3.33, 5-6.67, 5-3.33) = (1.67, -1.67, 1.67) 即 (1,-1,1)。

    法线 (1,-1,1) 也是外部,所以顺序 0,1,2 也是正确的。

  • 面3: A,C,D。

    A=(0,0,0), C=(10,0,10), D=(0,10,10)。

    向量AC=(10,0,10), AD=(0,10,10)。

    叉积 AC×AD = (0 * 10-10 * 10, 10 * 0-10 * 10, 10 * 10-0 * 0) = (-100, -100, 100) 即 (-1,-1,1)。

    面3中心 ( (0+10+0)/3, (0+0+10)/3, (0+10+10)/3 ) = (3.33, 3.33, 6.67)。

    重心到面中心向量:(5-3.33, 5-3.33, 5-6.67) = (1.67, 1.67, -1.67) 即 (1,1,-1)。

    我们的法线是 (-1,-1,1),正好相反,是向内。所以顺序 0,1,2 是反的,应该改为 0,2,1 才使得法线向外。

  • 面4: B,C,D。

    B=(10,10,0), C=(10,0,10), D=(0,10,10)。

    向量BC=(0,-10,10), BD=(-10,0,10)。

    叉积 BC×BD = ((-10) * 10 - 10 * 0, 10 * (-10) - 0 * 10, 0 * 0 - (-10) * (-10)) = (-100, -100, -100) 即 (-1,-1,-1)。

    面4中心 ( (10+10+0)/3, (10+0+10)/3, (0+10+10)/3 ) = (6.67, 6.67, 6.67)。

    重心到面中心向量:(5-6.67, 5-6.67, 5-6.67) = (-1.67, -1.67, -1.67) 即 (-1,-1,-1)。

    法线 (-1,-1,-1) 是外部,所以顺序 0,1,2 正确。

  • 因此,只有第三个面(A,C,D)需要改为 0,2,1,而其他三个面保持 0,1,2。

五、问题判断

  • WPF 3D 默认只渲染法线朝向相机的三角形(逆时针顺序为正面)。程序的四个面都使用了 TriangleIndices="0,1,2",但经过计算,第三个面(A,C,D)的法线指向内部,而不是朝外。因此:
    • 当相机从某个方向看时,如果所有面都背对相机,就什么都看不见(全白色);
    • 当相机转到特定角度,只有个别面的法线指向相机,所以只能看到一两个面。

六、改正

第三个面(A,C,D)需要改为 0,2,1,而其他三个面保持 0,1,2。

七、补充

  • 绕 X 轴旋转 160°(接近 180°)相当于把原本在 Y 轴正方向的东西翻到了后面。
    红色原本在视角的正前方(原始状态下只有它可见),但转 160° 后它正好翻到了背面。
    绿色和黄色原本藏在背面,现在随着旋转被翻到了正面。
    WPF 3D 默认只渲染法线朝向相机的三角形来看,红色不渲染,所以看见了藏在背面的绿色和黄色。
相关推荐
可爱系程序猿9 小时前
Unity 材质预览才弹 d3dcompiler_47.dll?先分清编辑器 SDK、着色器缓存和玩家包
程序人生·3d·unity·电脑·材质
Zldaisy3d15 小时前
从英特尔Connection苏州大会揭示算力狂飙下的散热范式革命,洞悉增材制造潜力重塑液冷散热版图
3d·制造
samble7 天前
从零搭建灌装监控系统(四):深色主题与样式系统,ResourceDictionary 统一管理
c#·wpf·mvvm·样式·工业控制
_Jonas7 天前
.net framework开发环境正式环境配置文件的切换
.net·wpf
Zldaisy3d7 天前
中南大学 | 热稳定纳米析出相助力增材制造Al-Fe-Cr-Sc-Zr合金400℃长期热暴露后室温强度保持
3d·制造
陆康永7 天前
3d swipe 拖动 -改为linear css
3d·swiper
Zldaisy3d8 天前
增材制造陶瓷的强化策略:机制与工艺-结构-性能关系的多尺度综述
3d·制造
在下胡三汉8 天前
用 glTF/glb 加载自定义 3D 模型
3d·gltf
dalong109 天前
WPF:Modbus 状态监控
wpf·modbus
He BianGu9 天前
【WPF-VisionMaster】机器视觉通用平台V5.0版本发行说明
opencv·c#·wpf·halcon·机器视觉·visionmaster