C# WPF + Helix Toolkit 实战:用两种方式打造“六面异色立方体”

🎨 引言

在 3D 图形开发中,给立方体的每个面设置不同颜色是一个非常经典且实用的小项目。它不仅帮助我们理解 3D 网格构造、材质绑定和光照渲染 的基本原理,还为我们后续学习更复杂的模型操作打下基础。

在这篇博客中,我们将使用 Helix Toolkit(WPF SharpDX 版本),通过 两种方法 来实现一个“六面异色立方体”,并详细分析它们的优缺点与适用场景。


效果演示

在这里插入图片描述

🧱 方法一:自动解析网格 —— CreateColoredBox

🔧 核心思想

  • 使用 MeshBuilder.AddBox(...) 创建一个标准立方体。
  • 遍历所有三角形索引,每6个三角形组成一个完整的面。
  • 计算每个面的中心点,判断其属于哪个方向(前/后/左/右/上/下)。
  • 动态为每个面创建子网格,并分配不同的材质颜色。

✅ 示例代码

private Model3DGroup CreateColoredBox(
    double width, double height, double depth,
    Brush frontBrush, Brush backBrush,
    Brush leftBrush, Brush rightBrush,
    Brush topBrush, Brush bottomBrush)
{
    var modelGroup = new Model3DGroup();
    var meshBuilder = new MeshBuilder();
    meshBuilder.AddBox(new Point3D(0, 0, 0), width, height, depth);
    var mesh = meshBuilder.ToMesh();

    for (int i = 0; i < mesh.TriangleIndices.Count; i += 6)
    {
        // 计算当前面的中心点
        var center = new Point3D();
        for (int j = 0; j < 6; j++)
        {
            var idx = mesh.TriangleIndices[i + j];
            center.X += mesh.Positions[idx].X;
            center.Y += mesh.Positions[idx].Y;
            center.Z += mesh.Positions[idx].Z;
        }
        center.X /= 6;
        center.Y /= 6;
        center.Z /= 6;

        // 判断面方向
        Brush brush;
        if (Math.Abs(center.Z - depth / 2) < 0.001) brush = frontBrush;
        else if (Math.Abs(center.Z + depth / 2) < 0.001) brush = backBrush;
        else if (Math.Abs(center.X - width / 2) < 0.001) brush = rightBrush;
        else if (Math.Abs(center.X + width / 2) < 0.001) brush = leftBrush;
        else if (Math.Abs(center.Y - height / 2) < 0.001) brush = topBrush;
        else if (Math.Abs(center.Y + height / 2) < 0.001) brush = bottomBrush;
        else brush = Brushes.Gray;

        // 创建子网格
        var subMesh = new MeshGeometry3D();
        for (int j = 0; j < 6; j++)
        {
            var idx = mesh.TriangleIndices[i + j];
            subMesh.Positions.Add(mesh.Positions[idx]);
            subMesh.TextureCoordinates.Add(mesh.TextureCoordinates[idx]);
            subMesh.TriangleIndices.Add(j);
        }

        // 重新计算法线
        subMesh.Normals = ComputeNormals(subMesh);

        var material = new DiffuseMaterial(brush);
        modelGroup.Children.Add(new GeometryModel3D(subMesh, material)
        {
            BackMaterial = material
        });
    }

    return modelGroup;
}

private Vector3DCollection ComputeNormals(MeshGeometry3D mesh)
{
    var normals = new Vector3DCollection();
    for (int i = 0; i < mesh.TriangleIndices.Count; i += 3)
    {
        var p0 = mesh.Positions[mesh.TriangleIndices[i]];
        var p1 = mesh.Positions[mesh.TriangleIndices[i + 1]];
        var p2 = mesh.Positions[mesh.TriangleIndices[i + 2]];
        var normal = Vector3D.CrossProduct(p1 - p0, p2 - p0);
        normal.Normalize();
        for (int j = 0; j < 3; j++)
            normals.Add(normal);
    }
    return normals;
}

📌 优点

  • 可拓展性强,适用于从 OBJ 模型中提取不同区域进行着色。
  • 不依赖顶点顺序,适合自动化处理。

⚠️ 注意事项

  • 需手动计算法线以确保光照正确。
  • 需要添加 BackMaterial 以保证背面可见。

🧩 方法二:手动定义顶点 —— CreateColoredBoxNew

