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 };