3D 场景编辑器
ChaUI 2.0.0 把 3D 菜单作为页面编辑器的一部分:scene 是带独立深度缓冲和相机的场景视口,scene_model 是其中的 ChaEngine 模型节点。前景、后景和普通 2D 组件仍按页面层级组合,场景内部的模型则按真实深度互相遮挡。
支持范围
3D 场景编辑器、场景后处理、阴影编辑和视口交互已经同步到当前全部 ChaUIMod 客户端适配。使用 ChaEngine 模型时还需要安装同版本的 ChaEngineMod;当前可用组合为 Forge 1.16.5、Forge 1.20.1,以及 NeoForge 1.21.1、1.21.4、1.21.8、1.21.11。这些组合统一使用场景专用 Shader 和 V4 provider。其他 ChaUIMod 版本仍可编辑、保存场景配置,但没有对应 ChaEngineMod 时模型节点会按不可用状态安全降级。
准备模型目录
客户端需要同时安装版本匹配的 ChaUIMod 与 ChaEngineMod,并取得服务器下发的 ChaEngine 模型资源。编辑器通过可选的 ChaEngine provider 读取模型目录,不会创建伪实体,也不会靠实体名称或 NBT 猜模型。
目录模型由两个字段唯一确定:
catalog: entity:实体模型目录;catalog: block:方块模型目录;catalog: item:物品模型目录,只列出配置了三维模型的物品;modelId:所选目录中的真实模型 ID。
编辑器的模型来源使用下拉框选择:
entity/block/item:从 ChaEngine 的目录中选择模型。首次显示相关属性时会自动读取目录,也可以搜索和手动刷新;custom:直接填写 ChaEngine 资源的相对路径;custom_entity:直接填写资源路径,并额外填写一个实体类型标识。
直接资源路径都相对于 ChaEngine 模型资源根目录,只能使用 / 分隔,不能以 / 开头,也不能包含 .、.. 或 Windows 盘符。模型文件和材质文件必填,动画文件可留空。例如:
source: custom
model: models/menu/guardian.geo.json
animation: animations/menu/guardian.animation.json
texture: textures/menu/guardian.pngcustom_entity 的 entityType 只用于标识该自定义模型对应的生物类型(例如 some_mod:creature),不会在世界中额外生成实体、AI 或碰撞体;模型仍由填写的资源路径直接渲染。
调整场景光照
选中 scene 后,属性面板会把“场景光照”作为独立分区,依次显示光照开关、环境亮度、曝光、主光方向、补光方向、阴影开关、阴影强度、柔和度、偏移和质量。内置与外置编辑器使用相同顺序;连续数值支持悬停后左右拖动,也可以单击输入精确值,修改会立即刷新场景预览。阴影质量使用下拉框选择。
scene:
lightingEnabled: true
ambientLight: 0.55
exposure: 1.25
keyLightX: 0.2
keyLightY: 1.0
keyLightZ: -0.7
fillLightX: -0.2
fillLightY: 1.0
fillLightZ: 0.7
shadowEnabled: true
shadowStrength: 0.55
shadowSoftness: 1.5
shadowBias: 0.0015
shadowMapSize: 1024ambientLight 默认 0.55,范围是 0.0 至 2.0,用来抬高背光面和暗部;exposure 默认 1.25,范围是 0.1 至 4.0,用来调整整体明暗。主光和补光的三个坐标组成方向向量,不是光源的世界坐标,渲染时会自动归一化;主光方向表示模型表面指向主光的方向。
shadowStrength 默认 0.55、范围为 0.0 至 1.0;shadowSoftness 默认 1.5、范围为 0.0 至 4.0;shadowBias 默认 0.0015、范围为 0.0 至 0.02。这三个字段可以左右拖动,步长依次为 0.01、0.1 和 0.0001。质量下拉框提供 512、1024、2048,默认 1024;分辨率越高越清晰,也会增加显存和渲染开销。
只有主光会投影,环境光和补光不会。同一场景里已成功生成有效范围的可见模型会互相投射和接收阴影;透明纹理使用二值阴影,透明空洞不投影,半透明部分不会形成渐变透明影子。新建场景会显式默认开启阴影,旧页面缺少 shadowEnabled 时默认关闭,打开或保存其他字段不会偷偷补写该开关。
lightingEnabled: false 时,模型光照阶段直接使用纹理原色、顶点 tint、overlay、原 alpha 与自发光,环境亮度、曝光、法线、两个方向和阴影都不再参与该阶段;单独启用的场景后处理仍会作用于最终画面。阴影范围尚未准备好或阴影资源失败时,会继续显示无阴影工作室光照。专用 Shader 只影响 ChaUI 3D 场景模型,不影响普通世界中的 ChaEngine 模型。当前不包含环境贴图、Bloom、SSAO、真实次表面散射、光源颜色或距离衰减。
这一功能要求对应版本的 ChaEngineMod 提供 ChaUISceneModelProviderV4 / API_VERSION=4。旧 V1、V2、V3 provider 不会被探测或作为固定光照回退;版本不匹配时只禁用对应模型节点,页面其他内容仍正常工作。
调整模型材质和场景后处理
选中 scene_model 后,“模型材质”分区可以调整金属度、粗糙度、自发光颜色和自发光强度。选中 scene 后,“场景后处理”分区可以选择色调映射,并调整亮度、对比度、饱和度、暗角、色差、锐化和色彩平衡。内置与外置编辑器使用同一组字段;连续数值可以左右拖动,也可以单击输入精确值。
scene:
toneMappingEnabled: true
toneMapping: aces
brightness: 0.0
contrast: 0.0
saturation: 1.0
vignetteEnabled: false
vignetteAmount: 0.5
vignetteHardness: 1.5
chromaticAberrationEnabled: false
chromaticAberration: 0.003
sharpenEnabled: false
sharpenStrength: 0.3
colorBalanceEnabled: false
colorBalanceShadowsR: 0.0
colorBalanceShadowsG: 0.0
colorBalanceShadowsB: 0.0
colorBalanceMidtonesR: 0.0
colorBalanceMidtonesG: 0.0
colorBalanceMidtonesB: 0.0
colorBalanceHighlightsR: 0.0
colorBalanceHighlightsG: 0.0
colorBalanceHighlightsB: 0.0sceneModel:
metalness: 0.15
roughness: 0.65
emissiveColor: "#FFFFFF"
emissiveStrength: 0.0金属度、粗糙度范围都是 0.0..1.0;自发光强度范围为 0.0..2.0。亮度范围 -0.5..0.5,对比度 -1.0..1.0,饱和度 0.0..2.0,暗角程度 0.0..1.5、硬度 0.5..3.0,色差 0.0..0.02,锐化 0.0..1.0,色彩平衡的每个 RGB 值为 -0.3..0.3。建议先保持中性默认值,再一次只打开一个效果观察变化。
创建顺序
- 使用
/chaui editor <页面ID>打开页面编辑器。 - 在组件库中先添加一个
scene,并拖动它确定 3D 视口在页面中的位置和大小。 - 选中场景后,在模型来源下拉框中选择
entity、block、item、custom或custom_entity。目录来源可以搜索并刷新后从下拉框选择modelId;直接来源则填写模型、动画(可选)和材质相对路径,custom_entity还要填写entityType。 - 新模型会创建为该
scene的直接子组件,类型是scene_model。scene_model不能放在页面根级,也不能挂到普通布局组件下。 - 继续加入图片、文字或按钮作为 2D 前景与后景;用页面组件顺序和
z控制它们与整个scene视口之间的层级。
选择与变换
直接点击模型身体即可选择整体模型,不需要手工配置碰撞盒。ChaEngineMod 会在模型首次成功渲染时,根据实际提交的几何生成固定局部 AABB;在该范围尚未生成前,模型可以显示但暂时不能点选。
选中模型后可以使用以下工具:
| 工具 | 快捷键 | 用途 |
|---|---|---|
| 选择 | Q | 只选择模型,不开始变换 |
| 移动 | V | 沿红、绿、蓝轴修改 x/y/z |
| 旋转 | R | 修改 rotationX/rotationY/rotationZ |
| 缩放 | E | 修改统一的 scale |
拖动开始时会捕获原始变换;松开后整次拖动只形成一条撤销记录。按 Esc 可以取消当前拖动并恢复原值。属性栏直接输入数值也会写入同一页面草稿,并可使用撤销、重做恢复。
选中场景或场景模型时,视口左上角会显示这组快捷键提示。属性栏中的连续数值(布局 x/y/width/height、实体 yaw/pitch/roll/scale/offset、模型位置/旋转/缩放、镜头与光照参数)悬停会显示左右拖动标记;单击仍进入文本编辑,按住左键横向拖动才会改值。布局尺寸每像素调整 1,位置和镜头坐标每像素调整 0.1,角度每像素调整 1 度,缩放每像素调整 0.05;按住 Shift 精调,按住 Ctrl 粗调。拖动只在当前字段第一次产生撤销记录,公式、文本、枚举和布尔字段不启用拖动。
普通页面元素的画布拖动需要左键按住 0.5 秒。若过早移动,编辑器会在屏幕上方显示红色“请长按 0.5 秒后拖拽”提示并从上方淡入;松开鼠标后提示向上淡出,页面布局不会被提前移动。
外置 Swing 编辑器遵循同一门槛和提示动画;提示固定在外置窗口顶部居中,且不会拦截页面树和属性栏的鼠标事件。
第一版只选择整个 scene_model,不支持骨骼、part 或单个三角形点击。需要多个点击目标时,应拆成多个模型节点或叠加普通 ChaUI 组件。
调整编辑相机
鼠标位于场景视口内时:
- 按住中键拖动:围绕目标点旋转观察;
- 按住
Shift + 中键拖动:平移观察目标; - 滚轮:拉近或拉远。
这些手势只改变当前标签页的临时预览,不会在浏览模型时不断改写页面 YAML。切换选中组件不会重置镜头,每个场景分别保留自己的临时镜头。切换标签后,每个标签会恢复自己的选择、工具和临时镜头。
内置编辑器右侧属性栏支持拖拽滚动条,也可以点击轨道跳转。外置编辑器的镜头记录中,点击“加载”会立即应用到当前临时镜头,“复制”按钮会复制对应脚本。
编辑模式中的显隐优先级是:临时显隐 > 条件显隐 > 显示。临时状态只影响编辑器,预览与实际页面仍按配置运行;父级隐藏仍会隐藏其子树。当临时状态与配置计算结果相反时,即使切换选中组件,也会保留特殊边框和左上角标签:青绿色表示“临时显示”,粉色表示“临时隐藏”。这些临时状态不写入页面 YAML。
记录镜头状态
想把某个观察角度留给菜单按钮或脚本使用时,不需要手抄坐标:
- 先用中键、
Shift + 中键和滚轮调整到想要的画面。 - 选中对应的
scene。属性栏的“当前临时镜头”会显示相机、目标和上方向的九个实际值。 - 点击“打开镜头记录”(记录当前镜头),在二级对话框的“记录名称”中输入一个 ID,例如
menu_focus、开场或boss-zoom。 - 点击“记录当前”。同名状态已经存在时,编辑器会先询问是否覆盖。
记录后的状态会保存在这个场景自己的 scene.cameraStates 中。状态 ID 可以使用中英文、数字、_ 和 -;不要使用空格、斜杠或点号。记录列表也集中在这个二级对话框中:
- 加载/应用只把状态放回当前临时镜头,便于继续检查画面,不会立即改写 YAML;
- 删除移除该状态,并进入正常撤销/重做记录;
- 复制按钮会按场景组件 ID 和状态 ID 生成
component("场景ID").scene.moveTo("状态ID", 800)并复制到系统剪贴板;对话框不再提供时长输入,复制结果固定使用800毫秒,需要其他时长时直接修改脚本第二个参数; - 点击“还原镜头”只把临时镜头恢复到场景默认的九个相机值,不删除任何记录;
- 只有点击编辑器顶栏“保存”后,记录/覆盖/删除才会写入页面文件。
下面是一个可直接放在 scene 数据块里的镜头状态。每个状态必须完整保留九个坐标:
scene:
cameraStates:
menu_focus:
cameraX: 0
cameraY: 0
cameraZ: 8
targetX: 0
targetY: 0
targetZ: 0
upX: 0
upY: 1
upZ: 0镜头状态只保存这九个观察值,不保存投影方式、FOV、正交高度、裁剪距离或场景光照;主光、补光和 lightingEnabled 始终在“场景光照”区域独立配置。
用脚本切换镜头
在页面运行时,可以让场景从当前镜头平滑移动到已记录的状态。把下面一行放进按钮或其他组件的事件脚本中:
component("stage").scene.moveTo("menu_focus", 800)这会让 ID 为 stage 的场景在 800 毫秒内使用五次 smoothstep 缓入缓出曲线移动到 menu_focus。第二个参数单位固定为毫秒:0 会立即切换;非零值可以是 1 到 3600000。客户端在每个渲染帧重新采样相机,不受 20Hz 游戏 tick 限制。再次调用时会从镜头当时已经移动到的位置继续,不会先跳回旧起点。
例如,下面这个按钮被点击后会回到上面记录的菜单镜头:
- id: return_to_menu
type: button
layout:
x: 20
y: 20
width: 120
height: 20
button:
label: 返回菜单镜头
events:
leftClick: |
component("stage").scene.moveTo("menu_focus", 800)镜头移动只属于当前玩家这一次打开页面的运行状态,不会被脚本写回页面 YAML。若脚本随后直接修改 cameraX/Y/Z、targetX/Y/Z 或 upX/Y/Z 中任一个普通相机值,当前的平滑移动会停止并使用新值。
常见错误是状态 ID 写错、删除后仍调用旧名称,或只填写了部分九坐标。保存前会提示这类配置问题;脚本调用时则应确认目标场景和状态都存在。
动画预览
选中 scene_model 后,动画面板会向 provider 查询该模型已有的动画。可以选择动画、播放或暂停、切换预览循环,并拖动时间位置检查姿态。
- 选择动画会更新持久字段
sceneModel.animation; sceneModel.animationLoop是页面保存的运行时循环设置;- 播放/暂停状态、预览循环开关和拖动到的预览时间只属于当前编辑会话,不写入页面;
- 切换页面标签、切换模型或关闭编辑器时会释放旧动画预览实例。
第一版不提供关键帧时间线、动画曲线或骨骼编辑。
完整 YAML 示例
下面的页面包含一个透视场景和一个循环动画模型。sceneModel 是数据块名称,组件类型仍写作 scene_model。
id: scene_menu_demo
version: 1
title: 3D 场景菜单
size:
width: 640
height: 360
coordinateMode: absolute
display:
mode: screen
elements:
- id: stage
type: scene
z: 10
layout:
x: 80
y: 40
width: 480
height: 280
scene:
projection: perspective
fov: 45
near: 0.01
far: 100
cameraX: 0
cameraY: 0
cameraZ: 8
targetX: 0
targetY: 0
targetZ: 0
upX: 0
upY: 1
upZ: 0
lightingEnabled: true
ambientLight: 0.55
exposure: 1.25
keyLightX: 0.2
keyLightY: 1.0
keyLightZ: -0.7
fillLightX: -0.2
fillLightY: 1.0
fillLightZ: 0.7
shadowEnabled: true
shadowStrength: 0.55
shadowSoftness: 1.5
shadowBias: 0.0015
shadowMapSize: 1024
toneMappingEnabled: true
toneMapping: aces
brightness: 0.0
contrast: 0.0
saturation: 1.0
vignetteEnabled: false
vignetteAmount: 0.5
vignetteHardness: 1.5
chromaticAberrationEnabled: false
chromaticAberration: 0.003
sharpenEnabled: false
sharpenStrength: 0.3
colorBalanceEnabled: false
colorBalanceShadowsR: 0.0
colorBalanceShadowsG: 0.0
colorBalanceShadowsB: 0.0
colorBalanceMidtonesR: 0.0
colorBalanceMidtonesG: 0.0
colorBalanceMidtonesB: 0.0
colorBalanceHighlightsR: 0.0
colorBalanceHighlightsG: 0.0
colorBalanceHighlightsB: 0.0
cameraStates:
menu_focus:
cameraX: 0
cameraY: 0
cameraZ: 8
targetX: 0
targetY: 0
targetZ: 0
upX: 0
upY: 1
upZ: 0
- id: guardian
type: scene_model
parent: stage
layout:
x: 0
y: 0
width: 1
height: 1
sceneModel:
catalog: entity
modelId: crystal_guardian
x: 0
y: 0
z: 0
rotationX: 0
rotationY: 25
rotationZ: 0
scale: 1
animation: idle
animationLoop: true
metalness: 0.15
roughness: 0.65
emissiveColor: "#FFFFFF"
emissiveStrength: 0.0如果不使用 provider 目录,也可以把上例中的 sceneModel 改成直接资源模型:
sceneModel:
source: custom
model: models/menu/guardian.geo.json
animation: animations/menu/guardian.animation.json
texture: textures/menu/guardian.png
x: 0
y: 0
z: 0
rotationY: 25
scale: 1
animationLoop: true保存时,编辑器提交当前页面草稿;成功回执到达后才更新保存基线。保存后关闭并重新打开页面,scene、scene_model、模型变换、材质、后处理、显式相机字段、cameraStates、animation 与 animationLoop 都应恢复。编辑时未记录的观察角度、播放暂停状态和时间拖动位置不会恢复,这是预期行为。
provider 不可用时
ChaEngineMod 缺失、provider API 不兼容、模型资源尚未同步或目录读取失败时,编辑器会显示不可用状态并安全降级:不会自动改写当前草稿,也不会影响页面中的 2D 组件。运行时只隐藏无法提交的模型节点,页面其他内容继续绘制和交互。
排查时依次确认 ChaUIMod 与 ChaEngineMod 的 Minecraft 版本和加载器完全一致,并确认该组合位于本页顶部列出的 ChaEngineMod 支持范围;目录模型要确认 catalog + modelId 与目录完全一致,直接模型要确认模型和材质路径都相对于 ChaEngine 资源根目录且文件确实存在。修改后重新打开编辑器并刷新目录。
猹件开发组