reze-engine 0.56.11 → 0.56.13

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.
@@ -290,6 +290,47 @@ fn point_world_to_camera(p: vec3f) -> vec3f { return (camera.view * vec4f(p, 1.0
290
290
  // One function per slot because WGSL has no texture arrays-of-bindings here; the
291
291
  // slot is topology, exactly like a Math node's operation.
292
292
 
293
+ /**
294
+ * The world's radiance arriving from a direction — what a reflection sees.
295
+ *
296
+ * The engine's ambient is irradiance: the SH fit of the sky integrated over a
297
+ * hemisphere, evaluated along the NORMAL. That is the right answer for diffuse
298
+ * light and the wrong one for a mirror, which needs radiance along the
299
+ * REFLECTION vector and needs it sharp. A stage ripped from a game asks for
300
+ * this on nearly every surface — it is what a Unity material's DEFAULT_REFLECTION
301
+ * keyword means —
302
+ * and so does every metal the app has ever drawn.
303
+ *
304
+ * ROUGHNESS PICKS A MIP, which is the cheap prefilter: the chain is built by
305
+ * successive halving at upload, so a level is a box average of the sky over a
306
+ * widening solid angle. A cosine-lobe convolution would be more correct; the
307
+ * visible difference is confined to the middle of the roughness range, and the
308
+ * chain costs one downsample per level instead of a render pass per level.
309
+ *
310
+ * Without an HDRI there is nothing to reflect but the flat world colour, which
311
+ * is what the ambient already is — so the two agree and a scene without a sky
312
+ * texture sees no change at all.
313
+ */
314
+ fn rzWorldSpecular(dir: vec3f, roughness: f32) -> vec3f {
315
+ // A SKY TEXTURE, or the best the scene has. The flag is 2 when an HDRI is
316
+ // installed, 1 when the world is a gradient fitted to the same harmonics,
317
+ // and 0 when it is one flat colour — and in the last two cases the ambient
318
+ // already answers by direction, which is a blurred sky and exactly what a
319
+ // world without a picture can honestly reflect.
320
+ if (light.sh[0].w < 1.5) { return rzWorldAmbient(normalize(dir)); }
321
+ let d = normalize(dir);
322
+ // The composite's own convention, restated: LH world with +Z forward, which
323
+ // is what makes a reflection line up with the dome the viewer can see.
324
+ let u = 0.5 + atan2(d.x, d.z) * 0.15915494309;
325
+ let v = 0.5 - asin(clamp(d.y, -1.0, 1.0)) * 0.31830988618;
326
+ let levels = f32(textureNumLevels(worldEnvTexture) - 1u);
327
+ // sqrt, not linear: mip n covers roughly twice the angle of n-1, so a linear
328
+ // ramp spends most of its travel in the blurry end and a mirror-to-satin
329
+ // sweep happens entirely in the first tenth of the dial.
330
+ let lod = clamp(sqrt(clamp(roughness, 0.0, 1.0)) * levels, 0.0, levels);
331
+ return textureSampleLevel(worldEnvTexture, diffuseSampler, vec2f(u, v), lod).rgb * light.ambientColor.w;
332
+ }
333
+
293
334
  fn group_tex0(uv: vec2f) -> vec4f { return textureSample(groupTexture0, diffuseSampler, uv); }
294
335
  fn group_tex1(uv: vec2f) -> vec4f { return textureSample(groupTexture1, diffuseSampler, uv); }
295
336
  fn group_tex2(uv: vec2f) -> vec4f { return textureSample(groupTexture2, diffuseSampler, uv); }