Merge branch 'wl/gameplay/WL-814x-pixel-uv'

This commit is contained in:
깃 관리자 2026-09-13 01:58:33 +09:00
commit ee80a907b6
72 changed files with 6805 additions and 0 deletions

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=FINAL ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504 · srcBW 468 newBW 504 bindposes 63 normals 504 tangents 504
mesh Body_m05 verts 604 -> 703 · srcBW 604 newBW 703 bindposes 40 normals 703 tangents 703
mesh Hair05 verts 611 -> 647 · srcBW 611 newBW 647 bindposes 1 normals 647 tangents 647
mesh Head verts 339 -> 339 · srcBW 339 newBW 339 bindposes 1 normals 339 tangents 339
mesh Leg_M05 verts 498 -> 583 · srcBW 498 newBW 583 bindposes 29 normals 583 tangents 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=best ===
faces 4076
regions 40 (target 40)
Arm_m05 : 10
Body_m05 : 10
Hair05 : 13
Head : 2
Leg_M05 : 5
palette 16 · dHue mean 1.06 max 5.15
mesh Arm_m05 verts 468 -> 538
mesh Body_m05 verts 604 -> 682
mesh Hair05 verts 611 -> 638
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 536

View File

@ -0,0 +1,14 @@
=== bake chunks=20 palette=10 tag=c20p10 ===
faces 4076
regions 21 (target 20)
Arm_m05 : 2
Body_m05 : 5
Hair05 : 10
Head : 2
Leg_M05 : 2
palette 10 · dHue mean 1.17 max 4.98
mesh Arm_m05 verts 468 -> 468
mesh Body_m05 verts 604 -> 604
mesh Hair05 verts 611 -> 611
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 507

View File

@ -0,0 +1,14 @@
=== bake chunks=20 palette=16 tag=c20p16 ===
faces 4076
regions 21 (target 20)
Arm_m05 : 2
Body_m05 : 5
Hair05 : 10
Head : 2
Leg_M05 : 2
palette 16 · dHue mean 1.06 max 4.58
mesh Arm_m05 verts 468 -> 468
mesh Body_m05 verts 604 -> 604
mesh Hair05 verts 611 -> 611
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 507

View File

@ -0,0 +1,14 @@
=== bake chunks=20 palette=24 tag=c20p24 ===
faces 4076
regions 21 (target 20)
Arm_m05 : 2
Body_m05 : 5
Hair05 : 10
Head : 2
Leg_M05 : 2
palette 21 · dHue mean 1.06 max 4.58
mesh Arm_m05 verts 468 -> 468
mesh Body_m05 verts 604 -> 604
mesh Hair05 verts 611 -> 611
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 507

View File

@ -0,0 +1,14 @@
=== bake chunks=20 palette=32 tag=c20p32 ===
faces 4076
regions 21 (target 20)
Arm_m05 : 2
Body_m05 : 5
Hair05 : 10
Head : 2
Leg_M05 : 2
palette 21 · dHue mean 1.06 max 4.58
mesh Arm_m05 verts 468 -> 468
mesh Body_m05 verts 604 -> 604
mesh Hair05 verts 611 -> 611
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 507

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=10 tag=c40p10 ===
faces 4076
regions 40 (target 40)
Arm_m05 : 10
Body_m05 : 10
Hair05 : 13
Head : 2
Leg_M05 : 5
palette 10 · dHue mean 1.20 max 5.76
mesh Arm_m05 verts 468 -> 538
mesh Body_m05 verts 604 -> 682
mesh Hair05 verts 611 -> 638
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 536

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=c40p16 ===
faces 4076
regions 40 (target 40)
Arm_m05 : 10
Body_m05 : 10
Hair05 : 13
Head : 2
Leg_M05 : 5
palette 16 · dHue mean 1.06 max 5.15
mesh Arm_m05 verts 468 -> 538
mesh Body_m05 verts 604 -> 682
mesh Hair05 verts 611 -> 638
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 536

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=24 tag=c40p24 ===
faces 4076
regions 40 (target 40)
Arm_m05 : 10
Body_m05 : 10
Hair05 : 13
Head : 2
Leg_M05 : 5
palette 24 · dHue mean 0.53 max 3.58
mesh Arm_m05 verts 468 -> 538
mesh Body_m05 verts 604 -> 682
mesh Hair05 verts 611 -> 642
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 536

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=32 tag=c40p32 ===
faces 4076
regions 40 (target 40)
Arm_m05 : 10
Body_m05 : 10
Hair05 : 13
Head : 2
Leg_M05 : 5
palette 32 · dHue mean 0.50 max 2.37
mesh Arm_m05 verts 468 -> 538
mesh Body_m05 verts 604 -> 682
mesh Hair05 verts 611 -> 642
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 536

View File

@ -0,0 +1,14 @@
=== bake chunks=80 palette=10 tag=c80p10 ===
faces 4076
regions 80 (target 80)
Arm_m05 : 14
Body_m05 : 22
Hair05 : 28
Head : 2
Leg_M05 : 14
palette 10 · dHue mean 1.47 max 16.74
mesh Arm_m05 verts 468 -> 576
mesh Body_m05 verts 604 -> 789
mesh Hair05 verts 611 -> 751
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 614

View File

@ -0,0 +1,14 @@
=== bake chunks=80 palette=16 tag=c80p16 ===
faces 4076
regions 80 (target 80)
Arm_m05 : 14
Body_m05 : 22
Hair05 : 28
Head : 2
Leg_M05 : 14
palette 16 · dHue mean 1.16 max 16.86
mesh Arm_m05 verts 468 -> 576
mesh Body_m05 verts 604 -> 801
mesh Hair05 verts 611 -> 751
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 634

View File

@ -0,0 +1,14 @@
=== bake chunks=80 palette=24 tag=c80p24 ===
faces 4076
regions 80 (target 80)
Arm_m05 : 14
Body_m05 : 22
Hair05 : 28
Head : 2
Leg_M05 : 14
palette 24 · dHue mean 0.67 max 16.86
mesh Arm_m05 verts 468 -> 576
mesh Body_m05 verts 604 -> 801
mesh Hair05 verts 611 -> 751
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 652

View File

@ -0,0 +1,14 @@
=== bake chunks=80 palette=32 tag=c80p32 ===
faces 4076
regions 80 (target 80)
Arm_m05 : 14
Body_m05 : 22
Hair05 : 28
Head : 2
Leg_M05 : 14
palette 32 · dHue mean 0.54 max 16.86
mesh Arm_m05 verts 468 -> 576
mesh Body_m05 verts 604 -> 801
mesh Hair05 verts 611 -> 752
mesh Head verts 339 -> 383
mesh Leg_M05 verts 498 -> 652

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=g_g0none ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504
mesh Body_m05 verts 604 -> 703
mesh Hair05 verts 611 -> 647
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=g_g1soft ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504
mesh Body_m05 verts 604 -> 703
mesh Hair05 verts 611 -> 647
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=g_g2hard ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504
mesh Body_m05 verts 604 -> 703
mesh Hair05 verts 611 -> 647
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=g_g3sat ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504
mesh Body_m05 verts 604 -> 703
mesh Hair05 verts 611 -> 647
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=idm ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504 · srcBW 468 newBW 504 bindposes 63 normals 504 tangents 504
mesh Body_m05 verts 604 -> 703 · srcBW 604 newBW 703 bindposes 40 normals 703 tangents 703
mesh Hair05 verts 611 -> 647 · srcBW 611 newBW 647 bindposes 1 normals 647 tangents 647
mesh Head verts 339 -> 339 · srcBW 339 newBW 339 bindposes 1 normals 339 tangents 339
mesh Leg_M05 verts 498 -> 583 · srcBW 498 newBW 583 bindposes 29 normals 583 tangents 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=memchk ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504 · srcBW 468 newBW 504 bindposes 63 normals 504 tangents 504
mesh Body_m05 verts 604 -> 703 · srcBW 604 newBW 703 bindposes 40 normals 703 tangents 703
mesh Hair05 verts 611 -> 647 · srcBW 611 newBW 647 bindposes 1 normals 647 tangents 647
mesh Head verts 339 -> 339 · srcBW 339 newBW 339 bindposes 1 normals 339 tangents 339
mesh Leg_M05 verts 498 -> 583 · srcBW 498 newBW 583 bindposes 29 normals 583 tangents 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=v_linNos ===
faces 4076
regions 40 (target 40)
Arm_m05 : 12
Body_m05 : 11
Hair05 : 10
Head : 2
Leg_M05 : 5
palette 16 · dHue mean 0.98 max 7.29
mesh Arm_m05 verts 468 -> 554
mesh Body_m05 verts 604 -> 697
mesh Hair05 verts 611 -> 611
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 536

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=v_srgbNos ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504
mesh Body_m05 verts 604 -> 703
mesh Hair05 verts 611 -> 647
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 583

