reze-engine 0.12.1 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +102 -61
  2. package/dist/engine.d.ts +9 -4
  3. package/dist/engine.d.ts.map +1 -1
  4. package/dist/engine.js +62 -18
  5. package/dist/shaders/body.d.ts +1 -1
  6. package/dist/shaders/body.d.ts.map +1 -1
  7. package/dist/shaders/body.js +7 -28
  8. package/dist/shaders/cloth_rough.d.ts +1 -1
  9. package/dist/shaders/cloth_rough.d.ts.map +1 -1
  10. package/dist/shaders/cloth_rough.js +4 -16
  11. package/dist/shaders/cloth_smooth.d.ts +1 -1
  12. package/dist/shaders/cloth_smooth.d.ts.map +1 -1
  13. package/dist/shaders/cloth_smooth.js +5 -17
  14. package/dist/shaders/default.d.ts +1 -1
  15. package/dist/shaders/default.d.ts.map +1 -1
  16. package/dist/shaders/eye.d.ts +1 -1
  17. package/dist/shaders/eye.d.ts.map +1 -1
  18. package/dist/shaders/face.d.ts +1 -1
  19. package/dist/shaders/face.d.ts.map +1 -1
  20. package/dist/shaders/face.js +21 -57
  21. package/dist/shaders/hair.d.ts +1 -1
  22. package/dist/shaders/hair.d.ts.map +1 -1
  23. package/dist/shaders/hair.js +7 -27
  24. package/dist/shaders/materials/body.d.ts +1 -1
  25. package/dist/shaders/materials/body.d.ts.map +1 -1
  26. package/dist/shaders/materials/body.js +86 -197
  27. package/dist/shaders/materials/cloth_rough.d.ts +1 -1
  28. package/dist/shaders/materials/cloth_rough.d.ts.map +1 -1
  29. package/dist/shaders/materials/cloth_rough.js +11 -122
  30. package/dist/shaders/materials/cloth_smooth.d.ts +1 -1
  31. package/dist/shaders/materials/cloth_smooth.d.ts.map +1 -1
  32. package/dist/shaders/materials/cloth_smooth.js +59 -172
  33. package/dist/shaders/materials/common.d.ts +6 -0
  34. package/dist/shaders/materials/common.d.ts.map +1 -0
  35. package/dist/shaders/materials/common.js +160 -0
  36. package/dist/shaders/materials/default.d.ts +1 -1
  37. package/dist/shaders/materials/default.d.ts.map +1 -1
  38. package/dist/shaders/materials/default.js +13 -146
  39. package/dist/shaders/materials/eye.d.ts +1 -1
  40. package/dist/shaders/materials/eye.d.ts.map +1 -1
  41. package/dist/shaders/materials/eye.js +13 -118
  42. package/dist/shaders/materials/face.d.ts +1 -1
  43. package/dist/shaders/materials/face.d.ts.map +1 -1
  44. package/dist/shaders/materials/face.js +85 -197
  45. package/dist/shaders/materials/hair.d.ts +1 -1
  46. package/dist/shaders/materials/hair.d.ts.map +1 -1
  47. package/dist/shaders/materials/hair.js +78 -183
  48. package/dist/shaders/materials/metal.d.ts +1 -1
  49. package/dist/shaders/materials/metal.d.ts.map +1 -1
  50. package/dist/shaders/materials/metal.js +16 -122
  51. package/dist/shaders/materials/nodes.d.ts +1 -1
  52. package/dist/shaders/materials/nodes.d.ts.map +1 -1
  53. package/dist/shaders/materials/nodes.js +77 -0
  54. package/dist/shaders/materials/stockings.d.ts +1 -1
  55. package/dist/shaders/materials/stockings.d.ts.map +1 -1
  56. package/dist/shaders/materials/stockings.js +26 -152
  57. package/dist/shaders/metal.d.ts +1 -1
  58. package/dist/shaders/metal.d.ts.map +1 -1
  59. package/dist/shaders/metal.js +4 -17
  60. package/dist/shaders/nodes.d.ts +1 -1
  61. package/dist/shaders/nodes.d.ts.map +1 -1
  62. package/dist/shaders/nodes.js +0 -9
  63. package/dist/shaders/passes/bloom.d.ts +1 -1
  64. package/dist/shaders/passes/bloom.d.ts.map +1 -1
  65. package/dist/shaders/passes/bloom.js +7 -4
  66. package/dist/shaders/passes/composite.d.ts +1 -1
  67. package/dist/shaders/passes/composite.d.ts.map +1 -1
  68. package/dist/shaders/passes/composite.js +11 -4
  69. package/dist/shaders/passes/ground.d.ts +1 -1
  70. package/dist/shaders/passes/ground.d.ts.map +1 -1
  71. package/dist/shaders/passes/ground.js +6 -2
  72. package/dist/shaders/passes/outline.d.ts +1 -1
  73. package/dist/shaders/passes/outline.d.ts.map +1 -1
  74. package/dist/shaders/passes/outline.js +2 -2
  75. package/dist/shaders/stockings.d.ts +1 -1
  76. package/dist/shaders/stockings.d.ts.map +1 -1
  77. package/package.json +1 -1
  78. package/src/engine.ts +60 -18
  79. package/src/shaders/materials/body.ts +90 -201
  80. package/src/shaders/materials/cloth_rough.ts +11 -122
  81. package/src/shaders/materials/cloth_smooth.ts +63 -176
  82. package/src/shaders/materials/common.ts +171 -0
  83. package/src/shaders/materials/default.ts +13 -146
  84. package/src/shaders/materials/eye.ts +13 -118
  85. package/src/shaders/materials/face.ts +89 -201
  86. package/src/shaders/materials/hair.ts +82 -187
  87. package/src/shaders/materials/metal.ts +16 -122
  88. package/src/shaders/materials/nodes.ts +77 -0
  89. package/src/shaders/materials/stockings.ts +27 -153
  90. package/src/shaders/passes/bloom.ts +7 -4
  91. package/src/shaders/passes/composite.ts +11 -4
  92. package/src/shaders/passes/ground.ts +6 -2
  93. package/src/shaders/passes/outline.ts +2 -2
  94. package/dist/bezier-interpolate.d.ts +0 -15
  95. package/dist/bezier-interpolate.d.ts.map +0 -1
  96. package/dist/bezier-interpolate.js +0 -40
  97. package/dist/engine_ts.d.ts +0 -143
  98. package/dist/engine_ts.d.ts.map +0 -1
  99. package/dist/engine_ts.js +0 -1575
  100. package/dist/ik.d.ts +0 -32
  101. package/dist/ik.d.ts.map +0 -1
  102. package/dist/ik.js +0 -337
  103. package/dist/player.d.ts +0 -64
  104. package/dist/player.d.ts.map +0 -1
  105. package/dist/player.js +0 -220
  106. package/dist/pool-scene.d.ts +0 -52
  107. package/dist/pool-scene.d.ts.map +0 -1
  108. package/dist/pool-scene.js +0 -1122
  109. package/dist/pool.d.ts +0 -38
  110. package/dist/pool.d.ts.map +0 -1
  111. package/dist/pool.js +0 -422
  112. package/dist/rzm-converter.d.ts +0 -12
  113. package/dist/rzm-converter.d.ts.map +0 -1
  114. package/dist/rzm-converter.js +0 -40
  115. package/dist/rzm-loader.d.ts +0 -24
  116. package/dist/rzm-loader.d.ts.map +0 -1
  117. package/dist/rzm-loader.js +0 -488
  118. package/dist/rzm-writer.d.ts +0 -27
  119. package/dist/rzm-writer.d.ts.map +0 -1
  120. package/dist/rzm-writer.js +0 -701
