场景画面效果优化
This commit is contained in:
@@ -60,3 +60,146 @@
|
|||||||
立即 return,没有这个窗口)。
|
立即 return,没有这个窗口)。
|
||||||
6. 无头模拟按键:`Input.action_press` 只改动作状态、**不发输入事件**(Motor 的跳跃缓冲在
|
6. 无头模拟按键:`Input.action_press` 只改动作状态、**不发输入事件**(Motor 的跳跃缓冲在
|
||||||
`_unhandled_input` 收事件,探不到);要用 `Input.parse_input_event(InputEventAction)`。
|
`_unhandled_input` 收事件,探不到);要用 `Input.parse_input_event(InputEventAction)`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## main2 卡通渲染 / 世界环境 / 光照 调优(达到可交付观感)
|
||||||
|
|
||||||
|
目标:把 `world/main2.tscn` 的卡通着色器参数 + WorldEnvironment + 光照调到"商业化"水平。
|
||||||
|
改了 5 个文件:`project.godot`、`world/main2.tscn`、`shader/toon.tres`、
|
||||||
|
新增 `shader/toon_ramp_1d.tres`、删除 `shader/new_gradient_texture_1d.tres`。
|
||||||
|
|
||||||
|
### 动画诊断出的三个致命问题
|
||||||
|
|
||||||
|
1. **描边等于不存在**。`cel-shader-base` 的 `next_pass` 链、`outline.gdshader` 都正常,
|
||||||
|
但 `outline_width = 2.0` 在这个 Godot 版本里只对应约 **0.1px**,肉眼不可能看见。
|
||||||
|
实测标定:`像素宽度 ≈ outline_width × 0.057`(1364px 视口)。已改为 **30**(≈1.7px)。
|
||||||
|
2. **`toon.tres` 的 `specular` / `fresnel` RGB 都是纯黑** —— 两个模块虽然连着,贡献恒为 0。
|
||||||
|
3. **漫反射渐变是"黑→硬边→白"的二值 ramp**,导致场景只有一层死板明暗。
|
||||||
|
|
||||||
|
### 最关键的一条坑(务必记住)
|
||||||
|
|
||||||
|
**编辑器只在启动时注册 `[shader_globals]`。** 外部(含 MCP `settings_set`)改
|
||||||
|
project.godot 的全局着色器参数,正在跑的编辑器视口**完全不变**。
|
||||||
|
我就是因为这个,一开始把 `outline_width` 从 2 调到 10 再到 60,截图却毫无变化,
|
||||||
|
最后才定位到根因。验证手段:写一个 `res://tests/test_*.gd`(必须 `extends McpTestSuite`),
|
||||||
|
在 `test_*` 方法里直接 `RenderingServer.global_shader_parameter_set(...)`,
|
||||||
|
再用 MCP `test_run` 执行 —— 能在编辑器进程内把值推进渲染器。
|
||||||
|
|
||||||
|
同时用这个办法做了隔离实验,排除了 4 个错误猜想:雾、SSAO、泛光、菲涅尔**都不是**
|
||||||
|
墙面噪点的来源;真正的噪点是**截图传输压缩**(480px 截图墙面完全干净,1364px 才有颗粒)。
|
||||||
|
另外顺手证实 `POSITION` 顶点覆盖是生效的(写 `p.y += p.w * 0.8` 面板会整体下移),
|
||||||
|
所以描边 pass 本身没问题,别去改上游 `outline.gdshader`。
|
||||||
|
|
||||||
|
### 最终取值
|
||||||
|
|
||||||
|
- **着色器全局**(`project.godot [shader_globals]`):
|
||||||
|
`diffuse_curve = toon_ramp_1d.tres`、`specular_smoothness = 0.08`、
|
||||||
|
`fresnel_smoothness = 0.12`、`outline_width = 30`、
|
||||||
|
`outline_color = Color(0.08, 0.07, 0.1, 1)`。
|
||||||
|
- **新 ramp**(`shader/toon_ramp_1d.tres`,GradientTexture1D/256):
|
||||||
|
0.00–0.30 → 0.24;0.38–0.62 → 0.60;0.70–1.00 → 1.00,两级转场各 0.08 软边。
|
||||||
|
- **材质**(`shader/toon.tres`,以及 main2 里地板的独立 ShaderMaterial):
|
||||||
|
`specular = (0.12,0.12,0.12,0.45)`、`fresnel = (0.4,0.55,0.8,0.18)`。
|
||||||
|
- **Environment**:天空换成项目现成的 `world/sky/cartoon_sky.tres`(与 character_select /
|
||||||
|
ocean_demo 一致);`ambient_light_source = 3`(Sky) + 冷色补光
|
||||||
|
`(0.3,0.38,0.55)`、sky_contribution 0.45、energy 0.5;ACES 色调映射(`tonemap_mode=3`,
|
||||||
|
这个版本枚举确实是 LINEAR0/REINHARDT1/FILMIC2/ACES3/AGX4);SSAO 轻度(intensity 1.0、
|
||||||
|
detail 0.3、light_affect 0);Glow 阈值抬到 2.2 防止白面爆光;雾 0.004 + aerial 0.3;
|
||||||
|
adjustment contrast 1.12 / saturation 1.08。
|
||||||
|
- **光照**:平行光改暖色 `(1,0.925,0.83)`、energy 0.95、`light_angular_distance 0.8` 软阴影、
|
||||||
|
bias 0.05 / n_bias 1.5、max_distance 60;sconce 聚光灯 energy 3.2 / range 12 /
|
||||||
|
angle 55 / 开启阴影。顺手开了 `anti_aliasing/quality/msaa_3d = 2`(4x,描边抗锯齿)。
|
||||||
|
|
||||||
|
### 排查时踩的 MCP 细节
|
||||||
|
|
||||||
|
- MCP `settings_set` **写不了 Color**:传 `{"r":..,"g":..}` 会落成嵌套字典、
|
||||||
|
传 `"#141219"` 会落成 String,两者都不是引擎要的 Color。
|
||||||
|
正解是手改 project.godot 写成 `Color(r,g,b,a)`。改完用无头探针脚本
|
||||||
|
(`extends SceneTree` + `ProjectSettings.get_setting()` 打印 `typeof(inner)`)复验。
|
||||||
|
- `settings_set` 会把**整个** ProjectSettings 从内存写回磁盘,
|
||||||
|
所以它写完之后我手改过的 `Color(...)` 会被覆盖成 String —— **必须最后一步再手改**。
|
||||||
|
- `editor_screenshot` 的 `view_target` 会**移动用户的编辑器相机**;`max_resolution=0`
|
||||||
|
才是原生分辨率。
|
||||||
|
|
||||||
|
### 追加:远处地面"发白"的根因 = fresnel 掠射角饱和(务必记住)
|
||||||
|
|
||||||
|
用户反馈:main2 里走廊/餐厅方向的地面(z≈15~25)呈一片**灰白偏冷的平面**,近处木地板正常。
|
||||||
|
|
||||||
|
- 排查路径:`floor1.glb` 只有 1 个 mesh / 1 个材质(用 Python 解 GLB 的 JSON chunk 确认),
|
||||||
|
AABB 覆盖 x −18.2~16.6、z −24.9~32.9 —— **餐厅地面就是这块地板**,不是缺几何、
|
||||||
|
也不是贴图问题(BaseColor 是纯木纹)。地毯不泛白是因为它的固有色深,把叠加量盖住了。
|
||||||
|
- **根因在 `shader/includes/base-cel-shader.gdshaderinc` 的 `fresnel_light()`**:
|
||||||
|
```
|
||||||
|
fresnel_dot = 1.0 - dot(normal, view); // 水平面越远越掠射 → 越接近 1
|
||||||
|
fresnel_threshold = pow(1.0 - fresnel_strength, dot(light, normal)); // ≈0.84
|
||||||
|
... * smoothstep(threshold ± fresnel_smoothness/2, fresnel_dot)
|
||||||
|
```
|
||||||
|
实测:5 m 处 fresnel_dot≈0.69(=0,无贡献),20 m 处≈0.92(=1,满强度)。
|
||||||
|
于是**远处地面被整片点亮**,叠加的是 `fresnel_color = (0.4,0.55,0.8)` 蓝白,
|
||||||
|
木地板 albedo(≈0.34,0.24,0.2) + 叠光(≈0.40,0.51,0.66) → 就是用户看到的灰白。
|
||||||
|
- **是上一轮调优引入的**:`fresnel` 原来 RGB=(0,0,0)(贡献恒 0,所以从没显形),
|
||||||
|
上一轮改成 (0.4,0.55,0.8) 后才出现。**大平面(地板/天花板)上放菲涅尔轮廓光必然有这副作用。**
|
||||||
|
- 修法(择一):`fresnel.a` 调到 0.05 以下;或把 `fresnel_color` 压暗到接近物色;
|
||||||
|
或把 `fresnel_smoothness`(全局 uniform)调小收紧过渡带。当前已按用户要求
|
||||||
|
**恢复为 (0.4,0.55,0.8,0.18)**,泛白会重现,等用户定夺。
|
||||||
|
|
||||||
|
### 追加:MCP `material_manage(apply_to_node)` 会写盘并**删除孤儿资源**
|
||||||
|
|
||||||
|
- 用 MCP `apply_to_node` 给 `model/floor1/pPlane1` 临时套一个纯红 unshaded 材质做隔离实验,
|
||||||
|
之后 `scene_open force_reload` **材质没有恢复** —— 因为该操作**直接改了磁盘上的 .tscn**
|
||||||
|
(返回值里的 `saved_to: ""` 不代表没落盘)。
|
||||||
|
- 更严重:Godot 重新序列化时把**失去引用的资源全删了** —— 地板配套的
|
||||||
|
`ShaderMaterial_mmyc1`(cel + outline)、`ShaderMaterial_tyxef`,
|
||||||
|
以及 3 个 `ext_resource`(`outline.gdshader`/`cel-shader-base.gdshader`/地板 BaseColor 贴图)
|
||||||
|
一并消失,同时把等于默认值的属性行省略(如 `glow_blend_mode = 1`)。
|
||||||
|
- **教训:拿 MCP 改材质做实验前先 `git stash` 或备份 .tscn**;事后用 `git diff` 对照逐行恢复。
|
||||||
|
恢复时注意用**调优后的值**(不是 HEAD 的原值)。
|
||||||
|
|
||||||
|
## 阴影锯齿专项(main2 沙发/盘子)
|
||||||
|
|
||||||
|
- 现象:沙发扶手上大片「梳齿/蕨叶」状黑纹 + 盘子影子边缘阶梯状锯齿。
|
||||||
|
- 逐个隔离(改 `shadow_enabled` / 单变量逐项)后确认:**都来自 `DirectionalLight3D`**。
|
||||||
|
- **根因 = `light_angular_distance = 0.8`**。它开启 PCSS 软阴影,半影半径随距离放大,
|
||||||
|
但 Godot 的采样数有限 → 出现稀疏采样尖刺(就是那片蕨叶纹)。
|
||||||
|
归零后(`0.0`)两个 artifact **同时消失**。
|
||||||
|
- 次要项:工程设置 `soft_shadow_filter_quality` 默认是 **2(Soft Low)**,
|
||||||
|
提到 **4(Soft High)** 后高频噪点能量 1.149 → 0.687(-40%),强跳变 756 → 630。
|
||||||
|
- `shadow_blur`(1.0/1.5/2.5/4.0)实测**几乎无影响**(0.669~0.687),已删掉该覆盖行。
|
||||||
|
- `shadow_bias`/`shadow_normal_bias` 归零会导致**全身自阴影爆发**(阴影面积 18484 → 114706),
|
||||||
|
必须用引擎默认 0.1 / 2.0(原场景的 0.05 / 1.5 偏低)。
|
||||||
|
- 最终:`light_angular_distance = 0.0`、删掉 bias/blur 覆盖行、
|
||||||
|
`directional_shadow_max_distance 60 → 45`、`project.godot` 加
|
||||||
|
`lights_and_shadows/{directional_shadow,positional_shadow}/soft_shadow_filter_quality=4`。
|
||||||
|
- 前后对比图存在 `docs/shadow_aliasing_fix.png`。
|
||||||
|
|
||||||
|
### 追加:用户把 blur 归零后「全画面三角形颗粒」
|
||||||
|
|
||||||
|
用户手动把 `shadow_blur = 0`,**同时把 `shadow_normal_bias` 也设成了 0**,
|
||||||
|
结果整幅画面(沙发、盘子、地板全部)盖满斜向的三角颗粒 / 摩尔纹。
|
||||||
|
|
||||||
|
在独立进程里做了 2×2 对照(`soft_shadow_filter_quality = 4`,
|
||||||
|
指标 = 区域内相邻像素亮度差的平均,越低越干净):
|
||||||
|
|
||||||
|
| 组合 | 4096 贴图 | 8192 贴图 |
|
||||||
|
|---|---|---|
|
||||||
|
| blur 0 + normal_bias 0(**用户当时**) | **12.730** | **17.923** |
|
||||||
|
| blur 0 + normal_bias 2 | 0.638 | 0.611 |
|
||||||
|
| blur 1 + normal_bias 0 | 0.566 | 0.522 |
|
||||||
|
| blur 1 + normal_bias 2(推荐) | 0.577 | 0.532 |
|
||||||
|
| blur 0.6 + normal_bias 2 + max_dist 25 | 0.546 | 0.537 |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
- **必须「blur=0 且 normal_bias=0」同时成立才会爆**(12.7)。任意改回一个就回到 ~0.6。
|
||||||
|
机制:`normal_bias = 0` 会在**每个阴影贴图纹素**上产生自阴影判定抖动,
|
||||||
|
而 `shadow_blur` 正是那个 PCF 半径 —— 它被归零后抖动不再被平滑,
|
||||||
|
于是以贴图纹素的频率原样显现成三角颗粒(贴图纹素斜投影到受光面就是四边形/三角)。
|
||||||
|
- **加大阴影贴图分辨率没用,反而更糟**(12.730 → 17.923)。
|
||||||
|
分辨率越高的贴图纹素越细密 → 抖动频率越高 → 颗粒越密越明显。
|
||||||
|
**所以"锯齿是阴影贴图不够大"是错的直觉。**
|
||||||
|
- 想要更锐的阴影:`shadow_blur` 可以取 0(normal_bias 保持 2.0 就干净,0.638)。
|
||||||
|
- 已把编辑器的 `shadow_normal_bias` 恢复到 2.0、`shadow_blur` 恢复到 1.0
|
||||||
|
(用 MCP `node_set_property`,**实测它只改编辑器内存、不写盘**)。
|
||||||
|
- 对比图存在 `docs/shadow_normal_bias_fix.png`。
|
||||||
|
|
||||||
|
|||||||
@@ -46,10 +46,92 @@ Godot 4.7.2(Forward+,Jolt Physics,D3D12)。编辑器位于
|
|||||||
- `shader/toon_apply.gd`(@tool Node3D)给每个 MeshInstance3D 复制一份独立材质,
|
- `shader/toon_apply.gd`(@tool Node3D)给每个 MeshInstance3D 复制一份独立材质,
|
||||||
因为**每个模型有各自的贴图**,所以必须独立(不能共享一份材质)。
|
因为**每个模型有各自的贴图**,所以必须独立(不能共享一份材质)。
|
||||||
- 已在项目设置里用了 **global uniform**:`diffuse_curve`、`specular_smoothness`、
|
- 已在项目设置里用了 **global uniform**:`diffuse_curve`、`specular_smoothness`、
|
||||||
`fresnel_smoothness`、`outline_width`、`outline_color` —— 这几项调参本来就是全局实时生效。
|
`fresnel_smoothness`、`outline_width`、`outline_color`。
|
||||||
|
⚠️ **但"全局实时生效"是错的**(2026-10-15 实测纠正):编辑器只在**启动时**
|
||||||
|
把 `[shader_globals]` 注册进 RenderingServer,之后外部改 project.godot(或
|
||||||
|
MCP 的 `project_manage settings_set`)**不会**影响正在运行的编辑器视口。
|
||||||
|
手动改完全局参数必须**重启编辑器**(或临时用 `test_run` 跑一段
|
||||||
|
`RenderingServer.global_shader_parameter_set()` 把值推进去)才能看到效果。
|
||||||
|
这正是当初"改了 outline_width 却毫无变化"的原因。
|
||||||
|
- `outline_width` 的实际像素宽度约为 `width × 0.057`(1364px 视口实测校准),
|
||||||
|
所以**原来的 2.0 实际只有约 0.1px —— 等于没描边**。要看到 2px 描边需要 width ≈ 30。
|
||||||
- 贴图尺寸极不统一(289 张 PNG / 24 种尺寸,1024²、512²、4096²、32² 混杂),
|
- 贴图尺寸极不统一(289 张 PNG / 24 种尺寸,1024²、512²、4096²、32² 混杂),
|
||||||
因此**不适合** Texture2DArray + per-instance uniform 方案(显存会爆且要额外打包流水线)。
|
因此**不适合** Texture2DArray + per-instance uniform 方案(显存会爆且要额外打包流水线)。
|
||||||
- 编辑器插件 `addons/toon_refresh/`:改 toon.tres 时自动重刷 toon_apply 材质。
|
- 编辑器插件 `addons/toon_refresh/`:改 toon.tres 时自动重刷 toon_apply 材质。
|
||||||
|
**只覆盖材质级参数**(color/specular/fresnel/uv),管不到 global uniform。
|
||||||
|
- ⚠️ **`fresnel`(轮廓光)不能给大平面用**:`fresnel_light()` 以
|
||||||
|
`1 - dot(normal, view)` 为激活量,水平地面/天花板稍远就是掠射角 → 直接饱和成满强度,
|
||||||
|
整片平面被 `fresnel_color` 点亮。**"远处地面发白"就是这么来的**
|
||||||
|
(原来是 (0,0,0) 贡献恒 0 所以没暴露,2026-10-15 改成 (0.4,0.55,0.8) 后显形)。
|
||||||
|
真要留轮廓光就把 `a` 压到 ≤0.05,或把颜色调暗到接近物色。
|
||||||
|
- ⚠️ **MCP `material_manage(op="apply_to_node")` 直接改磁盘 .tscn**,
|
||||||
|
且重新序列化时会**删除失去引用的子资源与 ext_resource**
|
||||||
|
(实测:地板实验后 `ShaderMaterial_mmyc1`/`tyxef` + 3 个 ext_resource 全被清掉,
|
||||||
|
`saved_to:""` 也照样落盘)。拿 MCP 做材质实验前先备份,事后用 `git diff` 逐行核对恢复。
|
||||||
|
|
||||||
|
## 卡通渲染调参(2026-10-15 定的基线取值)
|
||||||
|
|
||||||
|
- `shader/toon_ramp_1d.tres`(新,替代已删除的 `new_gradient_texture_1d.tres`):
|
||||||
|
三级 cel 明暗带,灰阶 0.24 / 0.60 / 1.00,转场各留 0.08 软边。
|
||||||
|
注意 `diffuse_sample()` **只取红通道**,所以渐变做成彩色也没用。
|
||||||
|
- `specular_smoothness = 0.08`、`fresnel_smoothness = 0.12`;
|
||||||
|
原值 10.0 会把高光压到几乎不可见(`smoothstep(0.05, 10.05, x)`)。
|
||||||
|
- `outline_width = 30`、`outline_color = Color(0.08, 0.07, 0.1, 1)`。
|
||||||
|
- `toon.tres` 的 `specular` / `fresnel` **RGB 原来都是纯黑 = 两个模块完全失效**,
|
||||||
|
现已改为 `specular=(0.12,0.12,0.12,α0.45)`、`fresnel=(0.4,0.55,0.8,α0.18)`。
|
||||||
|
注意 specular 的 α 只用来推 gloss 指数,**亮度只能靠 rgb 调**。
|
||||||
|
- MCP `settings_set` 写不了 Color:传 dict 会落成 `{"r":..}` 嵌套字典(引擎无法绑定),
|
||||||
|
传 `"#rrggbb"` 会落成 String。**正确做法是手改 project.godot 写成 `Color(r,g,b,a)`。**
|
||||||
|
int 型也一样:会落成 `={"type": "int","value": 4.0}` 的字典块,**用完记得手改回 `=4`**。
|
||||||
|
|
||||||
|
## 阴影质量(2026-10-15 定位完毕)
|
||||||
|
|
||||||
|
- **`DirectionalLight3D.light_angular_distance` 是本项目阴影锯齿的元凶。**
|
||||||
|
它开启 PCSS 软阴影:半影半径 = 遮挡距离 × tan(角径),但 Godot 的 PCSS
|
||||||
|
采样数固定 → 半径一大就变成**稀疏采样尖刺**,表现为:
|
||||||
|
1) 大面积表面(沙发扶手内侧面)上出现**成片的「梳齿/蕨叶」黑纹**;
|
||||||
|
2) 物体投影(白盘子)边缘出现**阶梯 + 毛刺**。
|
||||||
|
实测 `0.8°` 时 artifact 明显,**改成 `0.0` 后两者同时消失**。
|
||||||
|
⚠️ 别以为角径越大越"柔软自然"——在这个引擎里它只会换来尖刺。
|
||||||
|
- 工程设置 `rendering/lights_and_shadows/{directional_shadow,positional_shadow}/soft_shadow_filter_quality`
|
||||||
|
**默认只有 2(Soft Low)**,提到 **4(Soft High)** 实测高频噪点能量降 40%。枚举顺序:
|
||||||
|
`0 Hard, 1 Soft Very Low, 2 Soft Low, 3 Soft Medium, 4 Soft High, 5 Soft Ultra`。
|
||||||
|
- `shadow_blur`(0~10,默认 1.0)在 angular=0 时**几乎测不出影响**,不用调。
|
||||||
|
- `shadow_bias` / `shadow_normal_bias` **别低于引擎默认 0.1 / 2.0**:
|
||||||
|
归零会让全身自阴影爆发(阴影面积 18484px → 114706px)。原场景的 0.05 / 1.5 偏低。
|
||||||
|
- ⚠️ **`shadow_normal_bias = 0` + `shadow_blur = 0` 同时出现 = 整幅画面三角颗粒/摩尔纹**
|
||||||
|
(2026-10-15 实测,相邻像素亮度差 0.58 → 12.73,20 倍):
|
||||||
|
`normal_bias = 0` 让**每个阴影贴图纹素**都自阴影抖动,而 `shadow_blur` 就是 PCF 半径,
|
||||||
|
归零后抖动不再被平滑,于是按贴图纹素频率原样显现(纹素斜投影 → 三角/四边颗粒)。
|
||||||
|
任意恢复其中一个即可(0.638 / 0.566)。只想锐化就把 blur 取 0、**normal_bias 留 2.0**。
|
||||||
|
- ⚠️ **提高阴影贴图分辨率救不了锯齿**:`directional_shadow/size 4096 → 8192`
|
||||||
|
在正常配置下只改善 ~8%,在坏配置下**反而更糟**(12.73 → 17.92),
|
||||||
|
因为纹素越细抖动频率越高。"锯齿 = 贴图不够大"是错误直觉。
|
||||||
|
- 室内场景可把 `directional_shadow_max_distance` 收到 45(原来 60),近场纹素密度提高 1.3×。
|
||||||
|
|
||||||
|
## 验证"启动时固化"的设置(可复用套路)
|
||||||
|
|
||||||
|
`[shader_globals]`、`rendering/lights_and_shadows/*`(阴影贴图尺寸、软阴影滤波质量)、
|
||||||
|
MSAA 等**只在引擎启动时读一次**,改 project.godot 对运行中的编辑器视口无效。
|
||||||
|
不要靠编辑器截图验证这类改动,走这条独立进程路线:
|
||||||
|
|
||||||
|
1. 造一个探针场景 `tools/_probe.tscn` + `tools/_probe.gd`:`extends Node3D`,
|
||||||
|
在 `_ready()` 里 `load("res://world/xxx.tscn").instantiate()`、加一台 Camera3D、
|
||||||
|
等 ~60 帧、`await RenderingServer.frame_post_draw` 后
|
||||||
|
`get_viewport().get_texture().get_image().save_png(...)`、`quit()`。
|
||||||
|
2. `DisplayServer.window_set_position(Vector2i(-6000,-6000))` 把窗口挪到屏幕外,不打扰用户。
|
||||||
|
3. 用 `--resolution 1364x772` + 位置参数指定场景跑:
|
||||||
|
`godot --path <proj> --resolution 1364x772 res://tools/_probe.tscn`(**别加 `--headless`**,
|
||||||
|
dummy 渲染后端出不了图)。
|
||||||
|
4. 想在探针里改灯的参数做单变量对照,直接在脚本里改 `DirectionalLight3D` 的属性再截图,
|
||||||
|
一次进程就能出多张对照图。
|
||||||
|
5. **要像素级对齐编辑器视口**:`res://tests/test_xxx.gd`(`@tool` + `extends McpTestSuite`,
|
||||||
|
`print` 抓不到,得用 `FileAccess` 写文件)里读
|
||||||
|
`EditorInterface.get_editor_viewport_3d(0).get_camera_3d().global_transform`,
|
||||||
|
再 `test_run` 执行,就能拿到确切机位/ FOV。本项目的 sofa 机位是
|
||||||
|
`origin(-12.070005, 4.639197, -2.615989)`,`fov 70.01`,视口 1364×772。
|
||||||
|
6. 注意 main2 的「联机测试」UI 是 **autoload(`autoload/net.tscn`)**,不在场景树里,
|
||||||
|
探针要递归隐藏 `get_tree().root` 下的 `CanvasLayer`/`Control` 才遮不掉画面。
|
||||||
|
|
||||||
## 坐标系陷阱 + 上游着色器的边界(重要)
|
## 坐标系陷阱 + 上游着色器的边界(重要)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 298 KiB |
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://8dkvgo8t86i7"
|
||||||
|
path="res://.godot/imported/shadow_aliasing_fix.png-90fbb6b0ee035578f4d87eb80f997b80.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://docs/shadow_aliasing_fix.png"
|
||||||
|
dest_files=["res://.godot/imported/shadow_aliasing_fix.png-90fbb6b0ee035578f4d87eb80f997b80.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 588 KiB |
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://biohx0p58nu3e"
|
||||||
|
path="res://.godot/imported/shadow_normal_bias_fix.png-a5221ab9757e81767db17f6acdff4abe.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://docs/shadow_normal_bias_fix.png"
|
||||||
|
dest_files=["res://.godot/imported/shadow_normal_bias_fix.png-a5221ab9757e81767db17f6acdff4abe.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
+8
-5
@@ -102,26 +102,29 @@ throw_carry={
|
|||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
rendering_device/driver.windows="d3d12"
|
rendering_device/driver.windows="d3d12"
|
||||||
|
lights_and_shadows/directional_shadow/soft_shadow_filter_quality=4
|
||||||
|
lights_and_shadows/positional_shadow/soft_shadow_filter_quality=4
|
||||||
|
anti_aliasing/quality/msaa_3d=2
|
||||||
|
|
||||||
[shader_globals]
|
[shader_globals]
|
||||||
|
|
||||||
diffuse_curve={
|
diffuse_curve={
|
||||||
"type": "sampler2D",
|
"type": "sampler2D",
|
||||||
"value": "res://shader/new_gradient_texture_1d.tres"
|
"value": "res://shader/toon_ramp_1d.tres"
|
||||||
}
|
}
|
||||||
specular_smoothness={
|
specular_smoothness={
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 10.0
|
"value": 0.08
|
||||||
}
|
}
|
||||||
fresnel_smoothness={
|
fresnel_smoothness={
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 0.05
|
"value": 0.12
|
||||||
}
|
}
|
||||||
outline_width={
|
outline_width={
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 2.0
|
"value": 10.0
|
||||||
}
|
}
|
||||||
outline_color={
|
outline_color={
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"value": Color(0.0253638, 0.0253638, 0.025363795, 1)
|
"value": Color(0.08, 0.07, 0.1, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
[gd_resource type="GradientTexture1D" format=3 uid="uid://b3fs6dwpeg753"]
|
|
||||||
|
|
||||||
[sub_resource type="Gradient" id="Gradient_lxrd8"]
|
|
||||||
offsets = PackedFloat32Array(0.12706612, 0.13946281, 0.5041322, 0.52272725)
|
|
||||||
colors = PackedColorArray(0, 0, 0, 1, 0, 0, 0, 1, 0.19793734, 0.19793719, 0.19793719, 1, 1, 1, 1, 1)
|
|
||||||
|
|
||||||
[resource]
|
|
||||||
gradient = SubResource("Gradient_lxrd8")
|
|
||||||
+1
-1
@@ -12,7 +12,7 @@ render_priority = 0
|
|||||||
next_pass = SubResource("ShaderMaterial_m5gih")
|
next_pass = SubResource("ShaderMaterial_m5gih")
|
||||||
shader = ExtResource("2_63a2j")
|
shader = ExtResource("2_63a2j")
|
||||||
shader_parameter/color = Color(1, 1, 1, 1)
|
shader_parameter/color = Color(1, 1, 1, 1)
|
||||||
shader_parameter/specular = Color(0, 0, 0, 0.5019608)
|
shader_parameter/specular = Color(0.12, 0.12, 0.12, 0.45)
|
||||||
shader_parameter/fresnel = Color(0, 0, 0, 0.3019608)
|
shader_parameter/fresnel = Color(0, 0, 0, 0.3019608)
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
shader_parameter/uv_scale = Vector2(1, 1)
|
||||||
shader_parameter/uv_offset = Vector2(0, 0)
|
shader_parameter/uv_offset = Vector2(0, 0)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[gd_resource type="GradientTexture1D" format=3 uid="uid://bl3hlhokeshiv"]
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_cel"]
|
||||||
|
offsets = PackedFloat32Array(0.056254625, 0.2638786, 0.3815692, 0.5980755, 0.6195411)
|
||||||
|
colors = PackedColorArray(0.24, 0.24, 0.24, 1, 0.24, 0.24, 0.24, 1, 0.6, 0.6, 0.6, 1, 0.6, 0.6, 0.6, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
gradient = SubResource("Gradient_cel")
|
||||||
@@ -12,6 +12,7 @@ const PLAYER_GROUP: String = "net_player"
|
|||||||
const NET_PATH: String = "/root/Net"
|
const NET_PATH: String = "/root/Net"
|
||||||
|
|
||||||
@onready var spawner: MultiplayerSpawner = $MultiplayerSpawner
|
@onready var spawner: MultiplayerSpawner = $MultiplayerSpawner
|
||||||
|
@onready var player_spawn_pos: Node3D = $PlayerSpawnPos
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@@ -28,6 +29,7 @@ func _ready() -> void:
|
|||||||
## recursive=true 很关键 —— 节点 authority 不自动继承,Sync 子节点必须一起设。
|
## recursive=true 很关键 —— 节点 authority 不自动继承,Sync 子节点必须一起设。
|
||||||
func _create_player(peer_id: int) -> Node:
|
func _create_player(peer_id: int) -> Node:
|
||||||
var player := player_scene.instantiate()
|
var player := player_scene.instantiate()
|
||||||
|
player.global_position = player_spawn_pos.global_position
|
||||||
player.name = str(peer_id)
|
player.name = str(peer_id)
|
||||||
player.add_to_group(PLAYER_GROUP)
|
player.add_to_group(PLAYER_GROUP)
|
||||||
player.set_multiplayer_authority(peer_id, true)
|
player.set_multiplayer_authority(peer_id, true)
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
script = ExtResource("1_hyim0")
|
script = ExtResource("1_hyim0")
|
||||||
player_scene = ExtResource("2_4f7fj")
|
player_scene = ExtResource("2_4f7fj")
|
||||||
|
|
||||||
|
[node name="PlayerSpawnPos" type="Node3D" parent="." unique_id=1214822657]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.001055, 4.8038387, -7.0077953)
|
||||||
|
|
||||||
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="." unique_id=1020023513]
|
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="." unique_id=1020023513]
|
||||||
spawn_path = NodePath("..")
|
spawn_path = NodePath("..")
|
||||||
|
|
||||||
|
|||||||
+59
-17
@@ -6,6 +6,7 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://f6x6cxnaxj4s" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Walls/TEST_WALL.glb" id="4_vnhc7"]
|
[ext_resource type="PackedScene" uid="uid://f6x6cxnaxj4s" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Walls/TEST_WALL.glb" id="4_vnhc7"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cxxl2o4g5wpx2" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Walls/woman.glb" id="5_7oi24"]
|
[ext_resource type="PackedScene" uid="uid://cxxl2o4g5wpx2" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Walls/woman.glb" id="5_7oi24"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bklyqsj4831ma" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Rug/SM_Rug_1_04.fbx" id="5_kcwpv"]
|
[ext_resource type="PackedScene" uid="uid://bklyqsj4831ma" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Rug/SM_Rug_1_04.fbx" id="5_kcwpv"]
|
||||||
|
[ext_resource type="Sky" uid="uid://bi632suyifms5" path="res://world/sky/cartoon_sky.tres" id="6_cartoon"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dt4wcr14jknfd" path="res://assets/Cute_Furniture_Free_glb/Separate_Assets_glb/Kitchen_Table_09.glb" id="6_mt6fc"]
|
[ext_resource type="PackedScene" uid="uid://dt4wcr14jknfd" path="res://assets/Cute_Furniture_Free_glb/Separate_Assets_glb/Kitchen_Table_09.glb" id="6_mt6fc"]
|
||||||
[ext_resource type="PackedScene" uid="uid://f7w6uyre6d1a" path="res://assets/Cute_Furniture_Free_glb/Separate_Assets_glb/Couch_08.glb" id="7_7n6vr"]
|
[ext_resource type="PackedScene" uid="uid://f7w6uyre6d1a" path="res://assets/Cute_Furniture_Free_glb/Separate_Assets_glb/Couch_08.glb" id="7_7n6vr"]
|
||||||
[ext_resource type="PackedScene" uid="uid://6hduvpmmt22v" path="res://assets/Furniture_FREE-af040129/SM_Commode_7.glb" id="10_gb6bm"]
|
[ext_resource type="PackedScene" uid="uid://6hduvpmmt22v" path="res://assets/Furniture_FREE-af040129/SM_Commode_7.glb" id="10_gb6bm"]
|
||||||
@@ -158,19 +159,46 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://bid0g7ha0t6l6" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Walls/wall_White.glb" id="159_tyxef"]
|
[ext_resource type="PackedScene" uid="uid://bid0g7ha0t6l6" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Walls/wall_White.glb" id="159_tyxef"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bjbkx10uyjfsh" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Floor/floor1.glb" id="160_cvvfq"]
|
[ext_resource type="PackedScene" uid="uid://bjbkx10uyjfsh" path="res://assets/FreeLowPolyHouseInterior_NoAlpha/General/Floor/floor1.glb" id="160_cvvfq"]
|
||||||
|
|
||||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_theme"]
|
|
||||||
sky_horizon_color = Color(0.66224277, 0.6717428, 0.6867428, 1)
|
|
||||||
ground_horizon_color = Color(0.66224277, 0.6717428, 0.6867428, 1)
|
|
||||||
|
|
||||||
[sub_resource type="Sky" id="Sky_2xwvw"]
|
|
||||||
sky_material = SubResource("ProceduralSkyMaterial_theme")
|
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_tyxef"]
|
[sub_resource type="Environment" id="Environment_tyxef"]
|
||||||
background_mode = 2
|
background_mode = 2
|
||||||
sky = SubResource("Sky_2xwvw")
|
sky = ExtResource("6_cartoon")
|
||||||
|
ambient_light_source = 3
|
||||||
|
ambient_light_color = Color(0.3, 0.38, 0.55, 1)
|
||||||
|
ambient_light_sky_contribution = 0.45
|
||||||
|
ambient_light_energy = 0.5
|
||||||
|
reflected_light_source = 2
|
||||||
|
tonemap_mode = 3
|
||||||
|
tonemap_exposure = 1.05
|
||||||
ssao_enabled = true
|
ssao_enabled = true
|
||||||
|
ssao_radius = 1.2
|
||||||
|
ssao_intensity = 1.0
|
||||||
|
ssao_detail = 0.3
|
||||||
|
ssao_horizon = 0.05
|
||||||
|
ssao_sharpness = 0.5
|
||||||
glow_enabled = true
|
glow_enabled = true
|
||||||
glow_strength = 0.5
|
glow_levels/3 = 0.6
|
||||||
|
glow_levels/4 = 0.25
|
||||||
|
glow_normalized = true
|
||||||
|
glow_intensity = 0.05
|
||||||
|
glow_hdr_threshold = 2.2
|
||||||
|
glow_hdr_scale = 1.5
|
||||||
|
fog_enabled = true
|
||||||
|
fog_light_color = Color(0.72, 0.82, 0.95, 1)
|
||||||
|
fog_light_energy = 0.8
|
||||||
|
fog_sun_scatter = 0.1
|
||||||
|
fog_density = 0.004
|
||||||
|
fog_aerial_perspective = 0.3
|
||||||
|
fog_sky_affect = 0.2
|
||||||
|
volumetric_fog_enabled = true
|
||||||
|
volumetric_fog_density = 0.015
|
||||||
|
volumetric_fog_albedo = Color(0.8289096, 0.82890964, 0.82890975, 1)
|
||||||
|
volumetric_fog_emission_energy = 0.0
|
||||||
|
volumetric_fog_length = 62.55
|
||||||
|
volumetric_fog_ambient_inject = 1.0
|
||||||
|
volumetric_fog_sky_affect = 0.555
|
||||||
|
adjustment_enabled = true
|
||||||
|
adjustment_contrast = 1.12
|
||||||
|
adjustment_saturation = 1.08
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_tyxef"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_tyxef"]
|
||||||
render_priority = 0
|
render_priority = 0
|
||||||
@@ -180,9 +208,9 @@ shader = ExtResource("154_hkjiw")
|
|||||||
render_priority = 0
|
render_priority = 0
|
||||||
next_pass = SubResource("ShaderMaterial_tyxef")
|
next_pass = SubResource("ShaderMaterial_tyxef")
|
||||||
shader = ExtResource("155_theme")
|
shader = ExtResource("155_theme")
|
||||||
shader_parameter/color = Color(0.5251013, 0.5251013, 0.5251012, 1)
|
shader_parameter/color = Color(0.68, 0.68, 0.68, 1)
|
||||||
shader_parameter/base_texture = ExtResource("156_2xwvw")
|
shader_parameter/base_texture = ExtResource("156_2xwvw")
|
||||||
shader_parameter/specular = Color(0, 0, 0, 0.5019608)
|
shader_parameter/specular = Color(0.12, 0.12, 0.12, 0.45)
|
||||||
shader_parameter/fresnel = Color(0, 0, 0, 0.3019608)
|
shader_parameter/fresnel = Color(0, 0, 0, 0.3019608)
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
shader_parameter/uv_scale = Vector2(1, 1)
|
||||||
shader_parameter/uv_offset = Vector2(0, 0)
|
shader_parameter/uv_offset = Vector2(0, 0)
|
||||||
@@ -193,8 +221,16 @@ shader_parameter/uv_offset = Vector2(0, 0)
|
|||||||
environment = SubResource("Environment_tyxef")
|
environment = SubResource("Environment_tyxef")
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1063626102]
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1063626102]
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.25, 0, 0.49999997, 0.86602545, -0.50000006, 0.75, -0.43301266, 0, 0, 0)
|
transform = Transform3D(1, 0, 0, 0, 0.60483766, 0.7963488, 0, -0.7963488, 0.60483766, 0, 6.067111, 0)
|
||||||
|
light_color = Color(1, 0.925, 0.83, 1)
|
||||||
|
light_energy = 0.95
|
||||||
|
light_indirect_energy = 0.8
|
||||||
|
light_specular = 0.0
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
|
shadow_transmittance_bias = 3.193
|
||||||
|
directional_shadow_blend_splits = true
|
||||||
|
directional_shadow_fade_start = 0.9
|
||||||
|
directional_shadow_max_distance = 45.0
|
||||||
|
|
||||||
[node name="CSG" type="Node3D" parent="." unique_id=1111955109]
|
[node name="CSG" type="Node3D" parent="." unique_id=1111955109]
|
||||||
|
|
||||||
@@ -205,12 +241,18 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.7806181, 3.5406704, -1.173
|
|||||||
|
|
||||||
[node name="sconce" type="SpotLight3D" parent="Light" unique_id=1610519654]
|
[node name="sconce" type="SpotLight3D" parent="Light" unique_id=1610519654]
|
||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.496, 6.8725104, 16.683495)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.496, 6.8725104, 16.683495)
|
||||||
light_color = Color(1, 0.77066666, 0.57, 1)
|
light_color = Color(1, 0.78, 0.56, 1)
|
||||||
light_energy = 2.655
|
light_energy = 3.2
|
||||||
light_indirect_energy = 2.41
|
light_indirect_energy = 0.8
|
||||||
light_size = 0.1
|
light_volumetric_fog_energy = 1.5
|
||||||
light_specular = 1.27
|
light_size = 0.15
|
||||||
|
light_specular = 0.6
|
||||||
light_bake_mode = 1
|
light_bake_mode = 1
|
||||||
|
shadow_enabled = true
|
||||||
|
spot_range = 12.0
|
||||||
|
spot_attenuation = 1.2
|
||||||
|
spot_angle = 55.0
|
||||||
|
spot_angle_attenuation = 1.4
|
||||||
|
|
||||||
[node name="model" type="Node3D" parent="." unique_id=687260403]
|
[node name="model" type="Node3D" parent="." unique_id=687260403]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user