support for multiple {buffers, meshes, primitives, vertex layouts}
This commit is contained in:
parent
2dfd749180
commit
f781e5f134
32
gltf.js
32
gltf.js
@ -17,7 +17,9 @@ function parseGltfChunks(buffer)
|
||||
console.assert(magic === 0x46546C67);
|
||||
console.assert(version === 2);
|
||||
|
||||
const gltf = {};
|
||||
const gltf = {
|
||||
bin: [],
|
||||
};
|
||||
|
||||
var offset = 12;
|
||||
while ((length - offset) > 0) {
|
||||
@ -34,8 +36,7 @@ function parseGltfChunks(buffer)
|
||||
gltf.json = object;
|
||||
}
|
||||
if (chunkType === 0x004E4942) {
|
||||
console.assert(!("bin" in gltf));
|
||||
gltf.bin = {buffer: buffer, offset: offset, length: chunkLength};
|
||||
gltf.bin.push({buffer: buffer, offset: offset, length: chunkLength});
|
||||
}
|
||||
|
||||
offset += chunkLength;
|
||||
@ -127,24 +128,29 @@ function vertexFormat(componentType, type)
|
||||
}
|
||||
}
|
||||
|
||||
function primitiveVertexBufferLayouts(gltf, primitive)
|
||||
function primitiveAccessors(primitive)
|
||||
{
|
||||
const accessors = [
|
||||
gltf.json.accessors[primitive.attributes["POSITION"]],
|
||||
gltf.json.accessors[primitive.attributes["NORMAL"]],
|
||||
gltf.json.accessors[primitive.attributes["TEXCOORD_0"]],
|
||||
return [
|
||||
primitive.attributes["POSITION"],
|
||||
primitive.attributes["NORMAL"],
|
||||
primitive.attributes["TEXCOORD_0"],
|
||||
primitive.attributes["TANGENT"],
|
||||
];
|
||||
}
|
||||
|
||||
function vertexBufferLayouts(gltf, accessors)
|
||||
{
|
||||
const layouts = [];
|
||||
|
||||
for (let i = 0; i < accessors.length; i++) {
|
||||
const componentType = accessors[i].componentType;
|
||||
const type = accessors[i].type;
|
||||
const accessor = gltf.json.accessors[accessors[i]];
|
||||
const componentType = accessor.componentType;
|
||||
const type = accessor.type;
|
||||
|
||||
const bufferView = gltf.json.bufferViews[accessors[i].bufferView];
|
||||
const bufferView = gltf.json.bufferViews[accessor.bufferView];
|
||||
|
||||
const arrayStride = "byteStride" in bufferView ? bufferView.byteStride : attributeStride(componentType, type);
|
||||
const offset = "byteOffset" in accessors[i] ? accessors[i].byteOffset : 0;
|
||||
const offset = "byteOffset" in accessor ? accessor.byteOffset : 0;
|
||||
const layout = {
|
||||
arrayStride: arrayStride,
|
||||
attributes: [{
|
||||
@ -159,4 +165,4 @@ function primitiveVertexBufferLayouts(gltf, primitive)
|
||||
return layouts;
|
||||
}
|
||||
|
||||
export { parseGltfChunks, primitiveVertexBufferLayouts };
|
||||
export { parseGltfChunks, vertexBufferLayouts, primitiveAccessors };
|
||||
|
||||
157
index2.js
157
index2.js
@ -1,23 +1,29 @@
|
||||
import { getPath } from "./common.js";
|
||||
import { parseGltfChunks, primitiveVertexBufferLayouts } from "./gltf.js";
|
||||
import { parseGltfChunks, vertexBufferLayouts, primitiveAccessors } from "./gltf.js";
|
||||
|
||||
class GltfRenderer {
|
||||
constructor(device, canvasFormat, shaderModule, gltf, primitive, bufferLayouts)
|
||||
constructor(device, canvasFormat, shaderModule, gltf)
|
||||
{
|
||||
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);
|
||||
this.buffers = [];
|
||||
|
||||
console.assert(gltf.json.buffers.length === gltf.bin.length);
|
||||
for (let i = 0; i < gltf.bin.length; i++) {
|
||||
console.assert(gltf.json.buffers[i].byteLength == gltf.bin[i].length);
|
||||
const buffer = device.createBuffer({
|
||||
label: `gltf vertex buffer {i}`,
|
||||
size: gltf.bin[i].length,
|
||||
usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
device.queue.writeBuffer(buffer, 0,
|
||||
gltf.bin[i].buffer, gltf.bin[i].offset, gltf.bin[i].length);
|
||||
this.buffers.push(buffer);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// pipeline
|
||||
@ -39,30 +45,54 @@ class GltfRenderer {
|
||||
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',
|
||||
},
|
||||
});
|
||||
// by vertex buffer layout
|
||||
const renderPipelineKeys = {};
|
||||
this.renderPipelines = {};
|
||||
|
||||
this.meshes = [];
|
||||
for (let i = 0; i < gltf.json.meshes.length; i++) {
|
||||
const mesh = gltf.json.meshes[i];
|
||||
const meshPrimitives = [];
|
||||
|
||||
for (let j = 0; j < mesh.primitives.length; j++) {
|
||||
const accessors = primitiveAccessors(mesh.primitives[j]);
|
||||
const key = accessors.join(";");
|
||||
meshPrimitives.push([key, accessors]);
|
||||
renderPipelineKeys[key] = accessors;
|
||||
}
|
||||
this.meshes.push(meshPrimitives);
|
||||
}
|
||||
|
||||
for (let [key, accessors] of Object.entries(renderPipelineKeys)) {
|
||||
const bufferLayouts = vertexBufferLayouts(gltf, accessors);
|
||||
|
||||
const 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',
|
||||
},
|
||||
});
|
||||
|
||||
this.renderPipelines[key] = renderPipeline;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// bind group
|
||||
@ -87,6 +117,27 @@ class GltfRenderer {
|
||||
];
|
||||
}
|
||||
|
||||
renderPrimitive(renderPass, accessors, indices)
|
||||
{
|
||||
for (let i = 0; i < accessors.length; i++) {
|
||||
const accessor = accessors[i];
|
||||
const bufferViewIndex = this.gltf.json.accessors[accessor].bufferView;
|
||||
const bufferView = this.gltf.json.bufferViews[bufferViewIndex];
|
||||
|
||||
renderPass.setVertexBuffer(i, this.buffers[bufferView.buffer], bufferView.byteOffset, bufferView.byteLength);
|
||||
}
|
||||
|
||||
const indicesAccessor = this.gltf.json.accessors[indices];
|
||||
const indicesBufferView = this.gltf.json.bufferViews[indicesAccessor.bufferView];
|
||||
renderPass.setIndexBuffer(this.buffers[indicesBufferView.buffer],
|
||||
"uint16",
|
||||
indicesBufferView.byteOffset,
|
||||
indicesBufferView.byteLength);
|
||||
|
||||
renderPass.setBindGroup(0, this.bindGroups[0]);
|
||||
renderPass.drawIndexed(indicesAccessor.count);
|
||||
}
|
||||
|
||||
render(device, colorView, depthTexture)
|
||||
{
|
||||
const encoder = device.createCommandEncoder();
|
||||
@ -105,27 +156,20 @@ class GltfRenderer {
|
||||
},
|
||||
});
|
||||
|
||||
renderPass.setPipeline(this.renderPipeline);
|
||||
var lastKey = undefined;
|
||||
for (let i = 0; i < this.gltf.json.meshes.length; i++) {
|
||||
const mesh = this.gltf.json.meshes[i];
|
||||
for (let j = 0; j < mesh.primitives.length; j++) {
|
||||
const [key, accessors] = this.meshes[i][j];
|
||||
if (key !== lastKey)
|
||||
renderPass.setPipeline(this.renderPipelines[key]);
|
||||
lastKey = key;
|
||||
|
||||
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 primitive = mesh.primitives[j];
|
||||
this.renderPrimitive(renderPass, accessors, primitive.indices);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@ -140,20 +184,13 @@ async function loadGltf(device, canvasFormat)
|
||||
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);
|
||||
const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user