@@ -1,79 +1,17 @@
1
- // M_Stockings — 仿深空之眼渲染预设v1.0_by_小绿毛猫_material_graph_dump.json "M_Stockings".
2
- // NPR mask (bbox gradient × facing rim) drives Mix Shader between an Emission (HSV-boosted texture)
3
- // and a Principled BSDF with sheen. Mapping rotation + Generated-like coord approximated via UV,
4
- // since our Y-up PMX engine has no object bbox; the gradient is a soft mask, not a hard landmark.
1
+ // M_Stockings — 仿深空之眼渲染预设v1.0_by_小绿毛猫 "M_Stockings". A bbox-gradient ×
2
+ // facing-rim mask drives a Mix Shader between an HSV-boosted emission and a sheen
3
+ // Principled BSDF. Wyman hashed-alpha testing replaces the graph's Alpha=0.95 (which
4
+ // would require TAA to hide the dither dots across every pixel).
5
5
 
6
6
  import { NODES_WGSL } from "./nodes"
7
+ import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
7
8
 
8
9
  export const STOCKINGS_SHADER_WGSL = /* wgsl */ `
9
10
 
10
11
  ${NODES_WGSL}
12
+ ${COMMON_MATERIAL_PRELUDE_WGSL}
11
13
 
12
- struct CameraUniforms {
13
- view: mat4x4f,
14
- projection: mat4x4f,
15
- viewPos: vec3f,
16
- _padding: f32,
17
- };
18
-
19
- struct Light {
20
- direction: vec4f,
21
- color: vec4f,
22
- };
23
-
24
- struct LightUniforms {
25
- ambientColor: vec4f,
26
- lights: array<Light, 4>,
27
- };
28
-
29
- struct MaterialUniforms {
30
- diffuseColor: vec3f,
31
- alpha: f32,
32
- };
33
-
34
- struct VertexOutput {
35
- @builtin(position) position: vec4f,
36
- @location(0) normal: vec3f,
37
- @location(1) uv: vec2f,
38
- @location(2) worldPos: vec3f,
39
- };
40
-
41
- struct LightVP { viewProj: mat4x4f, };
42
-
43
- @group(0) @binding(0) var<uniform> camera: CameraUniforms;
44
- @group(0) @binding(1) var<uniform> light: LightUniforms;
45
- @group(0) @binding(2) var diffuseSampler: sampler;
46
- @group(0) @binding(3) var shadowMap: texture_depth_2d;
47
- @group(0) @binding(4) var shadowSampler: sampler_comparison;
48
- @group(0) @binding(5) var<uniform> lightVP: LightVP;
49
- @group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
50
- @group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
51
- @group(2) @binding(1) var<uniform> material: MaterialUniforms;
52
-
53
- fn sampleShadow(worldPos: vec3f, n: vec3f) -> f32 {
54
- // Back-facing to key light: direct contribution is zero anyway, skip 9 texture samples.
55
- if (dot(n, -light.lights[0].direction.xyz) <= 0.0) { return 0.0; }
56
- let biasedPos = worldPos + n * 0.08;
57
- let lclip = lightVP.viewProj * vec4f(biasedPos, 1.0);
58
- let ndc = lclip.xyz / max(lclip.w, 1e-6);
59
- let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
60
- let cmpZ = ndc.z - 0.001;
61
- let ts = 1.0 / 2048.0;
62
- // 3x3 PCF unrolled — Safari's Metal backend doesn't unroll nested shadow loops reliably.
63
- let s00 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(-ts, -ts), cmpZ);
64
- let s10 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(0.0, -ts), cmpZ);
65
- let s20 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f( ts, -ts), cmpZ);
66
- let s01 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(-ts, 0.0), cmpZ);
67
- let s11 = textureSampleCompareLevel(shadowMap, shadowSampler, suv, cmpZ);
68
- let s21 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f( ts, 0.0), cmpZ);
69
- let s02 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(-ts, ts), cmpZ);
70
- let s12 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(0.0, ts), cmpZ);
71
- let s22 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f( ts, ts), cmpZ);
72
- return (s00 + s10 + s20 + s01 + s11 + s21 + s02 + s12 + s22) * (1.0 / 9.0);
73
- }
74
-
75
- const PI_S: f32 = 3.141592653589793;
76
- // Principled BSDF params from dump (Alpha=0.95 is intentionally dropped — see alpha-hash note below)
14
+ // Principled params from dump (Alpha=0.95 intentionally dropped — see hash note below).
77
15
  const STOCK_METALLIC: f32 = 0.1;
78
16
  const STOCK_SPECULAR: f32 = 1.0;
79
17
  const STOCK_ROUGHNESS: f32 = 0.5;
@@ -84,12 +22,6 @@ const STOCK_RAMP002_P1: f32 = 0.9565; // EASE [0→black, 0.9565→white]
84
22
  const STOCK_RAMPFACE_P1: f32 = 0.5435; // EASE [0→black, 0.5435→white]
85
23
  const STOCK_LW_BLEND: f32 = 0.4; // Layer Weight Blend
86
24
 
87
- // principled_sheen (gpu_shader_material_principled.glsl:8-14) — empirical NV curve
88
- fn principled_sheen(NV: f32) -> f32 {
89
- let f = 1.0 - NV;
90
- return f * f * f * 0.077 + f * 0.01 + 0.00026;
91
- }
92
-
93
25
  // Wyman & McGuire "Hashed Alpha Testing" (2017) — world-space hash with derivative-aware
94
26
  // pixel-scale selection, matches Blender EEVEE prepass_frag.glsl::hashed_alpha_threshold.
95
27
  // Key property: dither pattern is stable in object/world space (doesn't swim) and stays
@@ -111,7 +43,7 @@ fn hashed_alpha_threshold(co: vec3f) -> f32 {
111
43
  let a_hi = _hash3d_wm(floor(px_hi * co));
112
44
  let fac = fract(pix_scale_log);
113
45
  let x = mix(a_lo, a_hi, fac);
114
- // CDF remap so that discard-probability = (1 - alpha) uniformly across scale transitions
46
+ // CDF remap so discard-probability = (1 - alpha) uniformly across scale transitions
115
47
  let a = min(fac, 1.0 - fac);
116
48
  let one_a = 1.0 - a;
117
49
  let denom = 1.0 / max(2.0 * a * one_a, 1e-6);
@@ -129,39 +61,6 @@ fn ramp_ease_s(f: f32, p0: f32, p1: f32) -> f32 {
129
61
  return t * t * (3.0 - 2.0 * t);
130
62
  }
131
63
 
132
- @vertex fn vs(
133
- @location(0) position: vec3f,
134
- @location(1) normal: vec3f,
135
- @location(2) uv: vec2f,
136
- @location(3) joints0: vec4<u32>,
137
- @location(4) weights0: vec4<f32>
138
- ) -> VertexOutput {
139
- var output: VertexOutput;
140
- let pos4 = vec4f(position, 1.0);
141
- let weightSum = weights0.x + weights0.y + weights0.z + weights0.w;
142
- let invWeightSum = select(1.0, 1.0 / weightSum, weightSum > 0.0001);
143
- let nw = select(vec4f(1.0, 0.0, 0.0, 0.0), weights0 * invWeightSum, weightSum > 0.0001);
144
- var skinnedPos = vec4f(0.0);
145
- var skinnedNrm = vec3f(0.0);
146
- for (var i = 0u; i < 4u; i++) {
147
- let m = skinMats[joints0[i]];
148
- let w = nw[i];
149
- skinnedPos += (m * pos4) * w;
150
- skinnedNrm += (mat3x3f(m[0].xyz, m[1].xyz, m[2].xyz) * normal) * w;
151
- }
152
- output.position = camera.projection * camera.view * vec4f(skinnedPos.xyz, 1.0);
153
- // Skip VS normalize — interpolation denormalizes anyway, and FS always does normalize(input.normal).
154
- output.normal = skinnedNrm;
155
- output.uv = uv;
156
- output.worldPos = skinnedPos.xyz;
157
- return output;
158
- }
159
-
160
- struct FSOut {
161
- @location(0) color: vec4f,
162
- @location(1) bloom_mask: f32,
163
- };
164
-
165
64
  @fragment fn fs(input: VertexOutput) -> FSOut {
166
65
  let n = normalize(input.normal);
167
66
  let v = normalize(camera.viewPos - input.worldPos);
@@ -172,18 +71,16 @@ struct FSOut {
172
71
 
173
72
  let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
174
73
  let tex_rgb = tex_s.rgb;
175
- // Alpha HASHED (Blender EEVEE "Hashed" blend mode) per preset author's note —
176
- // self-overlap on the stockings produces sort cracks under alpha blend. Wyman-style
177
- // worldPos hash + depth-write is sort-independent. NOTE: Principled.Alpha=0.95 from
178
- // the dump is DROPPED here — it relies on TAA to smooth the resulting 5%-everywhere
179
- // dither, and without TAA it shows as a pervasive dot pattern. Hash now gates only
180
- // on texture/material alpha, so solid stockings regions stay fully opaque.
74
+ // Alpha HASHED (Blender EEVEE "Hashed" blend mode) per preset author's note — self-overlap
75
+ // on the stockings produces sort cracks under alpha blend. Wyman-style worldPos hash +
76
+ // depth-write is sort-independent. NOTE: Principled.Alpha=0.95 from the dump is DROPPED;
77
+ // it relies on TAA to smooth the 5%-everywhere dither, and without TAA it shows as a
78
+ // pervasive dot pattern. Hash now gates only on texture/material alpha.
181
79
  let combined_alpha = material.alpha * tex_s.a;
182
80
  if (combined_alpha < hashed_alpha_threshold(input.worldPos)) { discard; }
183
- let out_alpha = 1.0;
184
81
 
185
- // ═══ NPR MASK: TEX_COORD.Generated → Mapping(Rot=0,π/2,π/2, Loc=(1,1,1)) → Gradient Texture
186
- // The Blender mapping reduces to gradient.x = 1 - input.y (rot swaps axes, loc offsets by 1).
82
+ // ═══ NPR MASK ═══ TEX_COORD.Generated → Mapping(Rot=0,π/2,π/2, Loc=(1,1,1)) → Gradient.
83
+ // The Blender mapping reduces to gradient.x = 1 - input.y (rot swaps axes, loc offsets).
187
84
  // We approximate Generated with UV since Y-up PMX has no object bbox in pipeline state.
188
85
  let gen_coord = vec3f(input.uv, 0.0);
189
86
  let mapped = mapping_point(gen_coord, vec3f(1.0), vec3f(0.0, 1.5708, 1.5708), vec3f(1.0));
@@ -191,55 +88,32 @@ struct FSOut {
191
88
 
192
89
  // Ramp.001 LINEAR [0→black, 0.5→white, 1.0→black] — triangular peak at 0.5
193
90
  let ramp001 = 1.0 - abs(2.0 * gradient - 1.0);
194
- // Ramp.002 EASE [0→black, 0.9565→white]
195
91
  let ramp002 = ramp_ease_s(ramp001, 0.0, STOCK_RAMP002_P1);
196
92
 
197
- // Layer Weight.Facing (Blend=0.4) → Ramp EASE [0→black, 0.5435→white]
198
93
  let facing = layer_weight_facing(STOCK_LW_BLEND, n, v);
199
94
  let ramp_face = ramp_ease_s(facing, 0.0, STOCK_RAMPFACE_P1);
200
95
 
201
- // Mix.001: MIX blend Fac=0.5, A=white, B=ramp_face → (A,B) averaged 50/50
96
+ // Mix.001: MIX blend Fac=0.5, A=white, B=ramp_face
202
97
  let mix001 = mix(1.0, ramp_face, 0.5);
203
- // Mix: LIGHTEN blend Fac=0.5, A=mix001, B=ramp002 → A smoothly lightens toward max(A,B)
98
+ // Mix: LIGHTEN blend Fac=0.5, A=mix001, B=ramp002
204
99
  let lighten = max(mix001, ramp002);
205
100
  let mask = mix(mix001, lighten, 0.5);
206
101
 
207
- // ═══ EMISSION SHADER ═══
208
- // Hue=0.5 (identity rotation), Sat=1.0, Val=5.0 (5× brightness boost), Fac=1; Strength=1
102
+ // ═══ EMISSION SHADER ═══ Hue=0.5 (identity), Sat=1.0, Val=5.0 (5× brightness), Fac=1.
209
103
  let emission = hue_sat_id(1.0, 5.0, 1.0, tex_rgb);
210
104
 
211
- // ═══ PRINCIPLED BSDF (EEVEE port) ═══
212
- // base_color_tint, metallic f0, sheen coarse approx (scales diffuse radiance).
213
- let NL = max(dot(n, l), 0.0);
214
- let NV = max(dot(n, v), 1e-4);
215
-
216
- // f0 = mix((0.08*spec)*dielectric_tint, base, metallic); dielectric_tint=1 since specular_tint=0.
217
- let dielectric_f0 = vec3f(0.08 * STOCK_SPECULAR);
218
- let f0 = mix(dielectric_f0, tex_rgb, STOCK_METALLIC);
219
- let f90 = mix(f0, vec3f(1.0), sqrt(STOCK_SPECULAR));
220
- let brdf_lut = brdf_lut_sample(NV, STOCK_ROUGHNESS);
221
- let reflection_color = F_brdf_multi_scatter(f0, f90, brdf_lut.xy);
222
-
223
- let spec_direct = bsdf_ggx(n, l, v, NL, NV, STOCK_ROUGHNESS) * sun * shadow * ltc_brdf_scale_from_lut(brdf_lut);
224
- let spec_indirect = amb;
225
- let spec_radiance = (spec_direct + spec_indirect) * reflection_color;
226
-
227
- // Sheen coarse: diffuse_color += sheen * sheen_color * principled_sheen(NV).
228
- let base_tint = tint_from_color(tex_rgb);
229
- let sheen_color = mix(vec3f(1.0), base_tint, STOCK_SHEEN_TINT);
230
- let diffuse_color = tex_rgb + STOCK_SHEEN * sheen_color * principled_sheen(NV);
231
-
232
- // diffuse_weight = (1 - metallic). Indirect diffuse uses L_w (no π; see closure_eval_surface_lib:302).
233
- let diffuse_weight = 1.0 - STOCK_METALLIC;
234
- let diffuse_radiance = diffuse_color * (sun * NL * shadow / PI_S + amb) * diffuse_weight;
235
- let principled = diffuse_radiance + spec_radiance;
236
-
237
- // ═══ MIX SHADER: Shader=Emission, Shader_001=Principled, Fac=mask ═══
105
+ // ═══ PRINCIPLED BSDF with sheen ═══ metallic=0.1, sheen=0.7, sheen_tint=0.5.
106
+ let principled = eval_principled(
107
+ PrincipledIn(tex_rgb, STOCK_METALLIC, STOCK_SPECULAR, STOCK_ROUGHNESS, 1e30, STOCK_SHEEN, STOCK_SHEEN_TINT),
108
+ n, l, v, sun, amb, shadow
109
+ );
110
+
111
+ // MIX SHADER: Shader=Emission, Shader_001=Principled, Fac=mask
238
112
  let final_color = mix(emission, principled, mask);
239
113
 
240
114
  var out: FSOut;
241
- out.color = vec4f(final_color, out_alpha);
242
- out.bloom_mask = 1.0;
115
+ out.color = vec4f(final_color, 1.0);
116
+ out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
243
117
  return out;
244
118
  }
245
119
 
@@ -24,10 +24,13 @@ fn fetch(c: vec2<i32>, clampV: f32) -> vec3f {
24
24
  let d = vec2<i32>(textureDimensions(hdrTex));
25
25
  let cc = clamp(c, vec2<i32>(0), d - vec2<i32>(1));
26
26
  let s = textureLoad(hdrTex, cc, 0);
27
- // Scene pass uses src-alpha blend with clear alpha 0 → premultiplied. Unpremultiply.
28
- let rgb = max(s.rgb / max(s.a, 1e-6), vec3f(0.0));
29
- // Bloom mask: MRT r8unorm written by material shaders (1.0 = bloom, 0.0 = skip).
30
- let mask = textureLoad(maskTex, cc, 0).r;
27
+ // hdrTex is rg11b10ufloat (no alpha channel). Alpha lives in maskTex.g, written
28
+ // alongside the bloom mask in .r by the scene pass. Scene uses src-alpha blend
29
+ // with clear alpha 0 hdr rgb is premultiplied; divide by the aux alpha to
30
+ // recover straight color before the Karis luminance weighting.
31
+ let aux = textureLoad(maskTex, cc, 0);
32
+ let mask = aux.r;
33
+ let rgb = max(s.rgb / max(aux.g, 1e-6), vec3f(0.0));
31
34
  let masked = rgb * mask;
32
35
  // Blender clamps each tap BEFORE Karis average (eevee_bloom: color = min(clampIntensity, color)).
33
36
  return select(masked, min(masked, vec3f(clampV)), clampV > 0.0);
@@ -13,6 +13,12 @@ override APPLY_GAMMA: bool = true;
13
13
  @group(0) @binding(1) var bloomTex: texture_2d<f32>; // bloomUpTexture mip 0 (full pyramid top)
14
14
  @group(0) @binding(2) var bloomSamp: sampler;
15
15
  @group(0) @binding(3) var<uniform> viewU: array<vec4<f32>, 2>;
16
+ // Aux mask/alpha texture. .r = bloom mask (unused here; bloom blit uses it).
17
+ // .g = accumulated canvas alpha (what hdr.a carried before the HDR format
18
+ // became rg11b10ufloat). We unpremultiply HDR by this alpha for tonemap, then
19
+ // re-premultiply the tonemapped color for output so the premultiplied canvas
20
+ // alphaMode composites the WebGPU surface over the page background correctly.
21
+ @group(0) @binding(4) var maskTex: texture_2d<f32>;
16
22
  // viewU[0] = (exposure, invGamma, _, _); viewU[1] = (tint.rgb, intensity)
17
23
  // invGamma = 1/gamma precomputed on CPU — avoids a per-pixel divide.
18
24
 
@@ -39,11 +45,12 @@ fn filmic(x: f32) -> f32 {
39
45
  }
40
46
 
41
47
  @fragment fn fs(@builtin(position) fragCoord: vec4f) -> @location(0) vec4f {
42
- let hdr = textureLoad(hdrTex, vec2<i32>(fragCoord.xy), 0);
43
- let a = max(hdr.a, 1e-6);
48
+ let coord = vec2<i32>(fragCoord.xy);
49
+ let hdr = textureLoad(hdrTex, coord, 0);
50
+ let alpha = textureLoad(maskTex, coord, 0).g;
51
+ let a = max(alpha, 1e-6);
44
52
  let straight = hdr.rgb / a;
45
53
  let fullSz = vec2f(textureDimensions(hdrTex));
46
- let bloomSz = vec2f(textureDimensions(bloomTex));
47
54
  // Bloom is at half-res (pyramid mip 0). Sampler interpolates back to full-res UVs.
48
55
  // fragCoord.xy is already at pixel center (e.g. 0.5, 0.5 for first pixel).
49
56
  let bloomUv = fragCoord.xy / max(fullSz, vec2f(1.0));
@@ -57,6 +64,6 @@ fn filmic(x: f32) -> f32 {
57
64
  if (APPLY_GAMMA) {
58
65
  disp = pow(disp, vec3f(viewU[0].y));
59
66
  }
60
- return vec4f(disp * hdr.a, hdr.a);
67
+ return vec4f(disp * alpha, alpha);
61
68
  }
62
69
  `
