第02章:环境搭建与第一个程序
上一章我们从宏观上认识了 OpenCSG.NET。本章开始动手:安装开发环境、把 OpenCSG.NET 引入项目、看懂官方仓库的结构,并亲手写出、运行、导出你的第一个三维零件。
2.1 准备开发环境
2.1.1 安装 .NET SDK
OpenCSG.NET 的核心库目标框架是 netstandard2.0,这意味着几乎任何现代 .NET 都能引用它。但要编译示例、测试、或使用官方解决方案,建议安装较新的 SDK:
- 最低要求:.NET 8 SDK(示例项目为
net8.0,测试项目双目标net8.0;net10.0,net8.0 这一腿需要 8.x 运行时)。 - 推荐:.NET 9 SDK 或更高——官方解决方案文件采用了新的
.slnx(XML 格式),只有 .NET 9+ 的dotnetCLI 才能直接构建它。
仓库钉了 SDK 版本:根目录的
global.json把 SDK 钉在10.0.4xx(rollForward: latestFeature)。克隆官方仓库后,机器上只有 8.x SDK 会在dotnet build时直接报 “A compatible .NET SDK was not found”。你自己的项目不受影响(没有global.json就跟随本机 SDK)。
验证安装:
dotnet --version
dotnet --list-sdks
只要能看到 8.x 或更高版本即可。Windows、macOS、Linux 三平台通用。
2.1.2 选择编辑器
任何支持 C# 的编辑器都可以:
- Visual Studio 2022(Windows,功能最全)
- Visual Studio Code + C# Dev Kit 扩展(跨平台,轻量)
- JetBrains Rider(跨平台,体验优秀)
2.2 三种引入 OpenCSG.NET 的方式
2.2.1 方式一:NuGet 包(最推荐)
绝大多数使用者应该直接引用 NuGet 上发布的 OpenCSG.NET 包。新建一个控制台项目并添加包:
dotnet new console -n MyCsgApp
cd MyCsgApp
dotnet add package OpenCSG.NET
这会在 MyCsgApp.csproj 中加入一行 PackageReference:
<ItemGroup>
<PackageReference Include="OpenCSG.NET" Version="*" />
</ItemGroup>
提示:
OpenCSG.NET核心库只对System.Text.Json有一个间接依赖,NuGet 会自动帮你还原,无需手动添加。
2.2.2 方式二:项目引用(源码集成)
如果你想跟踪最新源码、调试内核,或做二次开发,可以把 OpenCSG.NET 仓库克隆到本地,然后在你的项目里引用它的 csproj:
<ItemGroup>
<ProjectReference Include="..\OpenCSG.NET\src\OpenCSG.NET\OpenCSG.NET.csproj" />
</ItemGroup>
官方的三个示例/测试项目都是用这种方式引用核心库的。
2.2.3 方式三:直接拷贝源码
因为核心库零第三方依赖(除序列化用到的 System.Text.Json),源码文件也不多,你甚至可以把 src/OpenCSG.NET/*.cs 直接拷进你的工程。这在受限环境(如某些 Unity 场景)里很实用,但一般不推荐,因为难以跟踪上游更新。
2.3 看懂官方仓库结构
克隆官方仓库后,你会看到如下结构。理解它有助于你在需要时快速定位源码、示例和测试。
OpenCSG.NET/
├── OpenCSG.NET.slnx # 解决方案(新版 XML 格式,需 .NET 9+)
├── global.json # SDK 版本钉(10.0.4xx,rollForward latestFeature)
├── README.md # 项目说明(英文 + 中文)
├── LICENSE # MIT 许可证
├── OpenJsCad_LICENSE.txt # 上游 csg.js 的许可证(血统致谢)
├── .github/workflows/
│ ├── ci.yml # 双平台 CI:全量构建 + 双 TFM 测试 + 覆盖率门禁
│ ├── nightly.yml # 夜间长测(模糊用例)与性能回归门禁
│ └── nuget-publish.yml # 打 tag 时自动发布到 NuGet(Trusted Publishing/OIDC)
├── src/OpenCSG.NET/ # ★ 核心库(本教程主角,26 个 .cs 文件)
│ ├── Vector.cs # Vector3D/Vector2D/Matrix4x4/BoundingBox 等数学类型
│ ├── Vertex.cs / Plane.cs / Polygon.cs # 顶点/平面/凸多边形
│ ├── Solid.cs / Solids.cs / Tree.cs # ★ 实体、形体工厂、迭代式 BSP
│ ├── Formats.cs # STL 导出的经典扩展方法入口(见第 8 章)
│ ├── CsgNode.cs / CsgEvaluator.cs / CsgSerialization.cs / Profiles.cs # 声明式层
│ ├── CsgMesh.cs / StlWriter.cs # 网格导出管线(Z-up,见第 12 章)
│ ├── CsgHelpers.cs / HalfPlaneCut.cs # 工程辅助函数库(见第 12 章)
│ ├── Tessellation.cs # 弦高容差自适应细分(见第 12 章)
│ ├── PrimitiveConvention.cs # 图元口径参数化(见第 12 章)
│ └── View*.cs # 三视图投影子系统(7 个文件,见第 16 章)
├── samples/
│ ├── Runner.Examples/ # 基础用法示例(形体/变换/布尔/杠铃/管道/Wiki 图标)
│ └── Runner.CPurlin/ # 进阶实战:冷弯 C 型钢檩条(CpurlinModel + CLI)
├── tests/ # 四个测试工程(NUnit + FsCheck),见第 15 章
│ ├── OpenCSG.NET.Tests/ # 主测试套件(单元/契约/黄金/缺陷回归),双 TFM
│ ├── OpenCSG.NET.SystemTests/ # 系统/属性/性能测试,引用 CPurlin 样例
│ ├── OpenCSG.NET.TestKit/ # 测试基础设施(生成器、oracle、桥接器)
│ └── OpenCSG.NET.ApiCompat/ # netstandard2.0 消费面编译金丝雀
├── tools/ # 覆盖率门禁脚本、跨运行时校验器、数据生成器
└── perf/OpenCSG.NET.PerfTest/ # BenchmarkDotNet 性能基准
核心库目前有 26 个 .cs 文件,本教程会把它们逐一讲透。其中 Solid.cs、Solids.cs、Tree.cs 是内核三剑客;CsgNode.cs/CsgEvaluator.cs/CsgSerialization.cs/Profiles.cs 组成声明式层;CsgMesh.cs/StlWriter.cs/Tessellation.cs/CsgHelpers.cs 是网格导出与工程辅助层(第 12 章);View*.cs 七个文件组成三视图投影子系统(第 16 章)。
2.4 构建与测试官方仓库
如果你克隆了源码,可以先跑通官方的构建与测试,确认环境无误。
使用 .NET 9+/10 SDK(直接构建整个解决方案):
dotnet build OpenCSG.NET.slnx
dotnet test tests/OpenCSG.NET.Tests/
只有 .NET 8 SDK(单独构建核心库与测试):
dotnet build src/OpenCSG.NET/OpenCSG.NET.csproj -c Release
dotnet test tests/OpenCSG.NET.Tests/ -f net8.0
之所以要区分,是因为 .slnx 是 .NET 9 引入的新解决方案格式,且仓库 global.json 把 SDK 钉在 10.0.4xx;而核心库本身是 netstandard2.0,用 .NET 8 SDK 也能单独编译。测试项目双目标 net8.0;net10.0——只有 8.x SDK 时需用 -f net8.0 显式限定目标框架(第 15 章详解测试体系)。
运行官方示例:
dotnet run --project samples/Runner.Examples
dotnet run --project samples/Runner.CPurlin
Runner.Examples 会在工作目录生成 cube.stl、wiki.stl、CsgExamples.stl 等文件;Runner.CPurlin 生成 CPurlin-text.stl 与 CPurlin-bin.stl。两个示例都默认不打开查看器(CI/无头环境不弹窗),需要查看时显式设置环境变量:
OPENCSG_OPEN_VIEWER=1 dotnet run --project samples/Runner.CPurlin # Linux/macOS/Git Bash
# Windows CMD: set OPENCSG_OPEN_VIEWER=1 && dotnet run --project samples/Runner.CPurlin
2.5 你的第一个程序:一个带通孔的法兰盘
现在从零写一个完整程序。目标是做一个”法兰盘”雏形:一个扁圆柱盘体,中间挖一个大通孔,四周挖四个小螺栓孔。
新建控制台项目并添加包(见 2.2.1),然后把 Program.cs 替换为:
using Csg;
using static Csg.Solids;
// 参数(改这些数字即可生成不同规格的法兰)
double plateRadius = 30; // 盘体半径
double plateHeight = 6; // 盘体厚度
double boreRadius = 10; // 中心通孔半径
double boltRadius = 3; // 螺栓孔半径
double boltCircle = 22; // 螺栓孔分布圆半径
// 1) 盘体:一个扁圆柱。注意 Cylinder 默认沿 Y 轴,这里用 RotateX(90) 把它立起来沿 Z 轴
var plate = Cylinder(r: plateRadius, h: plateHeight, center: true).RotateX(90);
// 2) 中心通孔:一个略高于盘体的圆柱,保证完全穿透
var bore = Cylinder(r: boreRadius, h: plateHeight + 2, center: true).RotateX(90);
// 3) 盘体挖去中心孔
var flange = plate.Subtract(bore);
// 4) 四个螺栓孔:把一个小圆柱绕中心旋转到 4 个方位
for (int i = 0; i < 4; i++)
{
double angleDeg = 90 * i;
double rad = angleDeg * System.Math.PI / 180.0;
double x = boltCircle * System.Math.Cos(rad);
double y = boltCircle * System.Math.Sin(rad);
var hole = Cylinder(r: boltRadius, h: plateHeight + 2, center: true)
.RotateX(90) // 立起来沿 Z
.Translate(x: x, y: y); // 平移到分布圆上
flange = flange.Subtract(hole);
}
// 5) 导出为 ASCII STL
using (var writer = new StreamWriter("flange.stl"))
{
flange.WriteStl("flange", writer);
}
System.Console.WriteLine($"完成,共 {flange.Polygons.Count} 个多边形,已写入 flange.stl");
运行:
dotnet run
你会在项目目录里得到 flange.stl,控制台也会打印出结果实体的多边形数量。用 STL 查看器打开,就能看到一个中心带大孔、四周均布 4 个螺栓孔的法兰盘。
2.5.1 这个程序教会我们什么
尽管很短,这个程序已经涵盖了 OpenCSG.NET 命令式 API 的四大要素:
- 参数化——所有尺寸都是变量,改数字就换规格,这正是”代码即模型”的价值。
- 形体默认沿 Y 轴——
Cylinder沿 Y 轴生成,我们用.RotateX(90)把它转到沿 Z 轴。这是新手最常见的困惑,第 5、7 章会深入。 - 不可变对象 + 链式调用——每个返回
Solid的方法都返回新对象,绝不修改原对象。所以我们能安全地复用同一个”孔模板”再平移到不同位置。 - 布尔运算做减法——
Subtract把孔从盘体里”挖掉”。为保证完全穿透,孔的高度总是比盘体略大(plateHeight + 2),这是 CSG 打孔的经典技巧,避免共面导致的数值问题(第 6 章详解)。
2.6 常见环境问题排查
| 现象 | 原因 | 解决 |
|---|---|---|
dotnet build OpenCSG.NET.slnx 报无法识别 .slnx |
SDK 版本过低 | 升级到 .NET 9+ SDK,或改为单独构建 src/.../OpenCSG.NET.csproj |
找不到 Csg 命名空间 |
未添加包或未 using Csg; |
执行 dotnet add package OpenCSG.NET,并加上 using Csg; |
Cube(...) 报未定义 |
缺少静态引入 | 加上 using static Csg.Solids; |
| 生成的 STL 打不开 / 面片穿插 | 孔与实体恰好共面 | 让挖孔实体比目标略高/略大,避免精确共面(第 6 章) |
| 运行示例时报无法启动查看器 | 无 GUI 的服务器环境 | 忽略即可,STL 文件已经成功生成 |
2.7 本章小结
- 安装 .NET 8 SDK(构建核心库/测试/示例的最低要求),如需构建
.slnx解决方案则需 .NET 9+。 - 引入 OpenCSG.NET 有三种方式:NuGet 包(推荐)、项目引用(二次开发)、拷贝源码(受限环境)。使用时记得同时
using Csg;和using static Csg.Solids;。 - 官方仓库分为
src(核心库 26 个文件)、samples(示例)、tests(4 个测试工程)、tools(门禁/校验工具)与perf(基准测试)等目录;克隆后注意global.json的 SDK 钉版。 - 我们写出了第一个参数化程序——一个带通孔与螺栓孔的法兰盘,实践了”参数化、Y 轴默认朝向、不可变链式、布尔挖孔”四个关键点。
下一章我们暂时放下 API,深入理解 CSG 与 BSP 树的核心原理——只有理解了内核如何工作,你才能写出稳健、高效、可预测的建模代码。