ugly-game 0.5.16 → 0.5.18

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.
@@ -21,10 +21,12 @@ fn rot(m: mat4x4f, v: vec3f) -> vec3f { return mat3x3f(m[0].xyz, m[1].xyz, m[2].
21
21
  deformed[i]=vec4f(a.xyz,1.0); defN[i]=vec4f(normalize(b),0.0);
22
22
  }`;
23
23
  const DRAW = /* wgsl */ `
24
- struct U { mvp: mat4x4<f32>, sun: vec4<f32>, sunCol: vec4<f32>, amb: vec4<f32>, cam: vec4<f32>, fog: vec4<f32> };
24
+ struct U { mvp: mat4x4<f32>, sun: vec4<f32>, sunCol: vec4<f32>, amb: vec4<f32>, cam: vec4<f32>, fog: vec4<f32>, model: mat4x4<f32> };
25
25
  @group(0) @binding(0) var<uniform> u: U;
26
26
  struct VOut { @builtin(position) pos: vec4<f32>, @location(0) world: vec3<f32>, @location(1) col: vec3<f32>, @location(2) n: vec3<f32> };
27
- @vertex fn vs(@location(0) p: vec3<f32>, @location(1) c: vec3<f32>, @location(2) nrm: vec3<f32>) -> VOut { var o: VOut; o.pos=u.mvp*vec4(p,1.0); o.world=p; o.col=c; o.n=nrm; return o; }
27
+ // o.world must be the WORLD position (model·p), not the local deformed p else the fog distance is computed
28
+ // against the world-space camera and blows up on a planet surface (huge coords), washing creatures into the fog.
29
+ @vertex fn vs(@location(0) p: vec3<f32>, @location(1) c: vec3<f32>, @location(2) nrm: vec3<f32>) -> VOut { var o: VOut; o.pos=u.mvp*vec4(p,1.0); o.world=(u.model*vec4(p,1.0)).xyz; o.col=c; o.n=nrm; return o; }
28
30
  @fragment fn fs(i: VOut) -> @location(0) vec4<f32> {
29
31
  let d = clamp(dot(normalize(i.n), -normalize(u.sun.xyz)), 0.0, 1.0);
30
32
  let lit = i.col * (u.amb.xyz + d * u.sunCol.xyz);
@@ -93,7 +95,7 @@ export class GpuSkinRenderer {
93
95
  { binding: 3, resource: { buffer: palB } }, { binding: 4, resource: { buffer: defB } }, { binding: 5, resource: { buffer: pB } },
94
96
  { binding: 6, resource: { buffer: restNB } }, { binding: 7, resource: { buffer: defNB } }
95
97
  ] });
96
- const uBuf = dev.createBuffer({ size: 96 + 16 * 5, usage: U.UNIFORM | U.COPY_DST });
98
+ const uBuf = dev.createBuffer({ size: 96 + 16 * 7, usage: U.UNIFORM | U.COPY_DST });
97
99
  const uBG = dev.createBindGroup({ layout: this.drawPipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: { buffer: uBuf } }] });
98
100
  return { defB, defNB, colB, idxB, idxCount: c.indices.length, skinBG, uBuf, uBG, palB, n, model: c.model };
99
101
  });
@@ -109,13 +111,14 @@ export class GpuSkinRenderer {
109
111
  }
110
112
  cp.end();
111
113
  for (const p of this.packed) {
112
- const u = new Float32Array(24 + 20);
114
+ const u = new Float32Array(24 + 28);
113
115
  u.set(mul16(camVP, p.model), 0);
114
116
  u.set([sunDir[0], sunDir[1], sunDir[2], 0], 16);
115
117
  u.set([sunCol[0], sunCol[1], sunCol[2], 0], 20);
116
118
  u.set([amb[0], amb[1], amb[2], 0], 24);
117
119
  u.set([camPos[0], camPos[1], camPos[2], 0], 28);
118
120
  u.set([fog[0], fog[1], fog[2], fogDensity], 32);
121
+ u.set(p.model, 36); // world model matrix (for correct fog distance in the vs)
119
122
  this.device.queue.writeBuffer(p.uBuf, 0, u);
120
123
  }