@@ -48,7 +48,7 @@ struct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @l
48
48
  var o: VO; o.worldPos = position; o.normal = normal;
49
49
  o.position = camera.projection * camera.view * vec4f(position, 1.0); return o;
50
50
  }
51
- struct FSOut { @location(0) color: vec4f, @location(1) mask: f32 };
51
+ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
52
52
  @fragment fn fs(i: VO) -> FSOut {
53
53
  let n = normalize(i.normal);
54
54
  let centerDist = length(i.worldPos.xz);
@@ -88,7 +88,11 @@ struct FSOut { @location(0) color: vec4f, @location(1) mask: f32 };
88
88
  let finalColor = mix(baseColor, material.gridLineColor, gridLine * material.gridLineOpacity * edgeFade);
89
89
  var out: FSOut;
90
90
  out.color = vec4f(finalColor * edgeFade, edgeFade);
91
- out.mask = 0.0;
91
+ // mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =
92
+ // edgeFade turns the aux blend into alpha-over, so the drawable alpha fades
93
+ // from edgeFade at the center to 0 at the radial edge — letting the page
94
+ // background show through under the premultiplied canvas alphaMode.
95
+ out.mask = vec4f(0.0, 1.0, 0.0, edgeFade);
92
96
  return out;
93
97
  }
