diff --git a/.workbuddy/memory/2026-10-13.md b/.workbuddy/memory/2026-10-13.md new file mode 100644 index 0000000..3bd44df --- /dev/null +++ b/.workbuddy/memory/2026-10-13.md @@ -0,0 +1,25 @@ +# 2026-10-13 工作日志 + +## 修复:toon 材质所有模型联动、无法单独设基础纹理 + +**问题**:`shader/toon_apply.gd` 用 `material_override = toon.tres` 把同一个共享 `ShaderMaterial` 实例挂给所有 `MeshInstance3D`,导致 +1. 改 `toon.tres` 影响全部模型; +2. `material_override` 整包覆盖,丢失模型自带贴图,无法给单个模型设 `base_texture`。 + +**方案**:重写 `shader/toon_apply.gd` +- 为每个 `MeshInstance3D` 的每个 surface **复制独立材质实例**(`cartoon_material.duplicate()`,含 `next_pass` 描边的复制),通过 `set_surface_override_material(i, mat)` 逐面挂载。 +- 自动从 `mesh.surface_get_material(i)` 提取原始贴图(`BaseMaterial3D.albedo_texture` 或已有 ShaderMaterial 的 `base_texture`)写入各自的 `base_texture`。 +- 新增导出项:`base_texture_override`(手动指定单模型贴图,优先级最高)、`use_original_texture`、`use_material_override`(兼容旧整包模式,默认关)。 +- `toon.tres` 降级为"模板":脚本每次应用时拷贝其非贴图参数作为初值,之后各模型独立。 + +**关键文件**:`shader/toon_apply.gd`(uid 未变,场景引用 `assets/test/test.tscn` 仍有效) +**相关**:`shader/toon.tres`(基础 cel-shader + outline next_pass)、`shader/cel-shader-base.gdshader`、`shader/outline.gdshader`(outline 用 global uniform,全局限定) + +## 修复报错:`get_shader_uniform_list` 不存在 + +- 报错:`Nonexistent function 'get_shader_uniform_list' in base 'ShaderMaterial'`。 +- 原因:该方法属于 **`Shader`**,不属于 `ShaderMaterial`。 +- 修复:改为 `cartoon_material.shader.get_shader_uniform_list()`(先判空)。 +- 同时把 `get_surface_override_material(mi.material_override)` 返回的 `Material` 用显式 `is ShaderMaterial` 判断 + 声明式 `var x: ShaderMaterial` 赋值,避免隐式向下转换告警。 +- 环境:Godot 4.7,Forward Plus,config_version=5。本机未找到 Godot CLI,无法自动语法校验。 + diff --git a/assets/test/test.tscn b/assets/test/test.tscn index 33af91a..cde0b5a 100644 --- a/assets/test/test.tscn +++ b/assets/test/test.tscn @@ -1,7 +1,11 @@ [gd_scene format=3 uid="uid://ouhrovtvstsf"] -[ext_resource type="PackedScene" uid="uid://dh5ej8olhdv5x" path="res://assets/Furniture_FREE-af040129/SM_Bottle_1.glb" id="1_0vnai"] +[ext_resource type="Script" uid="uid://cyabo07rc0216" path="res://shader/toon_apply.gd" id="2_7gofs"] +[ext_resource type="Material" uid="uid://ps5swh44egxb" path="res://shader/toon.tres" id="3_pd47h"] +[ext_resource type="PackedScene" uid="uid://ifqfine3ofh2" path="res://assets/test/HotDog.glb" id="4_pd47h"] [node name="Node3D" type="Node3D" unique_id=301733971] -[node name="SM_Bottle_12" parent="." unique_id=56545120 instance=ExtResource("1_0vnai")] +[node name="HotDog2" parent="." unique_id=1370529729 instance=ExtResource("4_pd47h")] +script = ExtResource("2_7gofs") +cartoon_material = ExtResource("3_pd47h") diff --git a/shader/toon.tres b/shader/toon.tres index d7aa00a..242ee07 100644 --- a/shader/toon.tres +++ b/shader/toon.tres @@ -2,7 +2,6 @@ [ext_resource type="Shader" uid="uid://bbs8x8ygec4lo" path="res://shader/outline.gdshader" id="1_vdkh7"] [ext_resource type="Shader" uid="uid://wepsb3f7nni" path="res://shader/cel-shader-base.gdshader" id="2_63a2j"] -[ext_resource type="Texture2D" uid="uid://b353hjk53b3ob" path="res://assets/Food Pack - Low Poly Assets/Can_PaletteAssets.png" id="3_63a2j"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_m5gih"] render_priority = 0 @@ -12,8 +11,7 @@ shader = ExtResource("1_vdkh7") render_priority = 0 next_pass = SubResource("ShaderMaterial_m5gih") shader = ExtResource("2_63a2j") -shader_parameter/color = Color(0.7, 0.12, 0.86, 1) -shader_parameter/base_texture = ExtResource("3_63a2j") +shader_parameter/color = Color(1, 1, 1, 1) shader_parameter/specular = Color(0.3, 0.3, 0.3, 0.5) shader_parameter/fresnel = Color(0.2, 0.2, 0.2, 0.3) shader_parameter/uv_scale = Vector2(1, 1) diff --git a/shader/toon_apply.gd b/shader/toon_apply.gd index 416c244..93fc2b2 100644 --- a/shader/toon_apply.gd +++ b/shader/toon_apply.gd @@ -1,25 +1,62 @@ @tool extends Node3D -const ToonApply = preload("res://shader/toon_apply.gd") - +@export var refresh_now: bool = false: + set(value): + if value: + refresh_now = false # 自动弹回 + _apply_materials() @export var cartoon_material: ShaderMaterial: set(value): cartoon_material = value _apply_materials() - +@export_group("Instance Overrides") +@export var use_custom_color: bool = false: + set(value): + use_custom_color = value + _apply_materials() +@export var custom_color: Color = Color(1, 1, 1, 1): + set(value): + custom_color = value + if use_custom_color: # 只有开启时才实时刷新 + _apply_materials() + func _ready() -> void: _apply_materials() - + func _apply_materials(): - if not is_inside_tree(): + if not is_inside_tree() or cartoon_material == null: return - # 未指定时默认使用 ToonApply - var mat: Material = cartoon_material if cartoon_material != null else ToonApply as Material - for node in find_children("*", "MeshInstance3D", true, false): - if node is MeshInstance3D: - node.material_override = mat + if not node is MeshInstance3D: + continue + + # 1. 复制一份全新的独立材质,它自带模板 (toon.tres) 的默认颜色和贴图 + var unique_mat = cartoon_material.duplicate() + + # 2. 安全地获取原模型自带的贴图,并赋给独立材质 + if node.mesh != null and node.mesh.get_surface_count() > 0: + var original_mat = node.mesh.surface_get_material(0) + if original_mat != null: + var final_tex: Texture2D = null + # 兼容 StandardMaterial3D + if original_mat is StandardMaterial3D: + final_tex = original_mat.albedo_texture + # 兼容原模型自带的其他 ShaderMaterial(如从 Blender 导入的材质) + elif original_mat.has_method("get_shader_parameter"): + final_tex = original_mat.get_shader_parameter("base_texture") + + if final_tex != null: + unique_mat.set_shader_parameter("base_texture", final_tex) + + # 3. 处理颜色覆盖 + # 如果勾选了自定义颜色,直接在独立材质上修改 + # 如果没勾选,则什么都不做,保留从模板复制来的默认颜色 + if use_custom_color: + unique_mat.set_shader_parameter("color", custom_color) + + # 4. 最后,把配置好的独立材质一次性赋予模型 + node.material_override = unique_mat