webgpu-app/index2.js
2026-07-20 23:30:29 -05:00

162 lines
4.8 KiB
JavaScript

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