ugly-game 0.5.13 → 0.5.15
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.
- package/dist/assets/gpuProps.d.ts +1 -1
- package/dist/assets/gpuProps.js +19 -6
- package/dist/gpuShadow.js +17 -6
- package/package.json +1 -1
|
@@ -25,5 +25,5 @@ export declare class GpuPropsRenderer {
|
|
|
25
25
|
setInstances(instances: PropInstance[]): void;
|
|
26
26
|
/** Occluder pass: draw all instanced props' depth into the shared shadow map from the sun's ortho view. */
|
|
27
27
|
shadowPass(pass: GPURenderPassEncoder, lightVP: Float32Array): void;
|
|
28
|
-
frame(enc: GPUCommandEncoder, colorView: GPUTextureView, depthView: GPUTextureView, camVP: Float32Array, sunDir: [number, number, number], sunCol: [number, number, number], amb: [number, number, number], camPos: [number, number, number], fog: [number, number, number], fogDensity: number): void;
|
|
28
|
+
frame(enc: GPUCommandEncoder, colorView: GPUTextureView, depthView: GPUTextureView, camVP: Float32Array, sunDir: [number, number, number], sunCol: [number, number, number], amb: [number, number, number], camPos: [number, number, number], fog: [number, number, number], fogDensity: number, up?: [number, number, number]): void;
|
|
29
29
|
}
|
package/dist/assets/gpuProps.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// terrain. Runs in a load pass after the terrain so props depth-test against the surface.
|
|
5
5
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
6
|
const SHADER = /* wgsl */ `
|
|
7
|
-
struct U { mvp: mat4x4<f32>, sun: vec4<f32>, sunCol: vec4<f32>, amb: vec4<f32>, cam: vec4<f32>, fog: vec4<f32> };
|
|
7
|
+
struct U { mvp: mat4x4<f32>, sun: vec4<f32>, sunCol: vec4<f32>, amb: vec4<f32>, cam: vec4<f32>, fog: vec4<f32>, up: vec4<f32> };
|
|
8
8
|
@group(0) @binding(0) var<uniform> u: U;
|
|
9
9
|
@group(0) @binding(1) var<storage,read> models: array<mat4x4<f32>>;
|
|
10
10
|
struct VO { @builtin(position) pos: vec4<f32>, @location(0) world: vec3<f32>, @location(1) n: vec3<f32>, @location(2) c: vec3<f32> };
|
|
@@ -13,9 +13,20 @@ struct VO { @builtin(position) pos: vec4<f32>, @location(0) world: vec3<f32>, @l
|
|
|
13
13
|
let world = (m * vec4(p, 1.0)).xyz;
|
|
14
14
|
var o: VO; o.pos = u.mvp * vec4(world, 1.0); o.world = world; o.n = (m * vec4(nrm, 0.0)).xyz; o.c = col; return o;
|
|
15
15
|
}
|
|
16
|
+
// same fixed directional FILL as the terrain cubes (gpuShadow.fixedFill) so plants/rocks read the same 3D shape,
|
|
17
|
+
// day or night, under one shared light. up.w > 0.5 signals a valid local-up was supplied (else fall back to flat).
|
|
18
|
+
fn fixedFill(N: vec3<f32>, up: vec3<f32>) -> f32 {
|
|
19
|
+
var t = cross(up, vec3(0.0, 0.0, 1.0));
|
|
20
|
+
if (dot(t, t) < 0.01) { t = cross(up, vec3(1.0, 0.0, 0.0)); }
|
|
21
|
+
t = normalize(t);
|
|
22
|
+
let L = normalize(up * 0.82 + t * 0.57);
|
|
23
|
+
return max(dot(N, L), 0.0);
|
|
24
|
+
}
|
|
16
25
|
@fragment fn fs(i: VO) -> @location(0) vec4<f32> {
|
|
17
|
-
let
|
|
18
|
-
let
|
|
26
|
+
let N = normalize(i.n);
|
|
27
|
+
let ff = select(1.0, 0.5 + 0.85 * fixedFill(N, u.up.xyz), u.up.w > 0.5); // fixed fill (fall back to flat amb if no up)
|
|
28
|
+
let d = clamp(dot(N, -normalize(u.sun.xyz)), 0.0, 1.0);
|
|
29
|
+
let lit = i.c * (u.amb.xyz * ff + d * u.sunCol.xyz);
|
|
19
30
|
let dist = length(i.world - u.cam.xyz);
|
|
20
31
|
let f = clamp(1.0 - exp(-dist * u.fog.w), 0.0, 1.0);
|
|
21
32
|
return vec4(mix(lit, u.fog.xyz, f), 1.0);
|
|
@@ -59,7 +70,7 @@ export class GpuPropsRenderer {
|
|
|
59
70
|
primitive: { topology: 'triangle-list', cullMode: 'none' },
|
|
60
71
|
depthStencil: { format: 'depth32float', depthWriteEnabled: true, depthCompare: 'less' },
|
|
61
72
|
});
|
|
62
|
-
this.uBuf = device.createBuffer({ size: 96 + 16 *
|
|
73
|
+
this.uBuf = device.createBuffer({ size: 96 + 16 * 6, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
63
74
|
this.lightBuf = device.createBuffer({ size: 64, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
64
75
|
}
|
|
65
76
|
setModels(meshes) {
|
|
@@ -120,14 +131,16 @@ export class GpuPropsRenderer {
|
|
|
120
131
|
pass.drawIndexed(mdl.idxCount, this.counts[m]);
|
|
121
132
|
}
|
|
122
133
|
}
|
|
123
|
-
frame(enc, colorView, depthView, camVP, sunDir, sunCol, amb, camPos, fog, fogDensity) {
|
|
124
|
-
const u = new Float32Array(24 +
|
|
134
|
+
frame(enc, colorView, depthView, camVP, sunDir, sunCol, amb, camPos, fog, fogDensity, up) {
|
|
135
|
+
const u = new Float32Array(24 + 24);
|
|
125
136
|
u.set(camVP, 0);
|
|
126
137
|
u.set([sunDir[0], sunDir[1], sunDir[2], 0], 16);
|
|
127
138
|
u.set([sunCol[0], sunCol[1], sunCol[2], 0], 20);
|
|
128
139
|
u.set([amb[0], amb[1], amb[2], 0], 24);
|
|
129
140
|
u.set([camPos[0], camPos[1], camPos[2], 0], 28);
|
|
130
141
|
u.set([fog[0], fog[1], fog[2], fogDensity], 32);
|
|
142
|
+
if (up)
|
|
143
|
+
u.set([up[0], up[1], up[2], 1], 36); // up.w=1 → enable the fixed directional fill (matches the terrain)
|
|
131
144
|
this.device.queue.writeBuffer(this.uBuf, 0, u);
|
|
132
145
|
const rp = enc.beginRenderPass({ colorAttachments: [{ view: colorView, loadOp: 'load', storeOp: 'store' }], depthStencilAttachment: { view: depthView, depthLoadOp: 'load', depthStoreOp: 'store' } });
|
|
133
146
|
rp.setPipeline(this.pipe);
|
package/dist/gpuShadow.js
CHANGED
|
@@ -240,6 +240,17 @@ fn blockShade(fx: f32, fz: f32) -> f32 {
|
|
|
240
240
|
let t = clamp(edge / 0.17, 0.0, 1.0);
|
|
241
241
|
return 0.6 + 0.4 * (t * t * (3.0 - 2.0 * t));
|
|
242
242
|
}
|
|
243
|
+
// ONE fixed, subtle directional FILL light in the local gravity frame — always on, independent of the sun, so
|
|
244
|
+
// terrain + props keep their 3D shape even in darkness (the sun stays the primary, shadow-casting key light). The
|
|
245
|
+
// fill comes from up + a fixed horizontal tangent (~35 deg off vertical), so a cube's three visible faces all get
|
|
246
|
+
// distinct brightness and corners/terrace risers read at a glance. Cubes and props (gpuProps) share this formula.
|
|
247
|
+
fn fixedFill(N: vec3<f32>, up: vec3<f32>) -> f32 {
|
|
248
|
+
var t = cross(up, vec3(0.0, 0.0, 1.0));
|
|
249
|
+
if (dot(t, t) < 0.01) { t = cross(up, vec3(1.0, 0.0, 0.0)); }
|
|
250
|
+
t = normalize(t);
|
|
251
|
+
let L = normalize(up * 0.82 + t * 0.57); // fixed key-fill direction
|
|
252
|
+
return max(dot(N, L), 0.0); // 0 (facing away) .. 1 (facing the fill)
|
|
253
|
+
}
|
|
243
254
|
@fragment fn fs(i: VOut) -> @location(0) vec4<f32> {
|
|
244
255
|
if (i.emis > 0.5) { // self-glowing effect cube: full-bright, unlit
|
|
245
256
|
let g = mix(hsv(i.hue), vec3(1.0), 0.4);
|
|
@@ -270,12 +281,12 @@ fn blockShade(fx: f32, fz: f32) -> f32 {
|
|
|
270
281
|
// per-block edge AO makes each voxel visible on FLAT-hue cubes, but reads as a hard GRID over textures — so the
|
|
271
282
|
// atlas path drops it entirely (the texture already supplies surface detail).
|
|
272
283
|
let ao = select(blockShade(fx, fz), 1.0, cam.atlas.x > 0.5 && i.tile >= 0.0);
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
let
|
|
277
|
-
let
|
|
278
|
-
let lit = base * (
|
|
284
|
+
// LIGHTING = fixed directional FILL (always on, reads 3D shape in the dark) + the sun KEY (primary, shadowed).
|
|
285
|
+
// cam.sun.w is the fill/ambient brightness knob; the fill's directional term (0.5..1.35) keeps every face's
|
|
286
|
+
// orientation legible day or night, while the sun adds bright, shadow-casting key light on top during the day.
|
|
287
|
+
let fill = cam.sun.w * (0.5 + 0.85 * fixedFill(N, cam.up.xyz));
|
|
288
|
+
let key = cam.sunCol.xyz * ndl * sh; // direct sun (shadowed) — primary light
|
|
289
|
+
let lit = base * (fill + key) * ao;
|
|
279
290
|
return vec4(pow(clamp(lit, vec3(0.0), vec3(1.0)), vec3(0.4545)), 1.0); // gamma
|
|
280
291
|
}
|
|
281
292
|
`;
|