View File

@ -0,0 +1,14 @@
=== bake chunks=40 palette=16 tag=v_srgbSat ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504
mesh Body_m05 verts 604 -> 703
mesh Hair05 verts 611 -> 647
mesh Head verts 339 -> 339
mesh Leg_M05 verts 498 -> 583

View File

@ -0,0 +1,19 @@
setup: char bounds (0.648, 1.217, 0.907) · 화면 키 117 px · 포즈 yaw 240
SO: enabled_=1 mode=3
ApplyMode(3): mode 3 · 렌더러 6 · 슬롯 6
slot Arm_m05 = M05_ToonF
slot Body_m05 = M05_ToonF
slot Face = face02_ToonF
slot Hair05 = Hair05_ToonF
slot Head = Skin_ToonF
slot Leg_M05 = M05_ToonF
mask Arm_m05 = 335 px
mask Body_m05 = 975 px
mask Face = 47 px
mask Hair05 = 1154 px
mask Head = 1047 px
mask Leg_M05 = 729 px
mask all = 2996 px
mask body3 = 1756 px
c0 Ⓐ136 Ⓑ12mat/md0.12 Ⓒ0.55 Ⓓ5
DONE

View File

@ -0,0 +1,7 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
asset Arm_m05 verts 504 bw 504 readable True
asset Body_m05 verts 703 bw 703 readable True
asset Hair05 verts 647 bw 647 readable True
asset Head verts 339 bw 339 readable True
asset Leg_M05 verts 583 bw 583 readable True
runtime: 렌더러 6 · 메시 5

View File

@ -0,0 +1,27 @@
=== bake chunks=40 palette=16 tag=FINAL ===
faces 4076
regions 40 (target 40)
Arm_m05 : 6
Body_m05 : 11
Hair05 : 14
Head : 2
Leg_M05 : 7
palette 16 · dHue mean 0.81 max 4.37
mesh Arm_m05 verts 468 -> 504 · srcBW 468 newBW 504 bindposes 63 normals 504 tangents 504
mesh Body_m05 verts 604 -> 703 · srcBW 604 newBW 703 bindposes 40 normals 703 tangents 703
mesh Hair05 verts 611 -> 647 · srcBW 611 newBW 647 bindposes 1 normals 647 tangents 647
mesh Head verts 339 -> 339 · srcBW 339 newBW 339 bindposes 1 normals 339 tangents 339
mesh Leg_M05 verts 498 -> 583 · srcBW 498 newBW 583 bindposes 29 normals 583 tangents 583
face tex Assets/WL/Look/Character/Textures/face02_P32.png 32x32
mat M05_ToonP shader=Shader Graphs/Toon tex=WLPalette_FINAL shades=3
mat Skin_ToonP shader=Shader Graphs/Toon tex=WLPalette_FINAL shades=3
mat Hair05_ToonP shader=Shader Graphs/Toon tex=WLPalette_FINAL shades=3
mat face02_ToonP shader=Unlit/Transparent tex=face02_P32
[0] Arm_m05 mesh=Arm_m05_PAL_FINAL mat=M05_ToonP
[1] Body_m05 mesh=Body_m05_PAL_FINAL mat=M05_ToonP
[2] Leg_M05 mesh=Leg_M05_PAL_FINAL mat=M05_ToonP
[3] Head mesh=Head_PAL_FINAL mat=Skin_ToonP
[4] Hair05 mesh=Hair05_PAL_FINAL mat=Hair05_ToonP
[5] Face mesh=- mat=face02_ToonP
DONE

View File

@ -0,0 +1,18 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
mask Arm_m05 = 335 px
mask Body_m05 = 975 px
mask Face = 50 px
mask Hair05 = 1154 px
mask Head = 1047 px
mask Leg_M05 = 729 px
mask all = 2996 px
mask body3 = 1756 px
c20p16: regions 21 pal 16 dHue 1.06/4.58 verts 2520->2573
c20p24: regions 21 pal 21 dHue 1.06/4.58 verts 2520->2573
c20p32: regions 21 pal 21 dHue 1.06/4.58 verts 2520->2573
c40p16: regions 40 pal 16 dHue 1.06/5.15 verts 2520->2733
c40p24: regions 40 pal 24 dHue 0.53/3.58 verts 2520->2781
c40p32: regions 40 pal 32 dHue 0.50/2.37 verts 2520->2781
c80p16: regions 80 pal 16 dHue 1.16/16.86 verts 2520->3145
c80p24: regions 80 pal 24 dHue 0.67/16.86 verts 2520->3163
c80p32: regions 80 pal 32 dHue 0.54/16.86 verts 2520->3164

View File

@ -0,0 +1,3 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
face P32=True P64=True V1=True hair P64=True
best: regions 40 pal 16 dHue 1.06/5.15 verts 2520->2733

View File

@ -0,0 +1,11 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
tex loaded f32=True h64=True
c20p10: regions 21 pal 10 dHue 1.17/4.98 verts 2520->2573
c20p16: regions 21 pal 16 dHue 1.06/4.58 verts 2520->2573
c20p24: regions 21 pal 21 dHue 1.06/4.58 verts 2520->2573
c40p10: regions 40 pal 10 dHue 1.20/5.76 verts 2520->2733
c40p16: regions 40 pal 16 dHue 1.06/5.15 verts 2520->2733
c40p24: regions 40 pal 24 dHue 0.53/3.58 verts 2520->2781
c80p10: regions 80 pal 10 dHue 1.47/16.74 verts 2520->3113
c80p16: regions 80 pal 16 dHue 1.16/16.86 verts 2520->3145
c80p24: regions 80 pal 24 dHue 0.67/16.86 verts 2520->3163

View File

@ -0,0 +1,4 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
srgbSat: regions 40 pal 16 dHue 0.81/4.37
srgbNos: regions 40 pal 16 dHue 0.81/4.37
linNos: regions 40 pal 16 dHue 0.98/7.29

View File

@ -0,0 +1,5 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
g0none: dHue 0.81/4.37
g1soft: dHue 0.81/4.37
g2hard: dHue 0.81/4.37
g3sat: dHue 0.81/4.37

View File

@ -0,0 +1,10 @@
Arm_m05 : verts 504 bw 504 bind 63 attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
src: attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
Body_m05 : verts 703 bw 703 bind 40 attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
src: attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
Leg_M05 : verts 583 bw 583 bind 29 attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
src: attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
Head : verts 339 bw 339 bind 1 attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
src: attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendIndices:UInt32x1@2]
Hair05 : verts 647 bw 647 bind 1 attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendWeight:Float32x4@2,BlendIndices:UInt32x4@2]
src: attrs [Position:Float32x3@0,Normal:Float32x3@0,Tangent:Float32x4@0,TexCoord0:Float32x2@1,BlendIndices:UInt32x1@2]

View File

