import { getPath } from "./common.js"; import { parseGltfChunks, primitiveVertexBufferLayouts } from "./gltf.js"; class GltfRenderer { constructor(device, canvasFormat, shaderModule, gltf, primitive, bufferLayouts) { this.gltf = gltf; this.primitive = primitive; ////////////////////////////////////////////////////////////////////// // buffer ////////////////////////////////////////////////////////////////////// console.assert(gltf.json.buffers[0].byteLength == gltf.bin.length); this.vertexBuffer = device.createBuffer({ label: "gltf vertex buffer 0", size: gltf.bin.length, usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, }); device.queue.writeBuffer(this.vertexBuffer, 0, gltf.bin.buffer, gltf.bin.offset, gltf.bin.length); ////////////////////////////////////////////////////////////////////// // pipeline ////////////////////////////////////////////////////////////////////// const bindGroupLayouts = [ device.createBindGroupLayout({ label: "gltf bind group layout 0", entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: "uniform" } }] }), ]; const pipelineLayout = device.createPipelineLayout({ label: "gltf pipeline layout", bindGroupLayouts: bindGroupLayouts, }); this.renderPipeline = device.createRenderPipeline({ label: "gltf pipeline", layout: pipelineLayout, vertex: { module: shaderModule, entryPoint: "vertexMain", buffers: bufferLayouts, }, fragment: { module: shaderModule, entryPoint: "fragmentMain", targets: [{ format: canvasFormat, }] }, primitive: { topology: 'triangle-list', }, depthStencil: { depthWriteEnabled: true, depthCompare: 'less', format: 'depth24plus', }, }); ////////////////////////////////////////////////////////////////////// // bind group ////////////////////////////////////////////////////////////////////// this.uniformBufferSize = (4 * 4 * 4) * 2; this.uniformBuffer = device.createBuffer({ label: "gltf uniform 0", size: this.uniformBufferSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, }); this.bindGroups = [ device.createBindGroup({ label: "cell bind group 0", layout: bindGroupLayouts[0], entries: [{ binding: 0, resource: { buffer: this.uniformBuffer }, }] }), ]; } render(device, colorView, depthTexture) { const encoder = device.createCommandEncoder(); const renderPass = encoder.beginRenderPass({ colorAttachments: [{ view: colorView, loadOp: "clear", clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 }, storeOp: "store", }], depthStencilAttachment: { view: depthTexture.createView(), depthClearValue: 1.0, depthLoadOp: 'clear', depthStoreOp: 'store', }, }); renderPass.setPipeline(this.renderPipeline); const attributes = ["POSITION", "NORMAL", "TEXCOORD_0"]; for (let i = 0; i < attributes.length; i++) { const attributeIndex = this.primitive.attributes[attributes[i]]; const bufferViewIndex = this.gltf.json.accessors[attributeIndex].bufferView; const bufferView = this.gltf.json.bufferViews[bufferViewIndex]; renderPass.setVertexBuffer(i, this.vertexBuffer, bufferView.byteOffset, bufferView.byteLength); } const indicesAccessor = this.gltf.json.accessors[this.primitive.indices]; const indicesBufferView = this.gltf.json.bufferViews[indicesAccessor.bufferView]; renderPass.setIndexBuffer(this.vertexBuffer, "uint16", indicesBufferView.byteOffset, indicesBufferView.byteLength); renderPass.setBindGroup(0, this.bindGroups[0]); renderPass.drawIndexed(indicesAccessor.count); renderPass.end(); const commandBuffer = encoder.finish(); device.queue.submit([commandBuffer]); } } async function loadGltf(device, canvasFormat) { const response = await fetch("monkey.glb"); const buffer = await response.arrayBuffer(); const gltf = parseGltfChunks(buffer); console.log(gltf); const primitive = gltf.json.meshes[0].primitives[0]; //console.log(primitive.indices); //console.log(primitive.attributes); const bufferLayouts = primitiveVertexBufferLayouts(gltf, primitive); console.log(bufferLayouts); const code = await getPath("gltf.wgsl"); const shaderModule = device.createShaderModule({ label: "gltf module", code: await code, }); const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf, primitive, bufferLayouts); return renderer; } export { loadGltf };