Files
deepgrain-foundry/src/render/gpu/smooth.js
T

48 lines
3.1 KiB
JavaScript

// Field mip levels preserve the legacy trilinear AO sample at level 2.2.
const GPU_FIELD_MIP = `
@group(0) @binding(0) var source: texture_2d<f32>;
@group(0) @binding(1) var linear: sampler;
@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
let pos=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3)); return vec4f(pos[i],0,1);
}
@fragment fn fs(@builtin(position) p: vec4f) -> @location(0) vec4f {
let size=max(vec2u(1),textureDimensions(source)/2u);
return textureSampleLevel(source,linear,p.xy/vec2f(size),0);
}`;
function gpuSmoothInit() {
const d=GPU.device;
const pipeline=(code,vertex,format)=>d.createRenderPipeline({layout:'auto',vertex:{module:d.createShaderModule({code:vertex}),entryPoint:'vs'},fragment:{module:d.createShaderModule({code}),entryPoint:'fs',targets:[{format}]},primitive:{topology:'triangle-list'}});
GPU.smooth=pipeline(GPU_SMOOTH,GPU_DRAW,GPU.format);
GPU.fieldMip=pipeline(GPU_FIELD_MIP,GPU_FIELD_MIP,'rgba8unorm');
GPU.smoothUniform=d.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});
}
function gpuSmoothTextures() {
const w=R.bw,h=R.bh;
GPU.smoothOver=Array.from({length:3},()=>gpuTexture(w,h));
GPU.smoothMask=gpuTexture(w,h,'r8uint');
GPU.backTex=gpuTexture(w,h,'rgba8unorm',true);
GPU.treeTex=gpuTexture(w,h,'rgba8unorm',true);
GPU.fieldTex=GPU.device.createTexture({size:[w,h],format:'rgba8unorm',mipLevelCount:Math.min(4,1+Math.floor(Math.log2(Math.max(w,h)))),usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT});
GPU.viewTextures.push(...GPU.smoothOver,GPU.smoothMask,GPU.backTex,GPU.treeTex,GPU.fieldTex);
}
function gpuSmoothBindings(group,view,buffer) {
GPU.bindColourSmooth=group(GPU.colourSmooth,[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),view(GPU.backTex),view(GPU.treeTex),GPU.fieldTex.createView({baseMipLevel:0,mipLevelCount:1}),...GPU.smoothOver.map(view),view(GPU.smoothMask)]);
GPU.bindSmooth=group(GPU.smooth,[buffer(GPU.uniform),view(GPU.colourTex),view(GPU.backTex),view(GPU.treeTex),view(GPU.fieldTex),view(GPU.lightTex),view(GPU.glowTex),GPU.sampler,buffer(GPU.smoothUniform)]);
GPU.fieldMips=[];
for(let i=1;i<GPU.fieldTex.mipLevelCount;i++) GPU.fieldMips.push({
bind:group(GPU.fieldMip,[GPU.fieldTex.createView({baseMipLevel:i-1,mipLevelCount:1}),GPU.sampler]),
view:GPU.fieldTex.createView({baseMipLevel:i,mipLevelCount:1})
});
}
function gpuSmoothUpload() {
for(const [i,a] of [R.backPx,R.treePx,R.fieldPx].entries()) gpuWrite(GPU.smoothOver[i],a,R.bw,0,0,R.bw,R.bh);
gpuWrite(GPU.smoothMask,GPU.overrideMask,R.bw,0,0,R.bw,R.bh);
GPU.device.queue.writeBuffer(GPU.smoothUniform,0,new Float32Array([(performance.now()-SM.t0)/1000,smoothSurface(),SET.glow==='off'?0:SET.glow==='high'?0.9:0.55,0]));
}
function gpuSmoothMips(encoder) {
for(const m of GPU.fieldMips) {
const pass=encoder.beginRenderPass({colorAttachments:[{view:m.view,loadOp:'clear',storeOp:'store'}]});
pass.setPipeline(GPU.fieldMip);pass.setBindGroup(0,m.bind);pass.draw(3);pass.end();
}
}