🔧 核心思想

  • 手动定义立方体的 8 个顶点坐标。
  • 为每个面指定四个顶点(顺时针排列),构建四边形。
  • 使用 AddQuad(...) 添加每个面并绑定材质。

✅ 示例代码

private Model3DGroup CreateColoredBoxNew(
    double width, double height, double depth,
    Brush frontBrush, Brush backBrush,
    Brush leftBrush, Brush rightBrush,
    Brush topBrush, Brush bottomBrush)
{
    var modelGroup = new Model3DGroup();
    var points = GetCubeVertices(width, height, depth);

    AddFace(modelGroup, new[] { points[0], points[1], points[2], points[3] }, frontBrush); // 前面
    AddFace(modelGroup, new[] { points[5], points[4], points[7], points[6] }, backBrush);  // 后面
    AddFace(modelGroup, new[] { points[4], points[0], points[3], points[7] }, leftBrush);  // 左面
    AddFace(modelGroup, new[] { points[1], points[5], points[6], points[2] }, rightBrush); // 右面
    AddFace(modelGroup, new[] { points[3], points[2], points[6], points[7] }, topBrush);   // 上面
    AddFace(modelGroup, new[] { points[4], points[5], points[1], points[0] }, bottomBrush);// 下面

    return modelGroup;
}

private Point3D[] GetCubeVertices(double width, double height, double depth)
{
    double x = width / 2, y = height / 2, z = depth / 2;
    return new Point3D[]
    {
        new Point3D(-x, -y, z),  // 0: 左前上
        new Point3D(x, -y, z),   // 1: 右前上
        new Point3D(x, y, z),    // 2: 右前下
        new Point3D(-x, y, z),   // 3: 左前下
        new Point3D(-x, -y, -z), // 4: 左后上
        new Point3D(x, -y, -z),  // 5: 右后上
        new Point3D(x, y, -z),   // 6: 右后下
        new Point3D(-x, y, -z)   // 7: 左后下
    };
}

private void AddFace(Model3DGroup group, Point3D[] points, Brush brush)
{
    var meshBuilder = new MeshBuilder();
    meshBuilder.AddQuad(points[0], points[1], points[2], points[3]); // 四边形
    var geometry = meshBuilder.ToMesh();
    var material = new DiffuseMaterial(brush);
    group.Children.Add(new GeometryModel3D(geometry, material)
    {
        BackMaterial = material
    });
}

📌 优点

  • 结构清晰,适合初学者理解 3D 网格构造。
  • 易于控制每个面的方向和材质。
  • 适合教学或快速原型设计。

⚠️ 注意事项

  • 顶点顺序必须是顺时针排列,否则可能被剔除。
  • 面数较多时管理复杂,不适合大规模模型。

📊 对比总结

特性CreateColoredBoxCreateColoredBoxNew
实现难度中等(需理解三角面片)简单(手动定义顶点)
可读性较低
可扩展性强(可应用于任意模型)弱(仅适用于规则几何体)
是否需要手动计算法线否(由 AddQuad 自动生成)
是否推荐初学者使用

🧪 实际效果预览

运行程序后,你将看到一个立方体:

颜色
前面Red
后面Green
左面Blue
右面Yellow
上面Purple
下面Orange

无论你旋转视角还是缩放视图,六个面都始终可见,颜色准确无误。


🧰 XAML 配置建议

确保你的 MainWindow.xaml 包含以下内容:

<Window x:Class="Load3DModelWithMaterialUseHelix.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:hc="http://helix-toolkit.org/wpf"
        Title="六面异色立方体" Height="600" Width="800">
    <Grid>
        <hc:HelixViewport3D x:Name="helixViewport" ZoomExtentsWhenLoaded="True">
            <hc:DefaultLights />
        </hc:HelixViewport3D>
    </Grid>
</Window>

🎯 进阶方向

如果你对这个项目感兴趣,可以继续尝试以下功能:

  • 【封装类】将这两种方法封装成 ColoredBoxVisual3D 类供复用
  • 【交互增强】点击某个面高亮或弹出信息
  • 【动态更新】运行时修改某个面的颜色
  • 【纹理贴图】为每个面加载图片资源
  • 【多面体扩展】构造金字塔、五棱柱等复杂几何体

📌 GitHub 示例源码
CSDN下载

📬 订阅更新:关注我,获取更多 C#/WPF/3D 开发实战文章


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌霜残雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值