121
124
  const rp = enc.beginRenderPass({
@@ -107,7 +107,7 @@ export declare class GpuShadowRenderer {
107
107
  depth: GPUTextureView;
108
108
  w: number;
109
109
  h: number;
110
- }, tint?: [number, number, number, number], extraShadow?: (sp: GPURenderPassEncoder, lightVP: Float32Array) => void, up?: [number, number, number]): void;
110
+ }, tint?: [number, number, number, number], extraShadow?: (sp: GPURenderPassEncoder, lightVP: Float32Array) => void, up?: [number, number, number], linearOut?: boolean): void;
111
111
  /** Read back the last frame's GPU cull result (camera-visible, light-visible). Does its OWN copy+submit so it's
112
112
  * safe to call from a live render loop (no per-frame readback cost, no race with the ongoing frames). IR/tests. */
113
113
  readCullStats(): Promise<{
package/dist/gpuShadow.js CHANGED
@@ -254,6 +254,7 @@ fn fixedFill(N: vec3<f32>, up: vec3<f32>) -> f32 {
254
254
  @fragment fn fs(i: VOut) -> @location(0) vec4<f32> {
255
255
  if (i.emis > 0.5) { // self-glowing effect cube: full-bright, unlit
256
256
  let g = mix(hsv(i.hue), vec3(1.0), 0.4);
257
+ if (cam.up.w > 0.5) { return vec4(g * 2.6, 1.0); } // linear-HDR path: push emissive >1 so it blooms
257
258
  return vec4(pow(clamp(g, vec3(0.0), vec3(1.0)), vec3(0.4545)), 1.0);
258
259
  }
259
260
  let N = normalize(i.nrm);
@@ -287,6 +288,9 @@ fn fixedFill(N: vec3<f32>, up: vec3<f32>) -> f32 {
287
288
  let fill = cam.sun.w * (0.5 + 0.85 * fixedFill(N, cam.up.xyz));
288
289
  let key = cam.sunCol.xyz * ndl * sh; // direct sun (shadowed) — primary light
289
290
  let lit = base * (fill + key) * ao;
291
+ // cam.up.w > 0.5 selects LINEAR-HDR output (unclamped, no gamma) for an HDR pipeline that tonemaps downstream;
292
+ // otherwise the classic gamma-encoded LDR path (all existing consumers). Keeps both looks from one shader.
293
+ if (cam.up.w > 0.5) { return vec4(max(lit, vec3(0.0)), 1.0); }
290
294
  return vec4(pow(clamp(lit, vec3(0.0), vec3(1.0)), vec3(0.4545)), 1.0); // gamma
291
295
  }
292
296
  `;
@@ -602,7 +606,7 @@ export class GpuShadowRenderer {
602
606
  /** camVP/lightVP: column-major Float32Array(16). sunDir: travel direction. Pass `occlusion` (the depth target +
603
607
  * its size) to enable Hi-Z occlusion culling on the camera pass — the renderer rebuilds a coarse Hi-Z from that
604
608
  * depth each frame and the NEXT frame's cull uses it (hole-free: the first frame + any resize skip occlusion). */
605
- frame(enc, colorView, sceneDepth, camVP, lightVP, sunDir, sunCol, ambient, load = false, occlusion, tint = [1, 1, 1, 0], extraShadow, up = [0, 1, 0]) {
609
+ frame(enc, colorView, sceneDepth, camVP, lightVP, sunDir, sunCol, ambient, load = false, occlusion, tint = [1, 1, 1, 0], extraShadow, up = [0, 1, 0], linearOut = false) {
606
610
  this.cam.set(camVP, 0);
607
611
  this.cam.set(lightVP, 16);
608
612
  this.cam[32] = sunDir[0];
@@ -621,6 +625,7 @@ export class GpuShadowRenderer {
621
625
  this.cam[48] = up[0];
622
626
  this.cam[49] = up[1];
623
627
  this.cam[50] = up[2];
628
+ this.cam[51] = linearOut ? 1 : 0; // up.w = linear-HDR output flag
624
629
  this.device.queue.writeBuffer(this.camBuf, 0, this.cam);
625
630
  if (occlusion)
626
631
  this.ensureHiZ(occlusion.w, occlusion.h);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-game",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {