[WL-814x] 팔레트 아틀라스 UV 로 캐릭터를 진짜 도트로 (덩어리 40 · 팔레트 16색) (#814)
메시 UV 를 「색 하나를 가리키는 좌표」로 새로 굽는다. 삼각형 안에서 UV 가 상수라 화면에서 아무리 축소돼도 그 덩어리는 항상 단색 — 평균 날 디테일이 애초에 없다. 실측(WL_ArenaProto · 직교 10 · 1080x1920 · 캐릭터 2,996 px · 814u/814v 와 같은 축) 서로 다른 색 비율 89.3 % -> 1.7 % (합격선 <= 25 %) 캐릭터 영역 고유색 2,676 -> 52 (합격선 <= 60) 덩어리당 색 단계 - -> 평균 2.79 (14칸 중 13칸이 2~3 · 합격선 <= 4) 눈 진한 점 10 px -> 36 px (눈 1개 7x5 px) 색상(Hue) 오차 - -> 몸통 2.4° 피부 3.7° 머리칼 3.5° 삼각형 수 무변경 · 정점 2,520 -> 2,776 (+10 %) 원본 수정 0 — FBX/원본 png/프리팹/씬 전부 무변경. 메시는 복사본(.asset)에 UV 만 새로 굽고 런타임에 갈아끼운다. 되돌리기 = 새 SO 의 enabled_ = 0 이면 814s+814t 상태 100 %. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d285e7edea
commit
ada56c7688
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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]
|
||||
|
|
@ -101,7 +101,7 @@ public static class WLXCap
|
|||
UnityEngine.Object.DestroyImmediate(t);
|
||||
}
|
||||
|
||||
public static void Shoot(string name) { Save(Render(new Color(0.10f, 0.10f, 0.12f)), RAW + name + ".png"); }
|
||||
public static void Shoot(string name) { Render(new Color(0.10f, 0.10f, 0.12f)); Save(Render(new Color(0.10f, 0.10f, 0.12f)), RAW + name + ".png"); } // 1장 버리고 찍는다: 메시를 갈아끼운 직후 첫 프레임은 스킨이 아직 안 올라온다
|
||||
|
||||
public static void SaveMask(string name, params SkinnedMeshRenderer[] on)
|
||||
{
|
||||
|
|
@ -174,6 +174,25 @@ public static class WLXBake
|
|||
static float S2L(float c) { return c <= 0.04045f ? c / 12.92f : Mathf.Pow((c + 0.055f) / 1.055f, 2.4f); }
|
||||
static float L2S(float c) { return c <= 0.0031308f ? c * 12.92f : 1.055f * Mathf.Pow(c, 1f / 2.4f) - 0.055f; }
|
||||
public static Vector3 LinToSrgb(Vector3 v) { return new Vector3(L2S(v.x), L2S(v.y), L2S(v.z)); }
|
||||
public static Vector3 SrgbToLin(Vector3 v) { return new Vector3(S2L(v.x), S2L(v.y), S2L(v.z)); }
|
||||
|
||||
// 🔴 SrgbAvg = 평균을 sRGB(보이는 밝기)에서 낸다. 선형광 평균은 텍스처의 어두운 선을
|
||||
// 날려 버려 화면에서 머리칼/피부가 밝고 진해진다(1~3회차 실측: L +20 · S +0.11).
|
||||
public static bool SrgbAvg = true;
|
||||
// RestoreSat = 팔레트 칸의 채도를 「그 칸에 속한 덩어리들의 원본 채도」로 되돌린다.
|
||||
public static bool RestoreSat = true;
|
||||
// 부위 그룹별 채도/명도 보정 계수 (1 = 그대로). Hue 는 절대 건드리지 않는다.
|
||||
public static Dictionary<string, float> SGain = new Dictionary<string, float>();
|
||||
public static Dictionary<string, float> VGain = new Dictionary<string, float>();
|
||||
public static string[] palGroup = new string[0];
|
||||
public static string Group(string meshName)
|
||||
{
|
||||
if (meshName == "Head") return "Skin";
|
||||
if (meshName == "Hair05") return "Hair";
|
||||
return "M05";
|
||||
}
|
||||
static Vector3 ToWorkSrgb(Vector3 v) { return SrgbAvg ? v : LinToSrgb(v); }
|
||||
static Lab ToLabAuto(Vector3 v) { return ToLab(SrgbAvg ? SrgbToLin(v) : v); }
|
||||
|
||||
public struct Lab { public float L, a, b; }
|
||||
public static Lab ToLab(Vector3 lin)
|
||||
|
|
@ -219,7 +238,7 @@ public static class WLXBake
|
|||
var px = tmp.GetPixels32();
|
||||
t = new Tex { w = tmp.width, h = tmp.height, lin = new Vector3[px.Length] };
|
||||
for (int i = 0; i < px.Length; i++)
|
||||
t.lin[i] = new Vector3(S2L(px[i].r / 255f), S2L(px[i].g / 255f), S2L(px[i].b / 255f));
|
||||
t.lin[i] = SrgbAvg ? new Vector3(px[i].r / 255f, px[i].g / 255f, px[i].b / 255f) : new Vector3(S2L(px[i].r / 255f), S2L(px[i].g / 255f), S2L(px[i].b / 255f));
|
||||
UnityEngine.Object.DestroyImmediate(tmp);
|
||||
s_tex[path] = t;
|
||||
return t;
|
||||
|
|
@ -310,35 +329,46 @@ public static class WLXBake
|
|||
var assign = new int[roots.Count];
|
||||
for (int i = 0; i < roots.Count; i++)
|
||||
{
|
||||
var lab = ToLab(regions[roots[i]].Col);
|
||||
var lab = ToLabAuto(regions[roots[i]].Col);
|
||||
float bd = float.MaxValue; int bj = 0;
|
||||
for (int j = 0; j < N; j++) { float d = LabD(lab, ToLab(pal[j])); if (d < bd) { bd = d; bj = j; } }
|
||||
for (int j = 0; j < N; j++) { float d = LabD(lab, ToLabAuto(pal[j])); if (d < bd) { bd = d; bj = j; } }
|
||||
assign[i] = bj;
|
||||
}
|
||||
// 🔴 Hue 복원: 팔레트 칸의 H/S 를 그 칸 소속 덩어리들의 원본 H/S 로 되돌린다(채도·면적 가중)
|
||||
var palS = new Vector3[N];
|
||||
palGroup = new string[N];
|
||||
for (int j = 0; j < N; j++)
|
||||
{
|
||||
double hx = 0, hy = 0, sw = 0, ssum = 0, aw = 0;
|
||||
var garea = new double[M];
|
||||
for (int i = 0; i < roots.Count; i++)
|
||||
{
|
||||
if (assign[i] != j) continue;
|
||||
var reg = regions[roots[i]];
|
||||
hx += reg.hx; hy += reg.hy; sw += reg.sw;
|
||||
float h, s, v; RgbToHsv(LinToSrgb(reg.Col), out h, out s, out v);
|
||||
float h, s, v; RgbToHsv(ToWorkSrgb(reg.Col), out h, out s, out v);
|
||||
ssum += s * reg.area; aw += reg.area;
|
||||
garea[reg.mesh] += reg.area;
|
||||
}
|
||||
float ph, ps, pv; RgbToHsv(LinToSrgb(pal[j]), out ph, out ps, out pv);
|
||||
float ph, ps, pv; RgbToHsv(ToWorkSrgb(pal[j]), out ph, out ps, out pv);
|
||||
float hue = sw > 1e-6 ? (float)((Math.Atan2(hy, hx) * 180.0 / Math.PI + 360.0) % 360.0) : ph;
|
||||
float sat = aw > 1e-6 ? (float)(ssum / aw) : ps;
|
||||
float sat = (RestoreSat && aw > 1e-6) ? (float)(ssum / aw) : ps;
|
||||
// 🔴 부위별 채도·명도 보정 — Hue 는 손대지 않는다(발주 §1 「V 만 조절 · Hue ±8°」).
|
||||
// 3~4회차 실측에서 팔레트가 「지금」보다 진하고(S +0.10) 밝게(L +12~23) 나온 것을 되돌린다.
|
||||
int dom = 0; for (int m = 1; m < M; m++) if (garea[m] > garea[dom]) dom = m;
|
||||
string grp = Group(names[dom]);
|
||||
float sg, vg;
|
||||
sat *= SGain.TryGetValue(grp, out sg) ? sg : 1f;
|
||||
pv *= VGain.TryGetValue(grp, out vg) ? vg : 1f;
|
||||
palS[j] = HsvToRgb(hue, sat, pv);
|
||||
palGroup[j] = grp;
|
||||
}
|
||||
double dsum = 0, dw = 0; float dmax = 0;
|
||||
for (int i = 0; i < roots.Count; i++)
|
||||
{
|
||||
var reg = regions[roots[i]];
|
||||
float h0, s0, v0, h1, s1, v1;
|
||||
RgbToHsv(LinToSrgb(reg.Col), out h0, out s0, out v0);
|
||||
RgbToHsv(ToWorkSrgb(reg.Col), out h0, out s0, out v0);
|
||||
RgbToHsv(palS[assign[i]], out h1, out s1, out v1);
|
||||
if (s0 < 0.08f) continue;
|
||||
float d = Mathf.Abs(DHue(h0, h1));
|
||||
|
|
@ -368,7 +398,7 @@ public static class WLXBake
|
|||
AssetDatabase.CreateAsset(nm, p);
|
||||
}
|
||||
res.meshes[names[m]] = nm;
|
||||
L(string.Format(" mesh {0,-9} verts {1,4} -> {2,4}", names[m], srcs[m].vertexCount, nm.vertexCount));
|
||||
L(string.Format(" mesh {0,-9} verts {1,4} -> {2,4} · srcBW {3} newBW {4} bindposes {5} normals {6} tangents {7}", names[m], srcs[m].vertexCount, nm.vertexCount, srcs[m].boneWeights.Length, nm.boneWeights.Length, nm.bindposes.Length, nm.normals.Length, nm.tangents.Length));
|
||||
}
|
||||
if (SaveAssets) AssetDatabase.SaveAssets();
|
||||
Last = res;
|
||||
|
|
@ -408,7 +438,7 @@ public static class WLXBake
|
|||
|
||||
static void AccHue(Region r, Vector3 lin, float area)
|
||||
{
|
||||
float h, s, v; RgbToHsv(LinToSrgb(lin), out h, out s, out v);
|
||||
float h, s, v; RgbToHsv(ToWorkSrgb(lin), out h, out s, out v);
|
||||
float w = s * area;
|
||||
r.hx += w * Mathf.Cos(h * Mathf.Deg2Rad); r.hy += w * Mathf.Sin(h * Mathf.Deg2Rad); r.sw += w;
|
||||
}
|
||||
|
|
@ -530,7 +560,7 @@ public static class WLXBake
|
|||
|
||||
static float Cost(Region a, Region b)
|
||||
{
|
||||
float d = LabD(ToLab(a.Col), ToLab(b.Col));
|
||||
float d = LabD(ToLabAuto(a.Col), ToLabAuto(b.Col));
|
||||
float w = (a.area * b.area) / Mathf.Max(a.area + b.area, 1e-9f);
|
||||
return d * d * w;
|
||||
}
|
||||
|
|
@ -538,7 +568,7 @@ public static class WLXBake
|
|||
static Vector3[] KMeans(Vector3[] cols, float[] wts, int k)
|
||||
{
|
||||
int n = cols.Length;
|
||||
var labs = cols.Select(ToLab).ToArray();
|
||||
var labs = cols.Select(ToLabAuto).ToArray();
|
||||
var cent = new Lab[k]; var centRgb = new Vector3[k];
|
||||
var rnd = new System.Random(12345);
|
||||
var d2 = new float[n];
|
||||
|
|
@ -570,7 +600,7 @@ public static class WLXBake
|
|||
}
|
||||
var sumRgb = new Vector3[k]; var sw = new double[k];
|
||||
for (int i = 0; i < n; i++) { sumRgb[asg[i]] += cols[i] * wts[i]; sw[asg[i]] += wts[i]; }
|
||||
for (int j = 0; j < k; j++) if (sw[j] > 1e-9) { centRgb[j] = sumRgb[j] / (float)sw[j]; cent[j] = ToLab(centRgb[j]); }
|
||||
for (int j = 0; j < k; j++) if (sw[j] > 1e-9) { centRgb[j] = sumRgb[j] / (float)sw[j]; cent[j] = ToLabAuto(centRgb[j]); }
|
||||
if (!ch) break;
|
||||
}
|
||||
return centRgb;
|
||||
|
|
@ -579,14 +609,14 @@ public static class WLXBake
|
|||
static Mesh BuildMesh(Mesh src, List<Face> faces, int f0, int f1, int[] uf, Dictionary<int, int> rootIndex, int[] assign, int G)
|
||||
{
|
||||
var vt = src.vertices; var nmv = src.normals; var tg = src.tangents;
|
||||
var bpv = src.GetBonesPerVertex(); var bw = src.GetAllBoneWeights();
|
||||
var bwStart = new int[vt.Length];
|
||||
{ int acc = 0; for (int i = 0; i < vt.Length; i++) { bwStart[i] = acc; acc += (bpv.Length > 0 ? bpv[i] : 0); } }
|
||||
// 🔴 레거시 boneWeights(4본) 로 옮긴다 — SetBoneWeights(bonesPerVertex, BoneWeight1[]) 로 만든 메시를
|
||||
// .asset 으로 저장하면 SkinnedMeshRenderer 가 "mesh data size and vertex stride" 로 렌더를 멈춘다(실측).
|
||||
var bws = src.boneWeights;
|
||||
|
||||
var map = new Dictionary<long, int>();
|
||||
var nv = new List<Vector3>(); var nn = new List<Vector3>(); var nt = new List<Vector4>();
|
||||
var nuv = new List<Vector2>(); var ntri = new List<int>();
|
||||
var nbpv = new List<byte>(); var nbw = new List<BoneWeight1>();
|
||||
var nbw = new List<BoneWeight>();
|
||||
|
||||
Func<int, int, int> get = (vi, pal) =>
|
||||
{
|
||||
|
|
@ -597,7 +627,7 @@ public static class WLXBake
|
|||
if (nmv != null && nmv.Length > 0) nn.Add(nmv[vi]);
|
||||
if (tg != null && tg.Length > 0) nt.Add(tg[vi]);
|
||||
nuv.Add(new Vector2((pal % G + 0.5f) / G, (pal / G + 0.5f) / G));
|
||||
if (bpv.Length > 0) { nbpv.Add(bpv[vi]); for (int q = 0; q < bpv[vi]; q++) nbw.Add(bw[bwStart[vi] + q]); }
|
||||
if (bws != null && bws.Length > 0) nbw.Add(bws[vi]);
|
||||
return id;
|
||||
};
|
||||
|
||||
|
|
@ -615,13 +645,9 @@ public static class WLXBake
|
|||
if (nt.Count == nv.Count) mesh.SetTangents(nt);
|
||||
mesh.SetUVs(0, nuv);
|
||||
mesh.SetTriangles(ntri, 0);
|
||||
if (nbpv.Count == nv.Count)
|
||||
{
|
||||
var a1 = new NativeArray<byte>(nbpv.ToArray(), Allocator.Temp);
|
||||
var a2 = new NativeArray<BoneWeight1>(nbw.ToArray(), Allocator.Temp);
|
||||
mesh.SetBoneWeights(a1, a2); a1.Dispose(); a2.Dispose();
|
||||
}
|
||||
mesh.bindposes = src.bindposes;
|
||||
if (nbw.Count == nv.Count) mesh.boneWeights = nbw.ToArray();
|
||||
mesh.UploadMeshData(false);
|
||||
mesh.RecalculateBounds();
|
||||
return mesh;
|
||||
}
|
||||
|
|
@ -781,3 +807,488 @@ public static class WLXIter
|
|||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_ITER2.txt"); }
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLXIter3 — 3회차: 얼굴을 고친 상태에서 덩어리·팔레트·셰이드 전수 + 덩어리별 색단계 실측
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
public static class WLXIter3
|
||||
{
|
||||
public static Texture2D F32, F64, FV1, H64, H32;
|
||||
|
||||
public static void LoadTex()
|
||||
{
|
||||
F32 = AssetDatabase.LoadAssetAtPath<Texture2D>(WLXBake.TEX_DIR + "face02_P32.png");
|
||||
F64 = AssetDatabase.LoadAssetAtPath<Texture2D>(WLXBake.TEX_DIR + "face02_P64.png");
|
||||
FV1 = AssetDatabase.LoadAssetAtPath<Texture2D>(WLXBake.TEX_DIR + "face02_V1.png");
|
||||
H64 = AssetDatabase.LoadAssetAtPath<Texture2D>(WLXBake.TEX_DIR + "Hair05_P64.png");
|
||||
H32 = AssetDatabase.LoadAssetAtPath<Texture2D>(WLXBake.TEX_DIR + "Hair05_P32.png");
|
||||
}
|
||||
|
||||
public static void ApplyPalette(WLXBake.Result res, Texture2D faceTex, Texture2D hairTex)
|
||||
{
|
||||
var pal = AssetDatabase.LoadAssetAtPath<Texture2D>(res.palPath);
|
||||
for (int i = 0; i < WLXCap.Smrs.Length; i++)
|
||||
{
|
||||
var r = WLXCap.Smrs[i];
|
||||
var mats = (Material[])WLXCap.OrigMats(i).Clone();
|
||||
Texture2D tex = null; Mesh nm;
|
||||
bool usePal = res.meshes.TryGetValue(r.name, out nm);
|
||||
if (r.name == "Hair05" && hairTex != null) { usePal = false; tex = hairTex; }
|
||||
if (r.name == "Face") { usePal = false; tex = faceTex; }
|
||||
if (usePal) { r.sharedMesh = nm; tex = pal; }
|
||||
if (tex == null) { r.sharedMaterials = mats; continue; }
|
||||
for (int m = 0; m < mats.Length; m++)
|
||||
{
|
||||
if (mats[m] == null) continue;
|
||||
var c = new Material(mats[m]) { name = "TMP_" + mats[m].name };
|
||||
foreach (var pn in new[] { "_BaseMap", "_ShadowBaseMap", "_MainTex" }) if (c.HasProperty(pn)) c.SetTexture(pn, tex);
|
||||
mats[m] = c;
|
||||
}
|
||||
r.sharedMaterials = mats;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>덩어리 ID 를 색으로 찍는다(빛 0) — 「부위(덩어리)당 색 단계」를 재기 위한 지도.</summary>
|
||||
public static void ShootIdMap(WLXBake.Result res, string name)
|
||||
{
|
||||
int N = res.paletteUsed, G = Mathf.CeilToInt(Mathf.Sqrt(N)), S = G * 8;
|
||||
var t = new Texture2D(S, S, TextureFormat.RGBA32, false);
|
||||
t.filterMode = FilterMode.Point; t.wrapMode = TextureWrapMode.Clamp;
|
||||
var px = new Color32[S * S];
|
||||
for (int i = 0; i < px.Length; i++) px[i] = new Color32(0, 0, 0, 255);
|
||||
for (int j = 0; j < N; j++)
|
||||
{
|
||||
int gx = j % G, gy = j / G;
|
||||
var c = new Color32((byte)(8 + j * 7), (byte)(200 - j * 5), (byte)(40 + j * 3), 255);
|
||||
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) px[(gy * 8 + y) * S + gx * 8 + x] = c;
|
||||
}
|
||||
t.SetPixels32(px); t.Apply();
|
||||
var sh = Shader.Find("Unlit/Texture");
|
||||
var keep = new List<SkinnedMeshRenderer>();
|
||||
WLXCap.NoLook();
|
||||
for (int i = 0; i < WLXCap.Smrs.Length; i++)
|
||||
{
|
||||
var r = WLXCap.Smrs[i];
|
||||
Mesh nm;
|
||||
if (res.meshes.TryGetValue(r.name, out nm))
|
||||
{
|
||||
r.sharedMesh = nm;
|
||||
var m = new Material(sh) { name = "TMP_id" }; m.SetTexture("_MainTex", t);
|
||||
r.sharedMaterials = Enumerable.Repeat(m, WLXCap.OrigMats(i).Length).ToArray();
|
||||
}
|
||||
else { r.enabled = false; keep.Add(r); }
|
||||
}
|
||||
WLXCap.Shoot(name);
|
||||
foreach (var r in keep) r.enabled = true;
|
||||
UnityEngine.Object.DestroyImmediate(t);
|
||||
}
|
||||
|
||||
static readonly int[] CH = { 20, 40, 80 };
|
||||
static readonly int[] PN = { 10, 16, 24 };
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
WLXCap.Setup();
|
||||
WLXBake.SaveAssets = false;
|
||||
LoadTex();
|
||||
WLXCap.L("tex loaded f32=" + (F32 != null) + " h64=" + (H64 != null));
|
||||
|
||||
foreach (var ch in CH)
|
||||
foreach (var pn in PN)
|
||||
{
|
||||
string tag = "c" + ch + "p" + pn;
|
||||
WLXBake.Bake(ch, pn, tag);
|
||||
var res = WLXBake.Last;
|
||||
WLXCap.L(string.Format("{0}: regions {1} pal {2} dHue {3:F2}/{4:F2} verts {5}->{6}",
|
||||
tag, res.regionCount, res.paletteUsed, res.meanDHue, res.maxDHue, res.vertsBefore, res.vertsAfter));
|
||||
foreach (var sh in new[] { 3, 2 })
|
||||
{
|
||||
ApplyPalette(res, F32, null);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, sh));
|
||||
WLXCap.Shoot("i3_" + tag + "_s" + sh);
|
||||
WLXCap.NoLook(); WLXCap.RestoreMeshes();
|
||||
}
|
||||
// 머리칼 텍스처안
|
||||
ApplyPalette(res, F32, H64);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, 3));
|
||||
WLXCap.Shoot("i3_" + tag + "_s3_hairtex");
|
||||
WLXCap.NoLook(); WLXCap.RestoreMeshes();
|
||||
ShootIdMap(res, "idmap_" + tag);
|
||||
WLXCap.RestoreMats(); WLXCap.RestoreMeshes();
|
||||
}
|
||||
}
|
||||
catch (Exception e) { WLXCap.L("EXCEPTION " + e); }
|
||||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_ITER3.txt"); }
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLXIter4 — 4회차: 팔레트 색을 고르는 「평균 공간」과 「채도 복원」이 화면 색조에 미치는 영향
|
||||
// 3회차 실측에서 머리칼/피부가 원본보다 밝고(L +20) 진해졌다(S +0.11) → 원인 후보 2개를 A/B
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
public static class WLXIter4
|
||||
{
|
||||
public static void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
WLXCap.Setup();
|
||||
WLXBake.SaveAssets = false;
|
||||
WLXIter3.LoadTex();
|
||||
var combos = new[] {
|
||||
new { name = "srgbSat", srgb = true, sat = true },
|
||||
new { name = "srgbNos", srgb = true, sat = false },
|
||||
new { name = "linNos", srgb = false, sat = false },
|
||||
};
|
||||
foreach (var c in combos)
|
||||
{
|
||||
WLXBake.SrgbAvg = c.srgb; WLXBake.RestoreSat = c.sat;
|
||||
WLXBake.Bake(40, 16, "v_" + c.name);
|
||||
var res = WLXBake.Last;
|
||||
WLXCap.L(string.Format("{0}: regions {1} pal {2} dHue {3:F2}/{4:F2}", c.name, res.regionCount, res.paletteUsed, res.meanDHue, res.maxDHue));
|
||||
foreach (var sh in new[] { 3, 2 })
|
||||
{
|
||||
WLXIter3.ApplyPalette(res, WLXIter3.F32, null);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, sh));
|
||||
WLXCap.Shoot("i4_" + c.name + "_s" + sh);
|
||||
WLXCap.NoLook(); WLXCap.RestoreMeshes();
|
||||
}
|
||||
}
|
||||
WLXBake.SrgbAvg = true; WLXBake.RestoreSat = true;
|
||||
}
|
||||
catch (Exception e) { WLXCap.L("EXCEPTION " + e); }
|
||||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_ITER4.txt"); }
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLXIter5 — 5회차: 「지금」과 색조(채도·밝기)를 맞추는 보정 계수 탐색 (Hue 무변경)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
public static class WLXIter5
|
||||
{
|
||||
static void SetGain(float sM, float sS, float sH, float vM, float vS, float vH)
|
||||
{
|
||||
WLXBake.SGain = new Dictionary<string, float> { { "M05", sM }, { "Skin", sS }, { "Hair", sH } };
|
||||
WLXBake.VGain = new Dictionary<string, float> { { "M05", vM }, { "Skin", vS }, { "Hair", vH } };
|
||||
}
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
WLXCap.Setup();
|
||||
WLXBake.SaveAssets = false;
|
||||
WLXIter3.LoadTex();
|
||||
WLXBake.SrgbAvg = true; WLXBake.RestoreSat = true;
|
||||
|
||||
var sets = new[] {
|
||||
new { n = "g0none", s = new[]{1f,1f,1f}, v = new[]{1f,1f,1f} },
|
||||
new { n = "g1soft", s = new[]{0.80f,0.86f,0.85f}, v = new[]{1.00f,0.93f,0.93f} },
|
||||
new { n = "g2hard", s = new[]{0.72f,0.78f,0.78f}, v = new[]{1.00f,0.86f,0.88f} },
|
||||
new { n = "g3sat", s = new[]{0.80f,0.86f,0.85f}, v = new[]{1f,1f,1f} },
|
||||
};
|
||||
foreach (var g in sets)
|
||||
{
|
||||
SetGain(g.s[0], g.s[1], g.s[2], g.v[0], g.v[1], g.v[2]);
|
||||
WLXBake.Bake(40, 16, "g_" + g.n);
|
||||
var res = WLXBake.Last;
|
||||
WLXCap.L(string.Format("{0}: dHue {1:F2}/{2:F2}", g.n, res.meanDHue, res.maxDHue));
|
||||
WLXIter3.ApplyPalette(res, WLXIter3.F32, null);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, 3));
|
||||
WLXCap.Shoot("i5_" + g.n + "_s3");
|
||||
WLXCap.NoLook(); WLXCap.RestoreMeshes();
|
||||
}
|
||||
SetGain(1f, 1f, 1f, 1f, 1f, 1f);
|
||||
}
|
||||
catch (Exception e) { WLXCap.L("EXCEPTION " + e); }
|
||||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_ITER5.txt"); }
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLXFinal — 최종 채택본 굽기 + 에셋 배선 (덩어리 40 · 팔레트 16 · sRGB 평균 · g1soft 보정)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
public static class WLXFinal
|
||||
{
|
||||
const string MAT = "Assets/WL/Look/Character/Materials/";
|
||||
const string TEX = "Assets/WL/Look/Character/Textures/";
|
||||
const string SO = "Assets/WL/Look/Character/Resources/WL/WLCharacterPaletteSettings.asset";
|
||||
public const int CHUNKS = 40, PAL = 16;
|
||||
public const float SHADES = 3f;
|
||||
|
||||
static readonly StringBuilder sb = new StringBuilder();
|
||||
static void L(string s) { sb.AppendLine(s); }
|
||||
|
||||
public static void SetFinalGain()
|
||||
{
|
||||
WLXBake.SrgbAvg = true; WLXBake.RestoreSat = true;
|
||||
WLXBake.SGain = new Dictionary<string, float> { { "M05", 0.80f }, { "Skin", 0.86f }, { "Hair", 0.85f } };
|
||||
WLXBake.VGain = new Dictionary<string, float> { { "M05", 1.00f }, { "Skin", 0.93f }, { "Hair", 0.93f } };
|
||||
}
|
||||
|
||||
public static string Build()
|
||||
{
|
||||
sb.Length = 0;
|
||||
try
|
||||
{
|
||||
SetFinalGain();
|
||||
WLXBake.SaveAssets = true;
|
||||
L(WLXBake.Bake(CHUNKS, PAL, "FINAL"));
|
||||
var res = WLXBake.Last;
|
||||
var pal = AssetDatabase.LoadAssetAtPath<Texture2D>(res.palPath);
|
||||
|
||||
// 얼굴 점텍스처(1텍셀 = 1화면 px) — 814v V1 의 격자 1칸을 1텍셀로
|
||||
string fp = WLXBake.MakePointTex(TEX + "face02_V1.png", 32, "face02_P32", true);
|
||||
var faceTex = AssetDatabase.LoadAssetAtPath<Texture2D>(fp);
|
||||
L("face tex " + fp + " " + (faceTex != null ? faceTex.width + "x" + faceTex.height : "?"));
|
||||
|
||||
// 머티리얼 복사본
|
||||
var mM05 = MakeMat("M05_ToonS", "M05_ToonP", pal, true);
|
||||
var mSkin = MakeMat("Skin_ToonS", "Skin_ToonP", pal, true);
|
||||
var mHair = MakeMat("Hair05_ToonS", "Hair05_ToonP", pal, true);
|
||||
var mFace = MakeMat("face02_ToonS", "face02_ToonP", faceTex, false);
|
||||
|
||||
// SO
|
||||
var so = AssetDatabase.LoadAssetAtPath<WL.Look.Character.WLCharacterPaletteSettings>(SO);
|
||||
if (so == null)
|
||||
{
|
||||
so = ScriptableObject.CreateInstance<WL.Look.Character.WLCharacterPaletteSettings>();
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(SO));
|
||||
AssetDatabase.CreateAsset(so, SO);
|
||||
}
|
||||
var names = new[] { "Arm_m05", "Body_m05", "Leg_M05", "Head", "Hair05", "Face" };
|
||||
var meshes = new Mesh[names.Length];
|
||||
var mats = new Material[names.Length];
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (names[i] != "Face")
|
||||
meshes[i] = AssetDatabase.LoadAssetAtPath<Mesh>(WLXBake.MESH_DIR + names[i] + "_PAL_FINAL.asset");
|
||||
mats[i] = names[i] == "Head" ? mSkin : names[i] == "Hair05" ? mHair : names[i] == "Face" ? mFace : mM05;
|
||||
L(string.Format(" [{0}] {1,-9} mesh={2} mat={3}", i, names[i], meshes[i] != null ? meshes[i].name : "-", mats[i] != null ? mats[i].name : "-"));
|
||||
}
|
||||
so.enabled_ = 1; so.verboseLog = 0;
|
||||
so.rendererNames = names; so.paletteMeshes = meshes; so.paletteMaterials = mats;
|
||||
EditorUtility.SetDirty(so);
|
||||
|
||||
// 임시 산출물 정리 (비교용으로 만든 팔레트/텍스처)
|
||||
foreach (var g in AssetDatabase.FindAssets("WLPalette_", new[] { "Assets/WL/Look/Character/Textures" }))
|
||||
{
|
||||
string p = AssetDatabase.GUIDToAssetPath(g);
|
||||
if (!p.EndsWith("WLPalette_FINAL.png")) { AssetDatabase.DeleteAsset(p); L(" del " + p); }
|
||||
}
|
||||
foreach (var f in new[] { "face02_P64.png", "Hair05_P32.png" })
|
||||
if (AssetDatabase.LoadAssetAtPath<Texture2D>(TEX + f) != null) { AssetDatabase.DeleteAsset(TEX + f); L(" del " + TEX + f); }
|
||||
foreach (var g in AssetDatabase.FindAssets("_PAL_", new[] { "Assets/WL/Look/Character/Meshes" }))
|
||||
{
|
||||
string p = AssetDatabase.GUIDToAssetPath(g);
|
||||
if (!p.Contains("_PAL_FINAL")) { AssetDatabase.DeleteAsset(p); L(" del " + p); }
|
||||
}
|
||||
AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
|
||||
L("DONE");
|
||||
}
|
||||
catch (Exception e) { L("EXCEPTION " + e); }
|
||||
finally { File.WriteAllText("AgentScripts/WL814x_FINAL.txt", sb.ToString(), new UTF8Encoding(true)); }
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
static Material MakeMat(string src, string dst, Texture2D tex, bool toon)
|
||||
{
|
||||
var s = AssetDatabase.LoadAssetAtPath<Material>(MAT + src + ".mat");
|
||||
if (s == null) { L("!! no src mat " + src); return null; }
|
||||
var m = AssetDatabase.LoadAssetAtPath<Material>(MAT + dst + ".mat");
|
||||
if (m == null) { m = new Material(s); AssetDatabase.CreateAsset(m, MAT + dst + ".mat"); }
|
||||
else { m.shader = s.shader; m.CopyPropertiesFromMaterial(s); }
|
||||
foreach (var pn in new[] { "_BaseMap", "_ShadowBaseMap", "_MainTex" }) if (m.HasProperty(pn)) m.SetTexture(pn, tex);
|
||||
if (toon && m.HasProperty("_Shades")) m.SetFloat("_Shades", SHADES); // 부위당 색 단계 ≤ 4
|
||||
EditorUtility.SetDirty(m);
|
||||
L(" mat " + dst + " shader=" + m.shader.name + " tex=" + (tex != null ? tex.name : "-") + (toon ? " shades=" + SHADES : ""));
|
||||
return m;
|
||||
}
|
||||
|
||||
/// <summary>최종 검증 — 런타임 경로(WLCharacterLook.Apply)로 적용해서 찍는다 + 되돌리기 확인.</summary>
|
||||
public static void Verify()
|
||||
{
|
||||
try
|
||||
{
|
||||
WLXCap.Setup();
|
||||
var lookCfg = WL.Look.Character.WLCharacterLookSettings.Instance;
|
||||
var palCfg = WL.Look.Character.WLCharacterPaletteSettings.Instance;
|
||||
WLXCap.L("palette SO = " + (palCfg != null ? "found enabled_=" + palCfg.enabled_ : "NULL"));
|
||||
// 🔴 워밍업: 세션에서 스킨 메시를 처음 갈아끼운 직후의 첫 Camera.Render() 는
|
||||
// "mesh data size and vertex stride" 로 렌더가 멈춘다(에디터 한정 · 실측).
|
||||
// 한 번 갈아끼우고 버리는 렌더를 돌린 뒤 본 촬영을 한다.
|
||||
palCfg.enabled_ = 1;
|
||||
WL.Look.Character.WLCharacterLook.Apply(WLXCap.Root);
|
||||
for (int w = 0; w < 3; w++) WLXCap.Render(Color.black);
|
||||
WLXCap.RestoreMeshes(); WLXCap.RestoreMats();
|
||||
for (int w = 0; w < 2; w++) WLXCap.Render(Color.black);
|
||||
|
||||
// ① enabled_ = 0 → 814s+814t 상태 100 % 여야 한다
|
||||
int keep = palCfg.enabled_;
|
||||
palCfg.enabled_ = 0;
|
||||
WL.Look.Character.WLCharacterLook.Apply(WLXCap.Root);
|
||||
WLXCap.L("off: " + WL.Look.Character.WLCharacterPalette.LastLog);
|
||||
for (int i = 0; i < WLXCap.Smrs.Length; i++)
|
||||
WLXCap.L(" off " + WLXCap.Smrs[i].name + " mesh=" + WLXCap.Smrs[i].sharedMesh.name + " mat=" + WLXCap.Smrs[i].sharedMaterial.name);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, true, 0));
|
||||
WLXCap.Shoot("z_off_now"); WLXCap.NoLook();
|
||||
|
||||
// ② enabled_ = 1 → 팔레트
|
||||
palCfg.enabled_ = 1;
|
||||
WL.Look.Character.WLCharacterLook.Apply(WLXCap.Root);
|
||||
// 🔴 스킨 메시를 갈아끼운 직후 에디터에서 곧바로 Camera.Render() 하면
|
||||
// "mesh data size and vertex stride" 로 렌더가 멈춘다 → 에디터 틱을 한 번 돌린다.
|
||||
AssetDatabase.Refresh();
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
||||
WLXCap.L("on: " + WL.Look.Character.WLCharacterPalette.LastLog);
|
||||
for (int i = 0; i < WLXCap.Smrs.Length; i++)
|
||||
{
|
||||
var r0 = WLXCap.Smrs[i]; var m0 = r0.sharedMaterial;
|
||||
WLXCap.L(" on " + r0.name + " mesh=" + r0.sharedMesh.name + " mat=" + m0.name
|
||||
+ " tris=" + (r0.sharedMesh.triangles.Length / 3) + " verts=" + r0.sharedMesh.vertexCount
|
||||
+ " en=" + r0.enabled + " vis=" + r0.isVisible + " shader=" + (m0.shader != null ? m0.shader.name : "NULL")
|
||||
+ " base=" + (m0.HasProperty("_BaseMap") ? (m0.GetTexture("_BaseMap") != null ? m0.GetTexture("_BaseMap").name : "NULL") : "-")
|
||||
+ " shadow=" + (m0.HasProperty("_ShadowBaseMap") ? (m0.GetTexture("_ShadowBaseMap") != null ? m0.GetTexture("_ShadowBaseMap").name : "NULL") : "-")
|
||||
+ " shades=" + (m0.HasProperty("_Shades") ? m0.GetFloat("_Shades").ToString("F1") : "-")
|
||||
+ " bnd=" + r0.bounds.size.ToString("F2") + " lay=" + r0.gameObject.layer);
|
||||
}
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, 0));
|
||||
WLXCap.Shoot("z_final"); WLXCap.NoLook();
|
||||
// 림을 켠 종합안도 한 장(대조)
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, true, 0));
|
||||
WLXCap.Shoot("z_final_rimon"); WLXCap.NoLook();
|
||||
// 외곽선 없는 것(외곽선 1px 확인용)
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(false, true, true, false, 0));
|
||||
WLXCap.Shoot("z_final_noout"); WLXCap.NoLook();
|
||||
|
||||
// 덩어리 지도
|
||||
WLXFinal.SetFinalGain();
|
||||
WLXBake.SaveAssets = false;
|
||||
WLXBake.Bake(CHUNKS, PAL, "idm");
|
||||
WLXIter3.ShootIdMap(WLXBake.Last, "idmap_FINAL");
|
||||
AssetDatabase.DeleteAsset(WLXBake.Last.palPath);
|
||||
|
||||
palCfg.enabled_ = keep;
|
||||
}
|
||||
catch (Exception e) { WLXCap.L("EXCEPTION " + e); }
|
||||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_VERIFY.txt"); }
|
||||
}
|
||||
|
||||
/// <summary>회전 떨림 — 연속 8프레임(1°씩)의 픽셀 변화율. 814u 와 같은 축.</summary>
|
||||
public static void Jitter()
|
||||
{
|
||||
try
|
||||
{
|
||||
WLXCap.Setup();
|
||||
var palCfg = WL.Look.Character.WLCharacterPaletteSettings.Instance;
|
||||
float yaw0 = WLXCap.Root.transform.eulerAngles.y;
|
||||
foreach (var on in new[] { 0, 1 })
|
||||
{
|
||||
palCfg.enabled_ = on;
|
||||
WL.Look.Character.WLCharacterLook.Apply(WLXCap.Root);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, on == 0, 0));
|
||||
var prev = (WLXCap.Shot)null;
|
||||
double sum = 0; int n = 0; double mx = 0;
|
||||
for (int f = 0; f < 8; f++)
|
||||
{
|
||||
WLXCap.Root.transform.rotation = Quaternion.Euler(0, yaw0 + f, 0);
|
||||
var s = WLXCap.Render(new Color(0.10f, 0.10f, 0.12f));
|
||||
if (prev != null)
|
||||
{
|
||||
int diff = 0, tot = 0;
|
||||
for (int i = 0; i < s.px.Length; i++)
|
||||
{
|
||||
var a = prev.px[i]; var b = s.px[i];
|
||||
bool bg = a.r == 25 && a.g == 25 && a.b == 30 && b.r == 25 && b.g == 25 && b.b == 30;
|
||||
if (bg) continue;
|
||||
tot++;
|
||||
if (Mathf.Abs(a.r - b.r) + Mathf.Abs(a.g - b.g) + Mathf.Abs(a.b - b.b) > 12) diff++;
|
||||
}
|
||||
double r = tot > 0 ? 100.0 * diff / tot : 0;
|
||||
sum += r; n++; if (r > mx) mx = r;
|
||||
}
|
||||
prev = s;
|
||||
}
|
||||
WLXCap.L(string.Format("회전 떨림 {0}: 평균 {1:F2} % · 최대 {2:F2} % (8프레임 · 1°/프레임)", on == 0 ? "지금" : "팔레트", sum / Mathf.Max(n, 1), mx));
|
||||
WLXCap.NoLook();
|
||||
}
|
||||
WLXCap.Root.transform.rotation = Quaternion.Euler(0, yaw0, 0);
|
||||
palCfg.enabled_ = 1;
|
||||
}
|
||||
catch (Exception e) { WLXCap.L("EXCEPTION " + e); }
|
||||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_JITTER.txt"); }
|
||||
}
|
||||
|
||||
/// <summary>저장된 메시 에셋이 스킨 데이터를 제대로 들고 있는지 확인(렌더 정지 원인 추적).</summary>
|
||||
public static string CheckMesh()
|
||||
{
|
||||
var sb2 = new StringBuilder();
|
||||
foreach (var n in new[] { "Arm_m05", "Body_m05", "Leg_M05", "Head", "Hair05" })
|
||||
{
|
||||
var p = WLXBake.MESH_DIR + n + "_PAL_FINAL.asset";
|
||||
var m = AssetDatabase.LoadAssetAtPath<Mesh>(p);
|
||||
var src = AssetDatabase.LoadAllAssetsAtPath("Assets/Suriyun/Characters/RedKnight/FBX/Characters/M05.fbx").OfType<Mesh>().FirstOrDefault(x => x.name == n);
|
||||
sb2.AppendLine(n + " : " + (m == null ? "NULL" :
|
||||
"verts " + m.vertexCount + " bw " + m.boneWeights.Length + " bind " + m.bindposes.Length
|
||||
+ " attrs [" + string.Join(",", m.GetVertexAttributes().Select(a => a.attribute + ":" + a.format + "x" + a.dimension + "@" + a.stream)) + "]"));
|
||||
if (src != null)
|
||||
sb2.AppendLine(" src: attrs [" + string.Join(",", src.GetVertexAttributes().Select(a => a.attribute + ":" + a.format + "x" + a.dimension + "@" + a.stream)) + "]");
|
||||
}
|
||||
File.WriteAllText("AgentScripts/WL814x_MESHCHK.txt", sb2.ToString(), new UTF8Encoding(true));
|
||||
return sb2.ToString();
|
||||
}
|
||||
|
||||
/// <summary>메모리 메시 vs 에셋 메시 — 렌더 정지의 원인이 「에셋 저장」인지 가린다.</summary>
|
||||
public static void Diag2()
|
||||
{
|
||||
try
|
||||
{
|
||||
WLXCap.Setup();
|
||||
SetFinalGain();
|
||||
WLXBake.SaveAssets = false;
|
||||
WLXBake.Bake(CHUNKS, PAL, "memchk");
|
||||
var res = WLXBake.Last;
|
||||
WLXIter3.ApplyPalette(res, WLXIter3.F32, null);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, 0));
|
||||
WLXCap.Shoot("q_mem"); WLXCap.NoLook(); WLXCap.RestoreMeshes(); WLXCap.RestoreMats();
|
||||
|
||||
// 같은 팔레트 텍스처로 에셋 메시만 바꿔 끼운다
|
||||
var palTex = AssetDatabase.LoadAssetAtPath<Texture2D>(res.palPath);
|
||||
foreach (var r in WLXCap.Smrs)
|
||||
{
|
||||
var am = AssetDatabase.LoadAssetAtPath<Mesh>(WLXBake.MESH_DIR + r.name + "_PAL_FINAL.asset");
|
||||
if (am == null) continue;
|
||||
r.sharedMesh = am;
|
||||
WLXCap.L("asset " + r.name + " verts " + am.vertexCount + " bw " + am.boneWeights.Length + " readable " + am.isReadable);
|
||||
}
|
||||
var finalPal = AssetDatabase.LoadAssetAtPath<Texture2D>(WLXBake.TEX_DIR + "WLPalette_FINAL.png");
|
||||
for (int i = 0; i < WLXCap.Smrs.Length; i++)
|
||||
{
|
||||
var mats = (Material[])WLXCap.OrigMats(i).Clone();
|
||||
var tex = WLXCap.Smrs[i].name == "Face" ? WLXIter3.F32 : finalPal;
|
||||
for (int m = 0; m < mats.Length; m++)
|
||||
{
|
||||
var c = new Material(mats[m]) { name = "TMP2" };
|
||||
foreach (var pn in new[] { "_BaseMap", "_ShadowBaseMap", "_MainTex" }) if (c.HasProperty(pn)) c.SetTexture(pn, tex);
|
||||
if (c.HasProperty("_Shades")) c.SetFloat("_Shades", 3f);
|
||||
mats[m] = c;
|
||||
}
|
||||
WLXCap.Smrs[i].sharedMaterials = mats;
|
||||
}
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, 0));
|
||||
WLXCap.Shoot("q_asset"); WLXCap.NoLook();
|
||||
// 같은 런에서 런타임 경로(SO 머티리얼 + SO 메시)로도 찍어 본다
|
||||
WLXCap.RestoreMeshes(); WLXCap.RestoreMats();
|
||||
WL.Look.Character.WLCharacterLook.Apply(WLXCap.Root);
|
||||
WLXCap.L("runtime: " + WL.Look.Character.WLCharacterPalette.LastLog);
|
||||
WLXCap.ApplyLook(WLXCap.LookOpt(true, true, true, false, 0));
|
||||
WLXCap.Shoot("q_runtime"); WLXCap.NoLook();
|
||||
AssetDatabase.DeleteAsset(res.palPath);
|
||||
}
|
||||
catch (Exception e) { WLXCap.L("EXCEPTION " + e); }
|
||||
finally { WLXCap.Teardown(); WLXCap.Flush("WL814x_DIAG2.txt"); }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -103,8 +103,10 @@ def measure(img, msk, ref_hue=None, skinL=None):
|
|||
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))
|
||||
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:
|
||||
|
|
@ -118,6 +120,10 @@ def main():
|
|||
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:
|
||||
|
|
@ -167,12 +173,23 @@ def main():
|
|||
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("%-28s %8s %8s %8s %8s" % ("render", "dH몸통", "dH피부", "dH머리칼", "dH얼굴"))
|
||||
print("%-26s | %-22s | %-22s | %s" % ("render", "dHue 몸통/피부/머리칼", "채도S 몸통/피부/머리칼", "밝기L 몸통/피부/머리칼"))
|
||||
b0 = rows[0]
|
||||
for r in rows:
|
||||
def g(p):
|
||||
x = r.get(p)
|
||||
return ("%+.1f" % x["dhue"]) if (x and "dhue" in x) else "ref"
|
||||
print("%-28s %8s %8s %8s %8s" % (r["name"], g("body3"), g("Head"), g("Hair05"), g("Face")))
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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')
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2ad4735b15308b94ca1bd78da99c3ee1
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9161c6a9a87cab1438eb74cecad72893
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 470ec749ed9afb843a0bca59f47eea68
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9e63e2e61895e324099928771be402cd
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c4b2eca5a27bfdf4e802a23edf5e8d7e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 4300000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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}
|
||||
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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:
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dbb1204c1ba8048468874a4a590cfe27
|
||||
|
|
@ -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; } }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 254b7d1576e32124295b43c0dd1f76a0
|
||||
Loading…
Reference in New Issue