diff --git a/.workbuddy/memory/2026-10-15.md b/.workbuddy/memory/2026-10-15.md index 41ad3cd..67693eb 100644 --- a/.workbuddy/memory/2026-10-15.md +++ b/.workbuddy/memory/2026-10-15.md @@ -60,3 +60,146 @@ 立即 return,没有这个窗口)。 6. 无头模拟按键:`Input.action_press` 只改动作状态、**不发输入事件**(Motor 的跳跃缓冲在 `_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`。 + diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 53f2f2b..76ff21f 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -46,10 +46,92 @@ Godot 4.7.2(Forward+,Jolt Physics,D3D12)。编辑器位于 - `shader/toon_apply.gd`(@tool Node3D)给每个 MeshInstance3D 复制一份独立材质, 因为**每个模型有各自的贴图**,所以必须独立(不能共享一份材质)。 - 已在项目设置里用了 **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² 混杂), 因此**不适合** Texture2DArray + per-instance uniform 方案(显存会爆且要额外打包流水线)。 - 编辑器插件 `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 --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` 才遮不掉画面。 ## 坐标系陷阱 + 上游着色器的边界(重要) diff --git a/docs/shadow_aliasing_fix.png b/docs/shadow_aliasing_fix.png new file mode 100644 index 0000000..e6c9dc3 Binary files /dev/null and b/docs/shadow_aliasing_fix.png differ diff --git a/docs/shadow_aliasing_fix.png.import b/docs/shadow_aliasing_fix.png.import new file mode 100644 index 0000000..2ff474d --- /dev/null +++ b/docs/shadow_aliasing_fix.png.import @@ -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 diff --git a/docs/shadow_normal_bias_fix.png b/docs/shadow_normal_bias_fix.png new file mode 100644 index 0000000..666b22a Binary files /dev/null and b/docs/shadow_normal_bias_fix.png differ diff --git a/docs/shadow_normal_bias_fix.png.import b/docs/shadow_normal_bias_fix.png.import new file mode 100644 index 0000000..f3f26d9 --- /dev/null +++ b/docs/shadow_normal_bias_fix.png.import @@ -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 diff --git a/project.godot b/project.godot index 4de98fb..514407c 100644 --- a/project.godot +++ b/project.godot @@ -102,26 +102,29 @@ throw_carry={ [rendering] 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] diffuse_curve={ "type": "sampler2D", -"value": "res://shader/new_gradient_texture_1d.tres" +"value": "res://shader/toon_ramp_1d.tres" } specular_smoothness={ "type": "float", -"value": 10.0 +"value": 0.08 } fresnel_smoothness={ "type": "float", -"value": 0.05 +"value": 0.12 } outline_width={ "type": "float", -"value": 2.0 +"value": 10.0 } outline_color={ "type": "color", -"value": Color(0.0253638, 0.0253638, 0.025363795, 1) +"value": Color(0.08, 0.07, 0.1, 1) } diff --git a/shader/new_gradient_texture_1d.tres b/shader/new_gradient_texture_1d.tres deleted file mode 100644 index 9bca4b4..0000000 --- a/shader/new_gradient_texture_1d.tres +++ /dev/null @@ -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") diff --git a/shader/toon.tres b/shader/toon.tres index 30bdb63..27937dc 100644 --- a/shader/toon.tres +++ b/shader/toon.tres @@ -12,7 +12,7 @@ render_priority = 0 next_pass = SubResource("ShaderMaterial_m5gih") shader = ExtResource("2_63a2j") 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/uv_scale = Vector2(1, 1) shader_parameter/uv_offset = Vector2(0, 0) diff --git a/shader/toon_ramp_1d.tres b/shader/toon_ramp_1d.tres new file mode 100644 index 0000000..2209a1e --- /dev/null +++ b/shader/toon_ramp_1d.tres @@ -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") diff --git a/world/main.gd b/world/main.gd index 6628efe..25c33d2 100644 --- a/world/main.gd +++ b/world/main.gd @@ -12,6 +12,7 @@ const PLAYER_GROUP: String = "net_player" const NET_PATH: String = "/root/Net" @onready var spawner: MultiplayerSpawner = $MultiplayerSpawner +@onready var player_spawn_pos: Node3D = $PlayerSpawnPos func _ready() -> void: @@ -28,6 +29,7 @@ func _ready() -> void: ## recursive=true 很关键 —— 节点 authority 不自动继承,Sync 子节点必须一起设。 func _create_player(peer_id: int) -> Node: var player := player_scene.instantiate() + player.global_position = player_spawn_pos.global_position player.name = str(peer_id) player.add_to_group(PLAYER_GROUP) player.set_multiplayer_authority(peer_id, true) diff --git a/world/main.tscn b/world/main.tscn index b281c8d..b1ae1dd 100644 --- a/world/main.tscn +++ b/world/main.tscn @@ -8,6 +8,9 @@ script = ExtResource("1_hyim0") 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] spawn_path = NodePath("..") diff --git a/world/main2.tscn b/world/main2.tscn index 3610165..a25b1d6 100644 --- a/world/main2.tscn +++ b/world/main2.tscn @@ -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://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="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://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"] @@ -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://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"] 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_radius = 1.2 +ssao_intensity = 1.0 +ssao_detail = 0.3 +ssao_horizon = 0.05 +ssao_sharpness = 0.5 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"] render_priority = 0 @@ -180,9 +208,9 @@ shader = ExtResource("154_hkjiw") render_priority = 0 next_pass = SubResource("ShaderMaterial_tyxef") 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/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/uv_scale = Vector2(1, 1) shader_parameter/uv_offset = Vector2(0, 0) @@ -193,8 +221,16 @@ shader_parameter/uv_offset = Vector2(0, 0) environment = SubResource("Environment_tyxef") [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_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] @@ -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] 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_energy = 2.655 -light_indirect_energy = 2.41 -light_size = 0.1 -light_specular = 1.27 +light_color = Color(1, 0.78, 0.56, 1) +light_energy = 3.2 +light_indirect_energy = 0.8 +light_volumetric_fog_energy = 1.5 +light_size = 0.15 +light_specular = 0.6 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]