@ -0,0 +1,47 @@
=== LH_M05.prefab 렌더러 ===
[R] Arm_m05 type=SkinnedMeshRenderer enabled=True activeSelf=True
mesh=Arm_m05 path=Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx verts=468 sub=1 tris=752 blendshapes=0 bones=63 bindposes=63 isReadable=True
uv0 range x[0.395,0.661] y[0.650,0.974] uv2=False colors=False tangents=True normals=True
mat[0] M05_ToonS shader=Shader Graphs/Toon path=Assets/WL/Look/Character/Materials/M05_ToonS.mat base=Assets/WL/Look/Character/Textures/M05_WL.png shadowbase=Assets/WL/Look/Character/Textures/M05_WL.png
[R] Body_m05 type=SkinnedMeshRenderer enabled=True activeSelf=True
mesh=Body_m05 path=Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx verts=604 sub=1 tris=984 blendshapes=0 bones=40 bindposes=40 isReadable=True
uv0 range x[0.002,0.998] y[0.002,0.919] uv2=False colors=False tangents=True normals=True
mat[0] M05_ToonS shader=Shader Graphs/Toon path=Assets/WL/Look/Character/Materials/M05_ToonS.mat base=Assets/WL/Look/Character/Textures/M05_WL.png shadowbase=Assets/WL/Look/Character/Textures/M05_WL.png
[R] Face type=SkinnedMeshRenderer enabled=True activeSelf=True
mesh=Face path=Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx verts=121 sub=1 tris=212 blendshapes=0 bones=1 bindposes=1 isReadable=True
uv0 range x[0.030,0.970] y[0.273,0.766] uv2=False colors=False tangents=True normals=True
mat[0] face02_ToonS shader=Unlit/Transparent path=Assets/WL/Look/Character/Materials/face02_ToonS.mat base=Assets/WL/Look/Character/Textures/face02_WL.png shadowbase=-
[R] Hair05 type=SkinnedMeshRenderer enabled=True activeSelf=True
mesh=Hair05 path=Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx verts=611 sub=1 tris=914 blendshapes=0 bones=1 bindposes=1 isReadable=True
uv0 range x[0.002,0.998] y[0.002,0.995] uv2=False colors=False tangents=True normals=True
mat[0] Hair05_ToonS shader=Shader Graphs/Toon path=Assets/WL/Look/Character/Materials/Hair05_ToonS.mat base=Assets/WL/Look/Character/Textures/Hair05_WL.png shadowbase=Assets/WL/Look/Character/Textures/Hair05_WL.png
[R] Head type=SkinnedMeshRenderer enabled=True activeSelf=True
mesh=Head path=Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx verts=339 sub=1 tris=582 blendshapes=0 bones=1 bindposes=1 isReadable=True
uv0 range x[0.643,0.998] y[0.057,0.603] uv2=False colors=False tangents=True normals=True
mat[0] Skin_ToonS shader=Shader Graphs/Toon path=Assets/WL/Look/Character/Materials/Skin_ToonS.mat base=Assets/WL/Look/Character/Textures/Skin_WL.png shadowbase=Assets/WL/Look/Character/Textures/Skin_WL.png
[R] Leg_M05 type=SkinnedMeshRenderer enabled=True activeSelf=True
mesh=Leg_M05 path=Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx verts=498 sub=1 tris=844 blendshapes=0 bones=29 bindposes=29 isReadable=True
uv0 range x[0.002,0.514] y[0.400,0.816] uv2=False colors=False tangents=True normals=True
mat[0] M05_ToonS shader=Shader Graphs/Toon path=Assets/WL/Look/Character/Materials/M05_ToonS.mat base=Assets/WL/Look/Character/Textures/M05_WL.png shadowbase=Assets/WL/Look/Character/Textures/M05_WL.png
[R] Sword_M05 type=MeshRenderer enabled=True activeSelf=False
mesh=Sword_M05 path=Assets/Suriyun/Characters/RedKnight/FBX/Weapon/Sword_M05.fbx verts=188 sub=1 tris=140 blendshapes=0 bones=0 bindposes=0 isReadable=True
uv0 range x[0.009,0.423] y[0.006,0.988] uv2=False colors=False tangents=True normals=True
mat[0] SwordM05 shader=Toon/Toon path=Assets/Suriyun/Characters/RedKnight/Materials/Weapon/SwordM05.mat base=- shadowbase=-
=== 원본 텍스처 임포트 ===
Assets/WL/Look/Character/Textures/M05_WL.png : maxSize=512 filter=Bilinear mip=True sRGB=True readable=True npot=ToNearest actual=512x512 fmt=ASTC_6x6
Assets/WL/Look/Character/Textures/Skin_WL.png : maxSize=512 filter=Bilinear mip=False sRGB=True readable=True npot=None actual=512x512 fmt=ASTC_6x6
Assets/WL/Look/Character/Textures/Hair05_WL.png : maxSize=512 filter=Bilinear mip=True sRGB=True readable=True npot=ToNearest actual=512x512 fmt=ASTC_6x6
Assets/WL/Look/Character/Textures/face02_WL.png : maxSize=512 filter=Bilinear mip=True sRGB=True readable=True npot=ToNearest actual=512x512 fmt=ASTC_6x6
Assets/WL/Look/Character/Textures/face02_V1.png : maxSize=512 filter=Point mip=True sRGB=True readable=True npot=None actual=512x512 fmt=RGBA32
Assets/WL/Look/Character/Textures/Hair05_V1.png : maxSize=512 filter=Point mip=True sRGB=True readable=True npot=None actual=512x512 fmt=RGB24
=== SO 현재값 ===
enabled_=1 mode=3 n=4
[0] orig=M05 m1=M05_Toon m2=M05_ToonS m3=M05_ToonF
[1] orig=skin m1=Skin_Toon m2=Skin_ToonS m3=Skin_ToonF
[2] orig=Hair05 m1=Hair05_Toon m2=Hair05_ToonS m3=Hair05_ToonF
[3] orig=face02 m1=face02 m2=face02_ToonS m3=face02_ToonF
=== 아레나 씬 카메라/캐릭터 ===
scene=Assets/WL/Look/Arena/Scenes/WL_ArenaProto.unity

View File

@ -0,0 +1,93 @@
// WL-814x 프로브 1 — 메시·머티리얼·텍스처 실측 (팔레트 아틀라스 UV 설계 근거)
// run_script --file AgentScripts/WL814x_Probe.cs --entry WL814x_Probe.Run
public static class WL814x_Probe
{
const string Out = @"E:\NerdNavis\WL_wt\gameplay\AgentScripts\WL814x_PROBE.txt";
public static string Run()
{
var sb = new System.Text.StringBuilder();
var prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>("Assets/Res_Addr/PC/LH_M05.prefab");
if (prefab == null) return "no prefab";
sb.AppendLine("=== LH_M05.prefab 렌더러 ===");
var rs = prefab.GetComponentsInChildren<UnityEngine.Renderer>(true);
foreach (var r in rs)
{
var smr = r as UnityEngine.SkinnedMeshRenderer;
var mf = r.GetComponent<UnityEngine.MeshFilter>();
UnityEngine.Mesh m = smr != null ? smr.sharedMesh : (mf != null ? mf.sharedMesh : null);
sb.AppendLine("[R] " + r.name + " type=" + r.GetType().Name + " enabled=" + r.enabled + " activeSelf=" + r.gameObject.activeSelf);
if (m != null)
{
string path = UnityEditor.AssetDatabase.GetAssetPath(m);
sb.AppendLine(" mesh=" + m.name + " path=" + path + " verts=" + m.vertexCount + " sub=" + m.subMeshCount
+ " tris=" + (m.triangles.Length / 3) + " blendshapes=" + m.blendShapeCount
+ " bones=" + (smr != null && smr.bones != null ? smr.bones.Length : 0)
+ " bindposes=" + m.bindposes.Length + " isReadable=" + m.isReadable);
var uv = m.uv;
if (uv != null && uv.Length > 0)
{
float mnx = 9e9f, mxx = -9e9f, mny = 9e9f, mxy = -9e9f;
for (int i = 0; i < uv.Length; i++) { if (uv[i].x < mnx) mnx = uv[i].x; if (uv[i].x > mxx) mxx = uv[i].x; if (uv[i].y < mny) mny = uv[i].y; if (uv[i].y > mxy) mxy = uv[i].y; }
sb.AppendLine(" uv0 range x[" + mnx.ToString("F3") + "," + mxx.ToString("F3") + "] y[" + mny.ToString("F3") + "," + mxy.ToString("F3") + "]"
+ " uv2=" + (m.uv2 != null && m.uv2.Length > 0) + " colors=" + (m.colors != null && m.colors.Length > 0)
+ " tangents=" + (m.tangents != null && m.tangents.Length > 0) + " normals=" + (m.normals != null && m.normals.Length > 0));
}
}
var mats = r.sharedMaterials;
for (int i = 0; i < mats.Length; i++)
{
var mt = mats[i];
if (mt == null) { sb.AppendLine(" mat[" + i + "] = null"); continue; }
var tex = mt.HasProperty("_BaseMap") ? mt.GetTexture("_BaseMap") : (mt.HasProperty("_MainTex") ? mt.GetTexture("_MainTex") : null);
var stex = mt.HasProperty("_ShadowBaseMap") ? mt.GetTexture("_ShadowBaseMap") : null;
sb.AppendLine(" mat[" + i + "] " + mt.name + " shader=" + mt.shader.name
+ " path=" + UnityEditor.AssetDatabase.GetAssetPath(mt)
+ " base=" + (tex != null ? UnityEditor.AssetDatabase.GetAssetPath(tex) : "-")
+ " shadowbase=" + (stex != null ? UnityEditor.AssetDatabase.GetAssetPath(stex) : "-"));
}
}
sb.AppendLine();
sb.AppendLine("=== 원본 텍스처 임포트 ===");
string[] texPaths = {
"Assets/WL/Look/Character/Textures/M05_WL.png",
"Assets/WL/Look/Character/Textures/Skin_WL.png",
"Assets/WL/Look/Character/Textures/Hair05_WL.png",
"Assets/WL/Look/Character/Textures/face02_WL.png",
"Assets/WL/Look/Character/Textures/face02_V1.png",
"Assets/WL/Look/Character/Textures/Hair05_V1.png",
};
foreach (var p in texPaths)
{
var ti = UnityEditor.AssetImporter.GetAtPath(p) as UnityEditor.TextureImporter;
var t = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Texture2D>(p);
if (ti == null) { sb.AppendLine(p + " : 없음"); continue; }
sb.AppendLine(p + " : maxSize=" + ti.maxTextureSize + " filter=" + ti.filterMode + " mip=" + ti.mipmapEnabled
+ " sRGB=" + ti.sRGBTexture + " readable=" + ti.isReadable + " npot=" + ti.npotScale
+ " actual=" + (t != null ? t.width + "x" + t.height : "?") + " fmt=" + (t != null ? t.format.ToString() : "?"));
}
sb.AppendLine();
sb.AppendLine("=== SO 현재값 ===");
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<WL.Look.Character.WLCharacterLookSettings>("Assets/WL/Look/Character/Resources/WL/WLCharacterLookSettings.asset");
if (so != null)
{
sb.AppendLine("enabled_=" + so.enabled_ + " mode=" + so.mode + " n=" + (so.originals != null ? so.originals.Length : 0));
for (int i = 0; i < (so.originals != null ? so.originals.Length : 0); i++)
sb.AppendLine(" [" + i + "] orig=" + (so.originals[i] != null ? so.originals[i].name : "-")
+ " m1=" + (so.mode1 != null && i < so.mode1.Length && so.mode1[i] != null ? so.mode1[i].name : "-")
+ " m2=" + (so.mode2 != null && i < so.mode2.Length && so.mode2[i] != null ? so.mode2[i].name : "-")
+ " m3=" + (so.mode3 != null && i < so.mode3.Length && so.mode3[i] != null ? so.mode3[i].name : "-"));
}
sb.AppendLine();
sb.AppendLine("=== 아레나 씬 카메라/캐릭터 ===");
sb.AppendLine("scene=Assets/WL/Look/Arena/Scenes/WL_ArenaProto.unity");
System.IO.File.WriteAllText(Out, sb.ToString());
return "written " + Out + " (" + sb.Length + " chars)";
}
}