94
98
  `
@@ -74,11 +74,11 @@ struct VertexOutput {
74
74
  return output;
75
75
  }
76
76
 
77
- struct FSOut { @location(0) color: vec4f, @location(1) mask: f32 };
77
+ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
78
78
  @fragment fn fs() -> FSOut {
79
79
  var out: FSOut;
80
80
  out.color = material.edgeColor;
81
- out.mask = 1.0;
81
+ out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
82
82
  return out;
83
83
  }
84
84
  `
@@ -1,15 +0,0 @@
1
- /**
2
- * Bezier interpolation for VMD animations
3
- * Based on the reference implementation from babylon-mmd
4
- */
5
- /**
6
- * Bezier interpolation function
7
- * @param x1 First control point X (0-127, normalized to 0-1)
8
- * @param x2 Second control point X (0-127, normalized to 0-1)
9
- * @param y1 First control point Y (0-127, normalized to 0-1)
10
- * @param y2 Second control point Y (0-127, normalized to 0-1)
11
- * @param t Interpolation parameter (0-1)
12
- * @returns Interpolated value (0-1)
13
- */
14
- export declare function bezierInterpolate(x1: number, x2: number, y1: number, y2: number, t: number): number;
15
- //# sourceMappingURL=bezier-interpolate.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bezier-interpolate.d.ts","sourceRoot":"","sources":["../src/bezier-interpolate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAgCnG"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Bezier interpolation for VMD animations
3
- * Based on the reference implementation from babylon-mmd
4
- */
5
- /**
6
- * Bezier interpolation function
7
- * @param x1 First control point X (0-127, normalized to 0-1)
8
- * @param x2 Second control point X (0-127, normalized to 0-1)
9
- * @param y1 First control point Y (0-127, normalized to 0-1)
10
- * @param y2 Second control point Y (0-127, normalized to 0-1)
11
- * @param t Interpolation parameter (0-1)
12
- * @returns Interpolated value (0-1)
13
- */
14
- export function bezierInterpolate(x1, x2, y1, y2, t) {
15
- // Clamp t to [0, 1]
16
- t = Math.max(0, Math.min(1, t));
17
- // Binary search for the t value that gives us the desired x
18
- // We're solving for t in the Bezier curve: x(t) = 3*(1-t)^2*t*x1 + 3*(1-t)*t^2*x2 + t^3
19
- let start = 0;
20
- let end = 1;
21
- let mid = 0.5;
22
- // Iterate until we find the t value that gives us the desired x
23
- for (let i = 0; i < 15; i++) {
24
- // Evaluate Bezier curve at mid point
25
- const x = 3 * (1 - mid) * (1 - mid) * mid * x1 + 3 * (1 - mid) * mid * mid * x2 + mid * mid * mid;
26
- if (Math.abs(x - t) < 0.0001) {
27
- break;
28
- }
29
- if (x < t) {
30
- start = mid;
31
- }
32
- else {
33
- end = mid;
34
- }
35
- mid = (start + end) / 2;
36
- }
37
- // Now evaluate the y value at this t
38
- const y = 3 * (1 - mid) * (1 - mid) * mid * y1 + 3 * (1 - mid) * mid * mid * y2 + mid * mid * mid;
39
- return y;
40
- }
@@ -1,143 +0,0 @@
1
- import { Quat, Vec3 } from "reze-mmd";
2
- export type EngineOptions = {
3
- ambientColor?: Vec3;
4
- bloomIntensity?: number;
5
- rimLightIntensity?: number;
6
- cameraDistance?: number;
7
- cameraTarget?: Vec3;
8
- };
9
- export interface EngineStats {
10
- fps: number;
11
- frameTime: number;
12
- }
13
- export declare class Engine {
14
- private canvas;
15
- private device;
16
- private context;
17
- private presentationFormat;
18
- private camera;
19
- private cameraUniformBuffer;
20
- private cameraMatrixData;
21
- private cameraDistance;
22
- private cameraTarget;
23
- private lightUniformBuffer;
24
- private lightData;
25
- private vertexBuffer;
26
- private indexBuffer?;
27
- private resizeObserver;
28
- private depthTexture;
29
- private modelPipeline;
30
- private eyePipeline;
31
- private hairPipelineOverEyes;
32
- private hairPipelineOverNonEyes;
33
- private hairDepthPipeline;
34
- private outlinePipeline;
35
- private hairOutlinePipeline;
36
- private mainBindGroupLayout;
37
- private outlineBindGroupLayout;
38
- private jointsBuffer;
39
- private weightsBuffer;
40
- private skinMatrixBuffer?;
41
- private multisampleTexture;
42
- private readonly sampleCount;
43
- private renderPassDescriptor;
44
- private readonly STENCIL_EYE_VALUE;
45
- private readonly BLOOM_DOWNSCALE_FACTOR;
46
- private static readonly DEFAULT_BLOOM_THRESHOLD;
47
- private static readonly DEFAULT_BLOOM_INTENSITY;
48
- private static readonly DEFAULT_RIM_LIGHT_INTENSITY;
49
- private static readonly DEFAULT_CAMERA_DISTANCE;
50
- private static readonly DEFAULT_CAMERA_TARGET;
51
- private static readonly TRANSPARENCY_EPSILON;
52
- private static readonly STATS_FPS_UPDATE_INTERVAL_MS;
53
- private static readonly STATS_FRAME_TIME_ROUNDING;
54
- private ambientColor;
55
- private sceneRenderTexture;
56
- private sceneRenderTextureView;
57
- private bloomExtractTexture;
58
- private bloomBlurTexture1;
59
- private bloomBlurTexture2;
60
- private bloomExtractPipeline;
61
- private bloomBlurPipeline;
62
- private bloomComposePipeline;
63
- private blurDirectionBuffer;
64
- private bloomIntensityBuffer;
65
- private bloomThresholdBuffer;
66
- private linearSampler;
67
- private bloomExtractBindGroup?;
68
- private bloomBlurHBindGroup?;
69
- private bloomBlurVBindGroup?;
70
- private bloomComposeBindGroup?;
71
- private bloomThreshold;
72
- private bloomIntensity;
73
- private rimLightIntensity;
74
- private currentModel;
75
- private modelDir;
76
- private physics;
77
- private materialSampler;
78
- private textureCache;
79
- private vertexBufferNeedsUpdate;
80
- private drawCalls;
81
- private lastFpsUpdate;
82
- private framesSinceLastUpdate;
83
- private lastFrameTime;
84
- private frameTimeSum;
85
- private frameTimeCount;
86
- private stats;
87
- private animationFrameId;
88
- private renderLoopCallback;
89
- private player;
90
- private hasAnimation;
91
- constructor(canvas: HTMLCanvasElement, options?: EngineOptions);
92
- init(): Promise<void>;
93
- private createRenderPipeline;
94
- private createPipelines;
95
- private createBloomPipelines;
96
- private setupBloom;
97
- private setupResize;
98
- private handleResize;
99
- private setupCamera;
100
- private setupLighting;
101
- private setAmbientColor;
102
- loadAnimation(url: string): Promise<void>;
103
- playAnimation(): void;
104
- stopAnimation(): void;
105
- pauseAnimation(): void;
106
- seekAnimation(time: number): void;
107
- getAnimationProgress(): import("./player").AnimationProgress;
108
- /**
109
- * Apply animation pose to model
110
- */
111
- private applyPose;
112
- /**
113
- * Reset bones and physics to match a given pose
114
- * @param pose The pose to apply
115
- * @param resetBonesWithoutKeyframes If true, reset bones that don't have keyframes in the pose to identity
116
- */
117
- private resetBonesAndPhysics;
118
- getStats(): EngineStats;
119
- runRenderLoop(callback?: () => void): void;
120
- stopRenderLoop(): void;
121
- dispose(): void;
122
- loadModel(path: string): Promise<void>;
123
- rotateBones(bones: string[], rotations: Quat[], durationMs?: number): void;
124
- moveBones(bones: string[], relativeTranslations: Vec3[], durationMs?: number): void;
125
- setMorphWeight(name: string, weight: number, durationMs?: number): void;
126
- private updateVertexBuffer;
127
- private setupModelBuffers;
128
- private setupMaterials;
129
- private createMaterialUniformBuffer;
130
- private createUniformBuffer;
131
- private createTextureFromPath;
132
- private renderEyes;
133
- private renderHair;
134
- render(): void;
135
- private applyBloom;
136
- private updateCameraUniforms;
137
- private updateRenderTarget;
138
- private updateModelPose;
139
- private computeSkinMatrices;
140
- private drawOutlines;
141
- private updateStats;
142
- }
143
- //# sourceMappingURL=engine_ts.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine_ts.d.ts","sourceRoot":"","sources":["../src/engine_ts.ts"],"names":[],"mappings":"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"}