webgpu-app/light.js

161 lines
4.5 KiB
JavaScript

import { getPath } from "./common.js";
function parseHeader(buffer)
{
const array = new Uint32Array(buffer);
/*
console.log("index count", icosphereU32[0]);
console.log("index buffer offset", icosphereU32[1]);
console.log("index buffer size", icosphereU32[2]);
console.log("vertex buffer offset", icosphereU32[3]);
console.log("vertex buffer size", icosphereU32[4]);
*/
return {
indexCount: array[0],
indexOffset: array[1],
indexSize: array[2],
vertexOffset: array[3],
vertexSize: array[4],
};
}
class LightRenderer {
constructor(device, canvasFormat, viewUniformBuffer,
shaderModule, binBuffer, label)
{
//////////////////////////////////////////////////////////////////////
// buffer
//////////////////////////////////////////////////////////////////////
const header = parseHeader(binBuffer);
this.header = header;
this.buffer = device.createBuffer({
label: `${label} renderer buffer`,
size: header.indexSize + header.vertexSize,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
this.indexOffset = 0;
this.vertexOffset = header.indexSize;
device.queue.writeBuffer(this.buffer, this.indexOffset,
binBuffer, header.indexOffset, header.indexSize);
device.queue.writeBuffer(this.buffer, this.vertexOffset,
binBuffer, header.vertexOffset, header.vertexSize);
//////////////////////////////////////////////////////////////////////
// pipeline
//////////////////////////////////////////////////////////////////////
const bindGroupLayouts = [
device.createBindGroupLayout({
label: `${label} view matrix bind group layout`,
entries: [{
binding: 0,
visibility: GPUShaderStage.VERTEX,
buffer: { type: "uniform" }
},/* {
binding: 1,
visibility: GPUShaderStage.VERTEX,
buffer: { type: "read-only-storage" }
}*/]
}),
];
const pipelineLayout = device.createPipelineLayout({
label: `${label} pipeline layout`,
bindGroupLayouts: bindGroupLayouts,
});
const vertexBufferLayouts = [{
arrayStride: 36,
attributes: [{
format: "float32x3",
offset: 0,
shaderLocation: 0,
}, {
format: "float32x2",
offset: 12,
shaderLocation: 1,
}, {
format: "float16x4",
offset: 20,
shaderLocation: 2,
}, {
format: "float16x4",
offset: 28,
shaderLocation: 3,
}],
stepMode: "vertex",
}];
this.renderPipeline = device.createRenderPipeline({
label: `${label} pipeline`,
layout: pipelineLayout,
vertex: {
module: shaderModule,
entryPoint: "vertexMain",
buffers: vertexBufferLayouts,
},
fragment: {
module: shaderModule,
entryPoint: "fragmentMain",
targets: [{
format: canvasFormat,
}]
},
primitive: {
topology: "triangle-list",
},
depthStencil: {
depthWriteEnabled: true,
depthCompare: "less",
format: "depth24plus",
},
});
//////////////////////////////////////////////////////////////////////
// bind group
//////////////////////////////////////////////////////////////////////
this.bindGroups = [
device.createBindGroup({
label: `${label} bind group`,
layout: bindGroupLayouts[0],
entries: [{
binding: 0,
resource: { buffer: viewUniformBuffer },
}],
}),
];
}
render(renderPass)
{
renderPass.setPipeline(this.renderPipeline);
renderPass.setVertexBuffer(0, this.buffer, this.vertexOffset, this.header.vertexSize);
renderPass.setIndexBuffer(this.buffer, "uint16", this.indexOffset, this.header.indexSize);
renderPass.setBindGroup(0, this.bindGroups[0]);
renderPass.drawIndexed(this.header.indexCount);
}
}
async function loadLight(device, canvasFormat, viewUniformBuffer)
{
const lightWgsl = getPath("light.wgsl");
const shaderModule = device.createShaderModule({
label: "light shader",
code: await lightWgsl,
});
const response = await fetch("obj/icosphere.bin");
const binBuffer = await response.arrayBuffer();
const renderer = new LightRenderer(device, canvasFormat, viewUniformBuffer,
shaderModule, binBuffer, "light");
return renderer;
}
export { loadLight };