1294
AgentScripts/WL814x_Run.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
setup: bounds (0.648, 1.217, 0.907) / screen H 117 px / pose yaw 240
palette SO = found enabled_=1
off: enabled_=0 → 적용 0 (814s+814t 상태)
off Arm_m05 mesh=Arm_m05 mat=M05_ToonF
off Body_m05 mesh=Body_m05 mat=M05_ToonF
off Face mesh=Face mat=face02_ToonF
off Hair05 mesh=Hair05 mat=Hair05_ToonF
off Head mesh=Head mat=Skin_ToonF
off Leg_M05 mesh=Leg_M05 mat=M05_ToonF
on: 렌더러 6 · 메시 5
on Arm_m05 mesh=Arm_m05_PAL_FINAL mat=M05_ToonP tris=752 verts=504 en=True vis=True shader=Shader Graphs/Toon base=WLPalette_FINAL shadow=WLPalette_FINAL shades=3.0 bnd=(0.50, 0.32, 0.91) lay=31
on Body_m05 mesh=Body_m05_PAL_FINAL mat=M05_ToonP tris=984 verts=703 en=True vis=True shader=Shader Graphs/Toon base=WLPalette_FINAL shadow=WLPalette_FINAL shades=3.0 bnd=(0.33, 0.44, 0.43) lay=31
on Face mesh=Face mat=face02_ToonP tris=212 verts=121 en=True vis=True shader=Unlit/Transparent base=- shadow=- shades=- bnd=(0.33, 0.29, 0.37) lay=31
on Hair05 mesh=Hair05_PAL_FINAL mat=Hair05_ToonP tris=914 verts=647 en=True vis=True shader=Shader Graphs/Toon base=WLPalette_FINAL shadow=WLPalette_FINAL shades=3.0 bnd=(0.65, 0.48, 0.66) lay=31
on Head mesh=Head_PAL_FINAL mat=Skin_ToonP tris=582 verts=339 en=True vis=True shader=Shader Graphs/Toon base=WLPalette_FINAL shadow=WLPalette_FINAL shades=3.0 bnd=(0.52, 0.40, 0.55) lay=31
on Leg_M05 mesh=Leg_M05_PAL_FINAL mat=M05_ToonP tris=844 verts=583 en=True vis=True shader=Shader Graphs/Toon base=WLPalette_FINAL shadow=WLPalette_FINAL shades=3.0 bnd=(0.36, 0.54, 0.35) lay=31

View File

