本项目实现了一个基于节点的材质编辑器系统,与 Photon 渲染引擎深度集成,为 Minecraft 模组提供可视化的 PBR 材质创建能力。系统采用模块化设计,从节点图构建到实时渲染形成完整的工作流。
设计理念:
- 节点作为数据流图的基本单元,每个节点封装特定的材质计算逻辑
- 采用类型安全的 Socket 系统,支持 FLOAT、VEC2、VEC3、VEC4、SAMPLER2D 等 GLSL 类型
- 通过 NodeConnection 建立节点间的数据依赖关系
节点分类:
- Input Nodes: 提供材质的原始数据源(纹理采样、颜色、数值、UV 坐标)
- Math Nodes: 执行数学运算(加法、乘法、插值)
- Utility Nodes: 特殊处理(法线贴图解码)
- Output Node: 材质输出节点,定义 PBR 材质的最终属性(Base Color、Metallic、Roughness、Normal、Emissive、Alpha)
类型系统:
- EnhancedSocketType 定义了强类型的数据流
- 连接验证确保类型兼容性,防止无效的节点连接
- 支持自动类型转换(如 VEC3 到 VEC4 的扩展)
执行流程:
- 拓扑排序:分析节点依赖关系,确定正确的执行顺序
- 循环检测:识别并拒绝包含循环依赖的节点图
- 延迟求值:仅计算连接到 Material Output 的节点,避免不必要的计算
- 上下文传递:通过 NodeEvaluationContext 在节点间传递中间结果
关键特性:
- 支持多输出节点(如 Texture Sample 同时输出 Color、RGB、Alpha)
- 处理未连接的输入(使用默认值)
- 错误恢复机制,单个节点失败不会导致整个图崩溃
生成策略:
- 将节点图转换为 GLSL 着色器代码
- 为每个节点生成唯一的变量名,避免命名冲突
- 追踪变量依赖,确保声明顺序正确
GLSL 发射器 (GLSLEmitter):
- 为每种节点类型实现专门的 GLSL 代码生成逻辑
- 纹理采样节点生成
texture()调用 - 数学节点生成对应的 GLSL 运算符或函数
- 法线贴图节点生成切线空间到世界空间的转换代码
着色器模板 (ShaderTemplate):
- 提供 Vertex Shader 和 Fragment Shader 的基础框架
- 包含 PBR 工具函数(Fresnel、GGX、Smith Geometry)
- 定义标准的 uniform 和 varying 变量
集成方式:
- 利用 Minecraft 原生的 ShaderInstance API
- 着色器文件存储在
assets/[modid]/shaders/core/和program/目录 - 支持 JSON 格式的着色器程序定义
编译流程:
- 将生成的 GLSL 代码写入临时文件
- 创建 JSON 着色器程序描述文件
- 通过 Photon 的 ShaderManager 加载和编译
- 返回可用的 ShaderInstance 对象
着色器缓存:
- 基于节点图哈希的缓存机制,避免重复编译
- 支持热重载,材质修改后自动重新编译
Uniform 绑定:
- 自动绑定材质参数(颜色、数值)到 uniform 变量
- 纹理采样器绑定到对应的纹理单元
- 支持动态 uniform 更新
渲染管线:
- 使用独立的 FBO(Framebuffer Object)进行离屏渲染
- 支持多种预览几何体(球体、立方体、平面、圆柱)
- 实时应用节点图生成的材质
相机控制:
- 轨道相机系统(Yaw、Pitch、Distance)
- 鼠标拖拽旋转视角
- 滚轮缩放
- 自动聚焦到预览对象
性能优化:
- 帧率限制(~60 FPS)
- 仅在材质或视角变化时重新渲染
- 调试日志限流(每 5 秒输出一次统计信息)
Photon 兼容性检测:
- 运行时检测 Photon 是否加载
- 优雅降级:Photon 不可用时显示提示信息
JSON 格式:
{
"version": "1.0",
"name": "Material Name",
"nodes": [
{
"id": "uuid",
"type": "TEXTURE_SAMPLE",
"position": {"x": 100, "y": 200},
"parameters": {...}
}
],
"connections": [
{
"from": {"node": "id1", "socket": "Color"},
"to": {"node": "id2", "socket": "Albedo"}
}
]
}
序列化 (MaterialSerializer):
- 遍历节点图,提取节点和连接信息
- 保存节点特定参数(颜色值、纹理路径等)
- 使用 Gson 生成格式化的 JSON
反序列化 (MaterialDeserializer):
- 版本检查,确保兼容性
- 根据类型字符串重建节点实例
- 恢复节点参数和位置
- 重建连接关系
文件管理 (MaterialFileManager):
- 材质文件存储在
config/assimploader/materials/ - 文件扩展名:
.material.json - 支持列表、加载、保存、删除、导入、导出操作
- 文件名清理,防止非法字符
基于 ModernUI:
- 自定义 View 组件,继承自 ModernUI 的 View 类
- 使用 Canvas API 进行 2D 图形绘制
交互功能:
- 平移:中键或空白区域拖拽移动视口
- 缩放:鼠标滚轮缩放(0.1x - 3.0x)
- 节点拖拽:点击标题栏拖动节点
- 连接创建:从输出 Socket 拖拽到输入 Socket
- 节点选择:点击节点进行选择,显示属性面板
视觉元素:
- 网格背景(主网格和次网格)
- 贝塞尔曲线连接线
- 节点阴影和高亮效果
- Socket 颜色编码(根据类型)
支持的快捷键:
Ctrl+S: 保存材质Ctrl+O: 打开材质Ctrl+N: 新建材质Delete: 删除选中节点Ctrl+D: 复制节点Ctrl+Z: 撤销Ctrl+Y: 重做Space: 打开节点搜索对话框
功能:
- 快速搜索和添加节点
- 按类别过滤(Input、Math、Utility、Output)
- 模糊匹配节点名称
- 键盘导航支持
通知类型:
- 信息提示(蓝色)
- 成功提示(绿色)
- 警告提示(黄色)
- 错误提示(红色)
显示特性:
- 非阻塞式通知
- 自动淡出动画
- 支持多条通知堆叠
日志分类:
- 使用
DebugCategory.LOOKDEV标识 NodeEditor 相关日志 - 支持 DEBUG、INFO、WARN、ERROR 级别
关键调试点:
- 节点图执行:拓扑排序、循环检测、节点求值
- 着色器生成:代码生成、变量命名、依赖追踪
- 着色器编译:文件写入、Photon 编译、错误处理
- 材质预览:渲染循环、相机控制、材质更新
- 序列化:JSON 生成、文件 I/O、版本检查
性能考虑:
- 高频调用方法(如 render)使用限流日志
- 避免在每帧输出调试信息
- 使用 try-catch 包装关键操作,记录异常堆栈
依赖关系:
- Photon 提供增强的渲染管线和着色器系统
- 支持自定义着色器和材质
- 提供 ShaderInstance API 用于着色器管理
可选依赖:
- 系统设计为 Photon 可选
- 运行时检测 Photon 是否存在
- 无 Photon 时禁用实时预览功能
UI 框架:
- 提供现代化的 UI 组件和布局系统
- Canvas API 用于自定义绘制
- 事件系统处理用户交互
着色器系统:
- ShaderInstance:着色器程序封装
- Uniform:着色器参数绑定
- RenderSystem:OpenGL 状态管理
渲染 API:
- BufferBuilder:顶点数据构建
- Tesselator:网格渲染
- PoseStack:变换矩阵栈
- 打开节点编辑器:用户通过 UI 进入 LookDev 模式
- 添加节点:使用搜索对话框或节点面板添加所需节点
- 连接节点:拖拽 Socket 建立数据流
- 配置参数:在属性面板中调整节点参数(颜色、数值、纹理)
- 实时预览:材质自动应用到预览几何体
- 保存材质:将节点图序列化为 JSON 文件
- 节点图验证:检查连接有效性和类型兼容性
- 拓扑排序:确定节点执行顺序
- GLSL 生成:遍历节点,生成对应的 GLSL 代码
- 模板填充:将生成的代码插入着色器模板
- 文件写入:保存 .vsh、.fsh 和 .json 文件
- Photon 编译:通过 ShaderManager 编译着色器
- Uniform 绑定:设置材质参数
- 应用渲染:在预览或实际场景中使用材质
- 文件读取:从
.material.json读取 JSON 数据 - 版本检查:验证文件格式版本
- 节点重建:根据类型创建节点实例
- 参数恢复:设置节点的保存参数
- 连接重建:根据 ID 重新建立节点连接
- 着色器重新生成:触发着色器编译流程
- 预览更新:在编辑器中显示加载的材质
步骤:
- 在
NodeType枚举中添加新类型 - 在
NodeRegistry中注册节点元数据(输入/输出 Socket) - 创建节点类,继承
Node基类 - 实现
evaluate()方法(运行时求值) - 在
GLSLEmitter中添加 GLSL 代码生成逻辑 - 在
NodeFactory中添加节点创建分支 - 在序列化系统中添加参数处理
步骤:
- 在
EnhancedSocketType中定义新类型 - 添加类型转换规则
- 在
GLSLEmitter中处理新类型的代码生成 - 更新 UI 的颜色编码
灵活性:
ShaderTemplate可以被扩展或替换- 支持不同的渲染管线(Forward、Deferred)
- 可以添加自定义 uniform 和 varying
- 基于节点图内容的哈希缓存
- 避免重复编译相同的着色器
- 内存缓存 + 磁盘缓存
- 帧率限制,避免过度渲染
- 脏标记系统,仅在变化时更新
- 视锥剔除(未来可扩展)
- 异步着色器编译(未来可扩展)
- 增量更新,避免全图重绘
- 事件节流,限制高频事件处理
- 捕获 GLSL 编译错误
- 在 UI 中显示错误信息
- 提供错误行号和描述
- 节点求值异常捕获
- 优雅降级,使用默认值
- 错误日志记录
- 文件不存在处理
- JSON 解析错误恢复
- 版本不兼容提示
- 程序化纹理生成节点
- 噪声函数节点(Perlin、Simplex)
- 颜色空间转换节点
- 高级数学节点(矩阵运算、向量投影)
- 预设材质模板
- 材质分享和导入
- 在线材质市场集成
- 着色器性能分析工具
- 节点执行时间统计
- 优化建议
- 材质版本控制
- 多人协作编辑
- 变更历史和回滚
本系统实现了从节点图构建到实时渲染的完整材质编辑工作流,核心特点包括:
- 模块化设计:各组件职责清晰,易于维护和扩展
- 类型安全:强类型 Socket 系统防止无效连接
- 实时反馈:即时预览材质效果
- 可序列化:材质可保存、加载和分享
- Photon 集成:充分利用现代渲染管线
- 调试友好:全面的日志和错误处理
系统为 Minecraft 模组开发者提供了强大的材质创建工具,降低了 PBR 材质制作的技术门槛,同时保持了足够的灵活性和扩展性。