162 lines
4.8 KiB
JavaScript
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 };
|