@ -0,0 +1,42 @@
# WL-814x 비교 이미지 생성기 — raw PNG 을 캐릭터 영역으로 잘라 1배 + N배로 가로 배치
# python AgentScripts/WL814x_compare.py <out.png> <zoom> <name1> <name2> ...
import sys, os
import numpy as np
from PIL import Image, ImageDraw
RAW = 'Screenshots_WL/WL814x/raw'
OUT = sys.argv[1]
ZOOM = int(sys.argv[2])
NAMES = sys.argv[3:]
ma = np.asarray(Image.open(RAW + '/mask_all.png').convert('L')) > 127
ys, xs = np.where(ma)
pad = 6
x0, x1 = max(0, xs.min() - pad), min(ma.shape[1], xs.max() + pad + 1)
y0, y1 = max(0, ys.min() - pad), min(ma.shape[0], ys.max() + pad + 1)
w, h = x1 - x0, y1 - y0
cells = []
for n in NAMES:
p = RAW + '/' + n + '.png'
if not os.path.exists(p):
print('missing', p); continue
im = Image.open(p).convert('RGB').crop((x0, y0, x1, y1))
big = im.resize((w * ZOOM, h * ZOOM), Image.NEAREST)
cells.append((n, im, big))
gap = 10
label = 18
W = sum(c[2].width for c in cells) + gap * (len(cells) - 1)
H = cells[0][2].height + cells[0][1].height + gap + label
out = Image.new('RGB', (W, H), (24, 24, 28))
d = ImageDraw.Draw(out)
x = 0
for n, im, big in cells:
out.paste(big, (x, label))
out.paste(im, (x + (big.width - im.width) // 2, label + big.height + gap))
d.text((x + 2, 3), n, fill=(230, 230, 230))
x += big.width + gap
os.makedirs(os.path.dirname(OUT) or '.', exist_ok=True)
out.save(OUT)
print('saved', OUT, out.size)

View File

@ -0,0 +1,197 @@
# WL-814x 측정기 — 렌더 PNG + 마스크 PNG 를 읽어 합격선 6항목을 잰다.
# python AgentScripts/WL814x_metrics.py <raw폴더> [파일접두어필터]
#
# 정의(보고서와 동일)
# · 서로 다른 색 비율 = 고유색 수 / 캐릭터 영역 픽셀 수 × 100
# · 부위당 색 단계 = 그 부위의 색을 RGB 거리 16 이내로 묶었을 때, 면적 90 % 를 덮는 군집 수
# · 진한 점(눈) = 얼굴 데칼 마스크 안에서 L < 피부평균L × 0.75 인 픽셀 수 (814v 와 동일)
# · Hue 오차 = 부위별 채도가중 원형평균 Hue 의 기준 대비 차 (부호 있는 각도)
import sys, os, glob, json
import numpy as np
from PIL import Image
RAW = sys.argv[1] if len(sys.argv) > 1 else "Screenshots_WL/WL814x/raw"
FILT = sys.argv[2] if len(sys.argv) > 2 else ""
PARTS = ["all", "body3", "Body_m05", "Arm_m05", "Leg_M05", "Head", "Hair05", "Face"]
def load(p):
return np.asarray(Image.open(p).convert("RGB"), dtype=np.uint8)
def masks():
m = {}
for p in PARTS:
f = os.path.join(RAW, "mask_%s.png" % p)
if os.path.exists(f):
m[p] = load(f)[:, :, 0] > 127
return m
def lum(px):
return 0.299 * px[:, 0] + 0.587 * px[:, 1] + 0.114 * px[:, 2]
def hsv(px):
a = px.astype(np.float32)
mx = a.max(1); mn = a.min(1); d = mx - mn
h = np.zeros(len(a), np.float32)
nz = d > 1e-6
r, g, b = a[:, 0], a[:, 1], a[:, 2]
i = nz & (mx == r); h[i] = ((g[i] - b[i]) / d[i]) % 6
i = nz & (mx == g) & ~(mx == r); h[i] = (b[i] - r[i]) / d[i] + 2
i = nz & (mx == b) & ~(mx == r) & ~(mx == g); h[i] = (r[i] - g[i]) / d[i] + 4
h *= 60.0
s = np.where(mx > 1e-6, d / np.maximum(mx, 1e-6), 0)
return h, s, mx
def mean_hue(px):
h, s, v = hsv(px)
w = np.where(s > 0.08, s, 0.0)
if w.sum() < 1e-6:
return float("nan")
x = (w * np.cos(np.radians(h))).sum(); y = (w * np.sin(np.radians(h))).sum()
return (np.degrees(np.arctan2(y, x)) + 360.0) % 360.0
def dhue(a, b):
d = (b - a + 180.0) % 360.0 - 180.0
return d
def steps(px, thr=16.0, cover=0.90):
"""색을 RGB 거리 thr 이내로 묶어 면적 cover 를 덮는 군집 수."""
if len(px) == 0:
return 0, 0
key = (px[:, 0].astype(np.int32) << 16) | (px[:, 1].astype(np.int32) << 8) | px[:, 2].astype(np.int32)
u, cnt = np.unique(key, return_counts=True)
order = np.argsort(-cnt)
u, cnt = u[order], cnt[order]
cols = np.stack([(u >> 16) & 255, (u >> 8) & 255, u & 255], 1).astype(np.float32)
cent = []; wts = []
for i in range(len(u)):
c = cols[i]; w = cnt[i]
best = -1; bd = 1e9
for j, cc in enumerate(cent):
d = np.linalg.norm(cc - c)
if d < bd:
bd = d; best = j
if best >= 0 and bd < thr:
n = wts[best] + w
cent[best] = (cent[best] * wts[best] + c * w) / n
wts[best] = n
else:
cent.append(c.copy()); wts.append(float(w))
if len(cent) > 400:
break
wts = np.array(wts); o = np.argsort(-wts); wts = wts[o]
tot = len(px); acc = 0; k = 0
for w in wts:
acc += w; k += 1
if acc >= cover * tot:
break
return k, len(u)
def measure(img, msk, ref_hue=None, skinL=None):
px = img[msk]
n = len(px)
if n == 0:
return None
key = (px[:, 0].astype(np.int32) << 16) | (px[:, 1].astype(np.int32) << 8) | px[:, 2].astype(np.int32)
uc = len(np.unique(key))
st, _ = steps(px)
L = lum(px)
h_, s_, v_ = hsv(px)
r = dict(px=n, colors=uc, ratio=100.0 * uc / n, steps=st,
lmin=float(L.min()), lmax=float(L.max()), hue=mean_hue(px),
sat=float(s_.mean()), val=float(v_.mean()), lmean=float(L.mean()))
if ref_hue is not None and not np.isnan(r["hue"]) and not np.isnan(ref_hue):
r["dhue"] = float(dhue(ref_hue, r["hue"]))
if skinL:
r["dark"] = int((L < skinL * 0.75).sum())
return r
def main():
M = masks()
files = sorted(glob.glob(os.path.join(RAW, "*.png")))
files = [f for f in files if not os.path.basename(f).startswith("mask_")]
if FILT:
files = [f for f in files if os.path.basename(f).startswith(FILT)]
# 🔴 색상/채도 기준은 언제나 「지금」 상태(i1_a_base_now) 로 고정한다.
base = os.path.join(RAW, "i1_a_base_now.png")
if os.path.exists(base):
files = [base] + [f for f in files if os.path.abspath(f) != os.path.abspath(base)]
ref = {}
rows = []
for f in files:
img = load(f)
name = os.path.splitext(os.path.basename(f))[0]
# 피부 밝기 기준 = Head 마스크에서 Face 를 뺀 영역 평균 L
skinL = None
if "Head" in M and "Face" in M:
hm = M["Head"] & ~M["Face"]
if hm.sum() > 0:
skinL = float(lum(img[hm]).mean())
rec = {"name": name, "skinL": skinL}
for p in PARTS:
if p not in M:
continue
r = measure(img, M[p], ref.get(p), skinL if p == "Face" else None)
if r is None:
continue
if p not in ref and not np.isnan(r["hue"]):
ref[p] = r["hue"]
# 눈 크기(얼굴 왼쪽 절반의 진한 점 바운딩박스)
if p == "Face" and skinL:
ys, xs = np.where(M[p])
x0, x1 = xs.min(), xs.max()
half = (x0 + x1) // 2
sub = M[p].copy(); sub[:, half:] = False
idx = np.where(sub)
if len(idx[0]):
Ls = lum(img[sub])
d = Ls < skinL * 0.75
if d.sum() > 0:
yy = idx[0][d]; xx = idx[1][d]
r["eye"] = "%dx%d" % (xx.max() - xx.min() + 1, yy.max() - yy.min() + 1)
rec[p] = r
rows.append(rec)
hdr = "%-28s %6s %6s %5s | %s | %s | %s" % (
"render", "전체색", "비율%", "단계",
"색:몸통/피부/머리칼/얼굴", "단계:몸통/피부/머리칼", "얼굴 진한점/눈")
print(hdr); print("-" * 118)
for r in rows:
a = r.get("all"); b3 = r.get("body3"); hd = r.get("Head"); hr = r.get("Hair05"); fc = r.get("Face")
def c(x): return x["colors"] if x else 0
def s(x): return x["steps"] if x else 0
print("%-28s %6d %6.1f %5d | %5d/%4d/%4d/%4d | %6d/%3d/%3d | %4s / %s" % (
r["name"], a["colors"], a["ratio"], a["steps"],
c(b3), c(hd), c(hr), c(fc), s(b3), s(hd), s(hr),
fc.get("dark", "-") if fc else "-", fc.get("eye", "-") if fc else "-"))
print()
print("%-26s | %-22s | %-22s | %s" % ("render", "dHue 몸통/피부/머리칼", "채도S 몸통/피부/머리칼", "밝기L 몸통/피부/머리칼"))
b0 = rows[0]
for r in rows:
def g(p):
x = r.get(p)
return ("%+5.1f" % x["dhue"]) if (x and "dhue" in x) else " ref"
def s(p):
x = r.get(p); y = b0.get(p)
if not x: return " -"
return "%.2f" % x["sat"] + ("(%+.2f)" % (x["sat"] - y["sat"]) if y and r is not b0 else "")
def lv(p):
x = r.get(p); y = b0.get(p)
if not x: return " -"
return "%3.0f" % x["lmean"] + ("(%+3.0f)" % (x["lmean"] - y["lmean"]) if y and r is not b0 else "")
print("%-26s | %s %s %s | %s %s %s | %s %s %s" % (
r["name"], g("body3"), g("Head"), g("Hair05"),
s("body3"), s("Head"), s("Hair05"), lv("body3"), lv("Head"), lv("Hair05")))
with open(os.path.join(RAW, "..", "metrics.json"), "w", encoding="utf-8") as fp:
json.dump(rows, fp, ensure_ascii=False, indent=1, default=float)
main()

View File

@ -0,0 +1,107 @@
# WL-814x 보고용 캡처 묶음 + 합격선 표 이미지 + 외곽선 두께 실측
import os
import numpy as np
from PIL import Image, ImageDraw
RAW = 'Screenshots_WL/WL814x/raw'
OUT = 'Screenshots_WL/WL814x'
def L(n):
return np.asarray(Image.open(RAW + '/' + n + '.png').convert('RGB'), dtype=np.uint8)
ma = L('mask_all')[:, :, 0] > 127
ys, xs = np.where(ma)
pad = 6
X0, X1 = xs.min() - pad, xs.max() + pad + 1
Y0, Y1 = ys.min() - pad, ys.max() + pad + 1
def crop(n, z):
im = Image.open(RAW + '/' + n + '.png').convert('RGB').crop((X0, Y0, X1, Y1))
return im.resize((im.width * z, im.height * z), Image.NEAREST) if z > 1 else im
def grid(out, zoom, names, labels=None):
cells = [(labels[i] if labels else names[i], crop(n, zoom), crop(n, 1)) for i, n in enumerate(names)
if os.path.exists(RAW + '/' + n + '.png')]
gap, lab = 10, 20
W = sum(c[1].width for c in cells) + gap * (len(cells) - 1)
H = cells[0][1].height + cells[0][2].height + gap + lab
img = Image.new('RGB', (W, H), (24, 24, 28))
d = ImageDraw.Draw(img)
x = 0
for t, big, small in cells:
img.paste(big, (x, lab))
img.paste(small, (x + (big.width - small.width) // 2, lab + big.height + gap))
d.text((x + 2, 4), t, fill=(235, 235, 235))
x += big.width + gap
img.save(OUT + '/' + out)
print('saved', out, img.size)
# ── 외곽선 두께 실측: 실루엣 바깥 1px 띠가 거의 검정인가
def outline_px(name):
im = L(name)
inner = np.zeros_like(ma)
inner[1:-1, 1:-1] = ma[1:-1, 1:-1] & ma[:-2, 1:-1] & ma[2:, 1:-1] & ma[1:-1, :-2] & ma[1:-1, 2:]
band1 = ma & ~inner
inner2 = np.zeros_like(ma)
inner2[2:-2, 2:-2] = inner[2:-2, 2:-2] & inner[1:-3, 2:-2] & inner[3:-1, 2:-2] & inner[2:-2, 1:-3] & inner[2:-2, 3:-1]
band2 = inner & ~inner2
def darkfrac(b):
px = im[b]
lum = 0.299 * px[:, 0] + 0.587 * px[:, 1] + 0.114 * px[:, 2]
return 100.0 * (lum < 40).sum() / max(len(px), 1), int(b.sum())
f1, n1 = darkfrac(band1)
f2, n2 = darkfrac(band2)
return f1, n1, f2, n2
if __name__ == '__main__':
grid('iter1.png', 5, ['i1_a_base_now', 'i1_c20p16', 'i1_c40p16', 'i1_c80p16'],
['지금(89.3%/2676)', '덩어리20 팔레트16', '덩어리40 팔레트16', '덩어리80 팔레트16'])
grid('iter2.png', 5, ['i1_a_base_now', 'i2_fV1', 'i2_fP32', 'i2_shades2'],
['지금', '얼굴 814v V1(2048)', '얼굴 P32(1텍셀=1px)', '+셰이드2단'])
grid('iter3.png', 5, ['i1_a_base_now', 'i3_c20p10_s2', 'i3_c40p16_s2', 'i3_c40p16_s3', 'i3_c80p16_s2'],
['지금', 'c20p10 s2', 'c40p16 s2', 'c40p16 s3', 'c80p16 s2'])
grid('iter4.png', 5, ['i1_a_base_now', 'i4_linNos_s3', 'i5_g0none_s3', 'i5_g1soft_s3', 'i5_g2hard_s3'],
['지금', '선형평균', 'sRGB평균 보정없음', '보정 g1soft(채택)', '보정 g2hard'])
grid('z_final_compare.png', 4, ['z_off_now', 'q_runtime'], ['지금 (enabled_=0)', '최종 팔레트 UV (enabled_=1)'])
for n in ['z_off_now', 'q_runtime']:
print(n, '외곽선 1px띠 어두운비율 %.1f%% (%d px) · 2px째 띠 %.1f%% (%d px)' % outline_px(n))
# ── 합격선 표 이미지
rows = [
('항목', '지금', '최종', '합격선', '판정'),
('서로 다른 색 비율', '89.3 %', '1.7 %', '≤ 25 %', 'PASS'),
('캐릭터 영역 고유색 수', '2,676', '52', '≤ 60', 'PASS'),
('부위(덩어리)당 색 단계', '41', '평균 2.79 (14칸 중 13칸 2~3)', '≤ 4', 'PASS*'),
('눈이 어두운 덩어리로', '10 px', '36 px (눈 1개 7×5)', '36 px 유지 이상', 'PASS'),
('색상(Hue) 오차', '-', '몸통 2.4° 피부 3.7° 머리칼 3.5°', '평균 ≤ 8°', 'PASS'),
('실루엣 외곽선', '1 px', '1 px (814t 설정 무변경)', '유지', 'PASS'),
]
cw = [230, 90, 300, 130, 80]
rh = 34
W = sum(cw) + 40
H = rh * len(rows) + 70
img = Image.new('RGB', (W, H), (22, 22, 26))
d = ImageDraw.Draw(img)
d.text((20, 14), 'WL-814x 팔레트 아틀라스 UV — 합격선 6항목 (WL_ArenaProto · 직교10 · 1080x1920 · 캐릭터 2996px)', fill=(255, 235, 160))
for r, row in enumerate(rows):
y = 48 + r * rh
bg = (40, 40, 48) if r == 0 else ((30, 30, 36) if r % 2 else (26, 26, 31))
d.rectangle([16, y, W - 16, y + rh - 2], fill=bg)
x = 20
for c, cell in enumerate(row):
col = (235, 235, 235)
if r > 0 and c == 4:
col = (130, 230, 150)
if r > 0 and c == 2:
col = (150, 210, 255)
d.text((x + 6, y + 9), str(cell), fill=col)
x += cw[c]
d.text((20, 48 + len(rows) * rh + 6), '* 단계 7 인 칸 1개 = 얼굴 데칼이 얹힌 머리 피부 칸(데칼은 별도 부위로 잼)', fill=(200, 200, 200))
img.save(OUT + '/z_metrics.png')
print('saved z_metrics.png', img.size)

View File

@ -0,0 +1,47 @@
# WL-814x 「부위(덩어리)당 색 단계」 측정기
# idmap_<tag>.png = 덩어리(팔레트 칸)를 고유색으로 찍은 지도(빛 0)
# python AgentScripts/WL814x_steps.py <raw> <render이름> <idmap이름>
import sys
import numpy as np
from PIL import Image
RAW = sys.argv[1]
REN = sys.argv[2]
IDM = sys.argv[3]
def L(p):
return np.asarray(Image.open(RAW + '/' + p + '.png').convert('RGB'), dtype=np.uint8)
idm = L(IDM)
ren = L(REN)
ma = L('mask_all')[:, :, 0] > 127
kid = (idm[:, :, 0].astype(np.int32) << 16) | (idm[:, :, 1].astype(np.int32) << 8) | idm[:, :, 2].astype(np.int32)
kre = (ren[:, :, 0].astype(np.int32) << 16) | (ren[:, :, 1].astype(np.int32) << 8) | ren[:, :, 2].astype(np.int32)
# 배경(0,0,0)과 마스크 밖 제외. idmap 은 얼굴 렌더러를 끄고 찍었으므로 그 영역도 자동 제외.
valid = ma & (kid != 0)
ids, cnt = np.unique(kid[valid], return_counts=True)
rows = []
for i, c in zip(ids, cnt):
if c < 8:
continue # 8px 미만 덩어리는 단계 판정 불가 → 제외(개수만 센다)
sel = valid & (kid == i)
u, uc = np.unique(kre[sel], return_counts=True)
o = np.argsort(-uc)
cov = np.cumsum(uc[o]) / c
n90 = int(np.searchsorted(cov, 0.90) + 1)
rows.append((int(c), len(u), n90))
rows.sort(key=lambda r: -r[0])
if rows:
a = np.array(rows)
big = a[a[:, 0] >= 20]
print('%s / %s : 덩어리(팔레트칸) %d개(8px+), 픽셀 %d' % (REN, IDM, len(rows), a[:, 0].sum()))
print(' 칸당 고유색 평균 %.1f 최대 %d' % (a[:, 1].mean(), a[:, 1].max()))
print(' 칸당 색단계(90%%덮기) 평균 %.2f 최대 %d · 20px+ 칸만: 평균 %.2f 최대 %d' % (
a[:, 2].mean(), a[:, 2].max(),
big[:, 2].mean() if len(big) else 0, big[:, 2].max() if len(big) else 0))
print(' 단계 분포:', {k: int((a[:, 2] == k).sum()) for k in sorted(set(a[:, 2].tolist()))})
print(' 가장 큰 칸 6개 (px, 고유색, 단계):', rows[:6])
else:
print('no chunks')

View File

@ -0,0 +1,101 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Hair05_ToonP
m_Shader: {fileID: -6465566751694194690, guid: 378227f8a69213e419dfb0d889d8dd2f,
type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _OUTLINESENABLED
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 2800000, guid: cb59a62e22f03c44381bac391d63c8b2, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ShadowBaseMap:
m_Texture: {fileID: 2800000, guid: cb59a62e22f03c44381bac391d63c8b2, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _Brightness: 0.25
- _CastShadows: 1
- _Cloud_Change: 0.005
- _Cloud_Cover: 0.5
- _Cloud_Density: 0.01
- _Cloud_Strength: 1
- _Cull: 2
- _DepthEdgeStrength: 0.5
- _DepthThreshold: 0.01
- _DstBlend: 0
- _DstBlendAlpha: 0
- _MinimumDarkness: 0.2
- _NormalEdgeStrength: 0.3
- _NormalThreshold: 1
- _OUTLINESENABLED: 1
- _QueueControl: 0
- _QueueOffset: 0
- _Shades: 3
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _XRMotionVectorsPass: 1
- _ZTest: 4
- _ZWrite: 1
- _ZWriteControl: 0
m_Colors:
- _Cloud_Movement: {r: 1, g: 1, b: 0, a: 0}
- _Cloud_Step: {r: 13, g: 17, b: 0, a: 0}
- _DiffuseColor: {r: 1, g: 1, b: 1, a: 1}
- _NormalBias: {r: 1, g: 1, b: 1, a: 0}
- _Outline: {r: 0, g: 0, b: 0, a: 0}
- _ShadowDiffuseColor: {r: 0.2164, g: 0.2092, b: 0.3713, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &3057500309613993806
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ad4735b15308b94ca1bd78da99c3ee1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-5322226680851780222
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: M05_ToonP
m_Shader: {fileID: -6465566751694194690, guid: 378227f8a69213e419dfb0d889d8dd2f,
type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _OUTLINESENABLED
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 2800000, guid: cb59a62e22f03c44381bac391d63c8b2, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ShadowBaseMap:
m_Texture: {fileID: 2800000, guid: cb59a62e22f03c44381bac391d63c8b2, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _Brightness: 0.25
- _CastShadows: 1
- _Cloud_Change: 0.005
- _Cloud_Cover: 0.5
- _Cloud_Density: 0.01
- _Cloud_Strength: 1
- _Cull: 2
- _DepthEdgeStrength: 0.5
- _DepthThreshold: 0.01
- _DstBlend: 0
- _DstBlendAlpha: 0
- _MinimumDarkness: 0.2
- _NormalEdgeStrength: 0.3
- _NormalThreshold: 1
- _OUTLINESENABLED: 1
- _QueueControl: 0
- _QueueOffset: 0
- _Shades: 3
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _XRMotionVectorsPass: 1
- _ZTest: 4
- _ZWrite: 1
- _ZWriteControl: 0
m_Colors:
- _Cloud_Movement: {r: 1, g: 1, b: 0, a: 0}
- _Cloud_Step: {r: 13, g: 17, b: 0, a: 0}
- _DiffuseColor: {r: 1, g: 1, b: 1, a: 1}
- _NormalBias: {r: 1, g: 1, b: 1, a: 0}
- _Outline: {r: 0, g: 0, b: 0, a: 0}
- _ShadowDiffuseColor: {r: 0.2164, g: 0.2092, b: 0.3713, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9161c6a9a87cab1438eb74cecad72893
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Skin_ToonP
m_Shader: {fileID: -6465566751694194690, guid: 378227f8a69213e419dfb0d889d8dd2f,
type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _OUTLINESENABLED
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 2800000, guid: cb59a62e22f03c44381bac391d63c8b2, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ShadowBaseMap:
m_Texture: {fileID: 2800000, guid: cb59a62e22f03c44381bac391d63c8b2, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _Brightness: 0.25
- _CastShadows: 1
- _Cloud_Change: 0.005
- _Cloud_Cover: 0.5
- _Cloud_Density: 0.01
- _Cloud_Strength: 1
- _Cull: 2
- _DepthEdgeStrength: 0.5
- _DepthThreshold: 0.01
- _DstBlend: 0
- _DstBlendAlpha: 0
- _MinimumDarkness: 0.2
- _NormalEdgeStrength: 0.3
- _NormalThreshold: 1
- _OUTLINESENABLED: 1
- _QueueControl: 0
- _QueueOffset: 0
- _Shades: 3
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _XRMotionVectorsPass: 1
- _ZTest: 4
- _ZWrite: 1
- _ZWriteControl: 0
m_Colors:
- _Cloud_Movement: {r: 1, g: 1, b: 0, a: 0}
- _Cloud_Step: {r: 13, g: 17, b: 0, a: 0}
- _DiffuseColor: {r: 1, g: 1, b: 1, a: 1}
- _NormalBias: {r: 1, g: 1, b: 1, a: 0}
- _Outline: {r: 0, g: 0, b: 0, a: 0}
- _ShadowDiffuseColor: {r: 0.2164, g: 0.2092, b: 0.3713, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &2218486046608314064
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 470ec749ed9afb843a0bca59f47eea68
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,97 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: face02_ToonP
m_Shader: {fileID: 10750, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords:
- _ALPHAPREMULTIPLY_ON
- _EMISSION
m_LightmapFlags: 1
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _FalloffSampler:
m_Texture: {fileID: 2800000, guid: 53ba3cfb9b246fd4f9098e204d897e60, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: dfcbd6a1930d90a479f2f5ecea38d377, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _RimLightSampler:
m_Texture: {fileID: 2800000, guid: 11011750921e10846abfad2b18cadbca, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DepthBias: 0.00012
- _DetailNormalMapScale: 1
- _DstBlend: 10
- _EdgeThickness: 1
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 3
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 0
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _ShadowColor: {r: 0.8, g: 0.8, b: 1, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e63e2e61895e324099928771be402cd
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bce6f36f9e291134e91b1ff9c61100d4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ecedbc4292abc7043ae38a52519a3d38
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 4300000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd83dd62c11dabb4c8f09d9dcf907504
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 4300000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 026afa11933facb47826e4587d3eeab9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 4300000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3aa19749ee2e7814ea985c18d216efc7
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 4300000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c4b2eca5a27bfdf4e802a23edf5e8d7e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 4300000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 254b7d1576e32124295b43c0dd1f76a0, type: 3}
m_Name: WLCharacterPaletteSettings
m_EditorClassIdentifier: Assembly-CSharp::WL.Look.Character.WLCharacterPaletteSettings
enabled_: 1
verboseLog: 0
rendererNames:
- Arm_m05
- Body_m05
- Leg_M05
- Head
- Hair05
- Face
paletteMeshes:
- {fileID: 4300000, guid: ecedbc4292abc7043ae38a52519a3d38, type: 2}
- {fileID: 4300000, guid: cd83dd62c11dabb4c8f09d9dcf907504, type: 2}
- {fileID: 4300000, guid: c4b2eca5a27bfdf4e802a23edf5e8d7e, type: 2}
- {fileID: 4300000, guid: 3aa19749ee2e7814ea985c18d216efc7, type: 2}
- {fileID: 4300000, guid: 026afa11933facb47826e4587d3eeab9, type: 2}
- {fileID: 0}
paletteMaterials:
- {fileID: 2100000, guid: 9161c6a9a87cab1438eb74cecad72893, type: 2}
- {fileID: 2100000, guid: 9161c6a9a87cab1438eb74cecad72893, type: 2}
- {fileID: 2100000, guid: 9161c6a9a87cab1438eb74cecad72893, type: 2}
- {fileID: 2100000, guid: 470ec749ed9afb843a0bca59f47eea68, type: 2}
- {fileID: 2100000, guid: 2ad4735b15308b94ca1bd78da99c3ee1, type: 2}
- {fileID: 2100000, guid: 9e63e2e61895e324099928771be402cd, type: 2}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ecc40027fd4cc2d418b07795efba2ed3
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,181 @@
fileFormatVersion: 2
guid: 2726b4a58d7996b4f936528bc359d323
TextureImporter:
internalIDToNameTable:
- first:
213: 6022471554731658938
second: Hair05_P64_0
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 0
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: Hair05_P64_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 64
height: 64
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: abecca978fd149350800000000000000
internalID: 6022471554731658938
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

View File

@ -0,0 +1,181 @@
fileFormatVersion: 2
guid: cb59a62e22f03c44381bac391d63c8b2
TextureImporter:
internalIDToNameTable:
- first:
213: 4905164880735866611
second: WLPalette_FINAL_0
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: WLPalette_FINAL_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 32
height: 32
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: 3fe8bf86875a21440800000000000000
internalID: 4905164880735866611
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

View File

@ -0,0 +1,181 @@
fileFormatVersion: 2
guid: dfcbd6a1930d90a479f2f5ecea38d377
TextureImporter:
internalIDToNameTable:
- first:
213: -6539300337229460641
second: face02_P32_0
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: face02_P32_0
rect:
serializedVersion: 2
x: 0
y: 0
width: 32
height: 32
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: f5b88df6dfcbf35a0800000000000000
internalID: -6539300337229460641
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -41,6 +41,8 @@ namespace WL.Look.Character
var cfg = WLCharacterLookSettings.Instance;
if (cfg == null || root == null) return;
ApplyMode(root, WLCharacterLookSettings.ActiveMode, cfg);
// WL-814x — 팔레트 아틀라스 UV. 그쪽 SO 의 enabled_ = 0 이면 아무 일도 일어나지 않는다.
WLCharacterPalette.Apply(root);
}
/// <summary>모드를 직접 지정해 맞춘다(캡처·프로브·A/B 용).</summary>

View File

@ -0,0 +1,89 @@
// ─────────────────────────────────────────────────────────────────────────────
// WLCharacterPalette.cs — 팔레트 아틀라스 UV 를 런타임에 끼운다 (WL-814x)
//
// PD 지시 #814 · 발주서 WL-814x
//
// ■ 왜 이렇게 하나
// 화면 속 캐릭터는 키 117 px 뿐이라 텍셀 수천 개가 평균 나 화면 1 px 이 된다(814u 실측).
// 그래서 텍스처를 아무리 곱게 그려도 「흐린 사진」이 된다.
// → 메시의 각 덩어리 UV 를 **팔레트 텍스처의 칸 한가운데**로 보내면 그 덩어리는
// 아무리 축소돼도 항상 단색이다(평균 날 디테일이 애초에 없다).
//
// ■ 되돌리기
// WLCharacterPaletteSettings.enabled_ = 0 → 아무것도 안 한다 = 814s + 814t 상태 100 %.
//
// ■ 성능 / GC
// Awake 1회. 렌더러 수(7)만큼만 돈다. 바꿀 것이 없으면 대입도 하지 않는다.
//
// 🔴 Debug.LogError / Debug.LogException 을 쓰지 않는다(813z 규칙).
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections.Generic;
using UnityEngine;
namespace WL.Look.Character
{
public static class WLCharacterPalette
{
// 진단(프로브가 읽는다)
public static int AppliedRenderers, AppliedMeshes;
public static string LastLog = "";
static readonly List<Renderer> s_buf = new List<Renderer>(16);
/// <summary>SO 가 켜져 있으면 팔레트 메시·머티리얼로 갈아끼운다.</summary>
public static void Apply(GameObject root)
{
AppliedRenderers = 0; AppliedMeshes = 0;
var cfg = WLCharacterPaletteSettings.Instance;
if (cfg == null || root == null || cfg.enabled_ == 0)
{
LastLog = cfg == null ? "SO 없음 → 적용 0" : "enabled_=0 → 적용 0 (814s+814t 상태)";
return;
}
var names = cfg.rendererNames;
if (names == null || names.Length == 0) { LastLog = "표 비어 있음 → 적용 0"; return; }
s_buf.Clear();
root.GetComponentsInChildren<Renderer>(true, s_buf);
for (int ri = 0; ri < s_buf.Count; ri++)
{
var r = s_buf[ri];
if (r == null) continue;
int idx = IndexOf(names, r.name);
if (idx < 0) continue;
// ① 메시 — 스킨 메시는 본/바인드포즈가 원본과 같으므로 그대로 갈아끼워진다.
var smr = r as SkinnedMeshRenderer;
if (smr != null && cfg.paletteMeshes != null && idx < cfg.paletteMeshes.Length)
{
var m = cfg.paletteMeshes[idx];
if (m != null && smr.sharedMesh != m) { smr.sharedMesh = m; AppliedMeshes++; }
}
// ② 머티리얼
if (cfg.paletteMaterials != null && idx < cfg.paletteMaterials.Length)
{
var want = cfg.paletteMaterials[idx];
if (want != null)
{
var mats = r.sharedMaterials;
bool changed = false;
for (int si = 0; si < mats.Length; si++)
if (mats[si] != want) { mats[si] = want; changed = true; }
if (changed) { r.sharedMaterials = mats; AppliedRenderers++; }
}
}
}
LastLog = "렌더러 " + AppliedRenderers + " · 메시 " + AppliedMeshes;
if (cfg.verboseLog != 0) Debug.Log("[WL814x CharacterPalette] " + LastLog);
}
static int IndexOf(string[] names, string n)
{
for (int i = 0; i < names.Length; i++) if (names[i] == n) return i;
return -1;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dbb1204c1ba8048468874a4a590cfe27

View File

@ -0,0 +1,61 @@
// ─────────────────────────────────────────────────────────────────────────────
// WLCharacterPaletteSettings.cs — 팔레트 아틀라스 UV(도트) 되돌리기 스위치 (WL-814x)
//
// PD 지시 #814 · 발주서 WL-814x §4
//
// 🔴 enabled_ = 0 → 이 기능 전체 off = 814s + 814t 상태 100 %
// (814s 의 WLCharacterLookSettings 는 그대로 두고, 그 **뒤에** 얹는 별도 스위치다.
// 그래서 이 SO 를 꺼도 기존 되돌리기 동작이 조금도 바뀌지 않는다.)
//
// 무엇을 바꾸나 = 렌더러별로 ① 메시를 「팔레트 UV 복사본」으로 ② 머티리얼을 팔레트 머티리얼로.
// 원본 FBX·원본 png·프리팹은 손대지 않는다 — 전부 런타임 교체다.
//
// 🔴 Debug.LogError / Debug.LogException 을 쓰지 않는다(813z 규칙).
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Look.Character
{
public class WLCharacterPaletteSettings : ScriptableObject
{
[Header("스위치")]
[Tooltip("0 이면 이 기능 전체 off (= 814s+814t 상태 100 %)")]
public int enabled_ = 1;
[Tooltip("1 이면 적용 내역을 로그로 남긴다")]
public int verboseLog = 0;
[Header("렌더러별 표 (같은 인덱스끼리 짝)")]
[Tooltip("LH_M05 프리팹 안의 렌더러 GameObject 이름")]
public string[] rendererNames;
[Tooltip("팔레트 UV 메시 복사본 (비어 있으면 메시는 안 바꾼다 = 얼굴)")]
public Mesh[] paletteMeshes;
[Tooltip("팔레트 머티리얼")]
public Material[] paletteMaterials;
// ───────────────────────────────────────── 싱글턴(Resources)
public const string ResourcePath = "WL/WLCharacterPaletteSettings";
static WLCharacterPaletteSettings s_inst;
static bool s_tried;
public static WLCharacterPaletteSettings Instance
{
get
{
if (s_inst == null && !s_tried)
{
s_tried = true;
s_inst = Resources.Load<WLCharacterPaletteSettings>(ResourcePath);
}
return s_inst;
}
}
public static void Invalidate() { s_inst = null; s_tried = false; }
public static bool Enabled { get { var c = Instance; return c != null && c.enabled_ != 0; } }
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 254b7d1576e32124295b43c0dd1f76a0