Lighting on the GPU in the WebGPU path (t88 phase 2b)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,10 @@ function gpuWorldTextures() {
|
||||
GPU.lut = gpuBuffer(tables);
|
||||
GPU.landData = new Float32Array((W + H) * 4);
|
||||
GPU.land = gpuBuffer(GPU.landData);
|
||||
if (GPU.columns) GPU.columns.destroy();
|
||||
GPU.columnData = new Float32Array(W * 4); GPU.columns = gpuBuffer(GPU.columnData);
|
||||
GPU.mach = gpuTexture(W, H, 'r16uint'); GPU.block = gpuTexture(BW, BH, 'r8uint');
|
||||
GPU.worldTextures.push(GPU.mach, GPU.block);
|
||||
GPU.bindColour = null;
|
||||
}
|
||||
function gpuViewTextures() {
|
||||
@@ -40,15 +44,17 @@ function gpuViewTextures() {
|
||||
GPU.colourTex = gpuTexture(bw, bh, 'rgba8unorm', true);
|
||||
GPU.glowTex = gpuTexture(gw, gh, 'rgba8unorm', true);
|
||||
GPU.blurX = gpuTexture(gw, gh, 'rgba8unorm', true); GPU.blurY = gpuTexture(gw, gh, 'rgba8unorm', true);
|
||||
GPU.lightTex = gpuTexture(Math.max(1, R.lw), Math.max(1, R.lh));
|
||||
GPU.viewTextures = [GPU.override, GPU.overrideGlow, GPU.colourTex, GPU.glowTex, GPU.blurX, GPU.blurY, GPU.lightTex];
|
||||
GPU.lightTex = gpuTexture(Math.max(1, R.lw), Math.max(1, R.lh), 'rgba8unorm', true);
|
||||
GPU.lightWork = [0,1].map(() => gpuTexture(Math.max(1,R.lw),Math.max(1,R.lh),'rgba16float',true));
|
||||
GPU.viewTextures = [GPU.override, GPU.overrideGlow, GPU.colourTex, GPU.glowTex, GPU.blurX, GPU.blurY, GPU.lightTex, ...GPU.lightWork];
|
||||
GPU.bindColour = null;
|
||||
}
|
||||
function gpuBindings() {
|
||||
if (GPU.bindColour) return;
|
||||
const d = GPU.device, buffer = b => ({ buffer: b }), view = t => t.createView();
|
||||
const group = (pipeline, resources) => d.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries: resources.map((resource, binding) => ({ binding, resource })) });
|
||||
GPU.bindColour = group(GPU.colour, [buffer(GPU.uniform), buffer(GPU.lut), buffer(GPU.land), ...GPU.worldTextures.map(view), view(GPU.override), view(GPU.overrideGlow), view(GPU.colourTex), view(GPU.glowTex)]);
|
||||
GPU.bindColour = group(GPU.colour, [buffer(GPU.uniform), buffer(GPU.lut), buffer(GPU.land), ...GPU.worldTextures.slice(0,9).map(view), view(GPU.override), view(GPU.overrideGlow), view(GPU.colourTex), view(GPU.glowTex)]);
|
||||
gpuLightBindings(group, view, buffer);
|
||||
GPU.bindDraw = group(GPU.draw, [buffer(GPU.uniform), view(GPU.colourTex), view(GPU.lightTex), view(GPU.blurY), GPU.sampler]);
|
||||
if (GPU.blurUniforms) for (const b of GPU.blurUniforms) b.destroy();
|
||||
GPU.blurUniforms = [0, 1].map(() => d.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST }));
|
||||
@@ -56,11 +62,21 @@ function gpuBindings() {
|
||||
}
|
||||
function gpuUpload(lighting, glowOn) {
|
||||
gpuWorldTextures(); gpuViewTextures(); gpuBindings();
|
||||
const x = Math.max(0, R.vx0 - 2), y = Math.max(0, R.vy0 - 2);
|
||||
const w = Math.min(W, R.vx0 + R.bw + 2) - x, h = Math.min(H, R.vy0 + R.bh + 2) - y;
|
||||
const margin = lighting ? Math.ceil(28 / R.lres) * R.lres + R.lres : 2;
|
||||
const x = Math.max(0, R.vx0 - margin), y = Math.max(0, R.vy0 - margin);
|
||||
const w = Math.min(W, R.vx0 + R.bw + margin) - x, h = Math.min(H, R.vy0 + R.bh + margin + 12) - y;
|
||||
const arrays = [mat, flags, life, part, bgm, digp];
|
||||
arrays.forEach((a, i) => gpuWrite(GPU.worldTextures[i], a, W, x, y, w, h));
|
||||
gpuWrite(GPU.temp, temp, W, x, y, w, h);
|
||||
if (lighting) {
|
||||
let top=y;
|
||||
for(let xx=x;xx<x+w;xx++) top=Math.min(top,roofY[xx]);
|
||||
// Roof scans can start above the view; loose loads also inspect twelve grains below.
|
||||
for(const [t,a] of [[GPU.worldTextures[0],mat],[GPU.worldTextures[1],flags],[GPU.worldTextures[3],part]]) gpuWrite(t,a,W,x,top,w,y+h-top);
|
||||
gpuWrite(GPU.mach,mach,W,x,top,w,y+h-top);
|
||||
const bx=x>>2, by=top>>2;
|
||||
gpuWrite(GPU.block,blockP,BW,bx,by,Math.min(BW,Math.ceil((x+w)/4))-bx,Math.min(BH,Math.ceil((y+h)/4))-by);
|
||||
}
|
||||
const fx = Math.max(0, Math.floor(x / FOG)), fy = Math.max(0, Math.floor(y / FOG));
|
||||
gpuWrite(GPU.worldTextures[7], fog, FW, fx, fy, Math.min(FW, Math.ceil((x + w) / FOG) + 1) - fx, Math.min(FH, Math.ceil((y + h) / FOG) + 1) - fy);
|
||||
// Small per-row/column tables may change in scene tools independently of world allocation.
|
||||
@@ -71,7 +87,8 @@ function gpuUpload(lighting, glowOn) {
|
||||
q.writeBuffer(GPU.land, 0, land);
|
||||
gpuWrite(GPU.override, R.px, R.bw, 0, 0, R.bw, R.bh);
|
||||
gpuWrite(GPU.overrideGlow, R.glowPx, R.glowC.width, 0, 0, R.glowC.width, R.glowC.height);
|
||||
if (lighting) gpuWrite(GPU.lightTex, R.lightPx, R.lw, 0, 0, R.lw, R.lh);
|
||||
for(let i=0;i<W;i++) { GPU.columnData[i*4]=surfY[i]; GPU.columnData[i*4+1]=roofY[i]; }
|
||||
q.writeBuffer(GPU.columns,0,GPU.columnData);
|
||||
const zp = R.zp, ox = Math.round(-(R.camX - R.vx0) * zp), oy = Math.round(-(R.camY - R.vy0) * zp);
|
||||
GPU.params.set([R.vx0, R.vy0, R.bw, R.bh, W, H, FW, FH,
|
||||
+SET.fog, R.rain, SET.grain, R.frame, +R.lens, Math.max(0, Object.keys(THERM).indexOf(SET.thermalPalette)), +SET.incandescence, +glowOn,
|
||||
|
||||
Reference in New Issue
Block a user