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(magic === 0x46546C67);
|
||||||
console.assert(version === 2);
|
console.assert(version === 2);
|
||||||
|
|
||||||
const gltf = {};
|
const gltf = {
|
||||||
|
bin: [],
|
||||||
|
};
|
||||||
|
|
||||||
var offset = 12;
|
var offset = 12;
|
||||||
while ((length - offset) > 0) {
|
while ((length - offset) > 0) {
|
||||||
@ -34,8 +36,7 @@ function parseGltfChunks(buffer)
|
|||||||
gltf.json = object;
|
gltf.json = object;
|
||||||
}
|
}
|
||||||
if (chunkType === 0x004E4942) {
|
if (chunkType === 0x004E4942) {
|
||||||
console.assert(!("bin" in gltf));
|
gltf.bin.push({buffer: buffer, offset: offset, length: chunkLength});
|
||||||
gltf.bin = {buffer: buffer, offset: offset, length: chunkLength};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += chunkLength;
|
offset += chunkLength;
|
||||||
@ -127,24 +128,29 @@ function vertexFormat(componentType, type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function primitiveVertexBufferLayouts(gltf, primitive)
|
function primitiveAccessors(primitive)
|
||||||
{
|
{
|
||||||
const accessors = [
|
return [
|
||||||
gltf.json.accessors[primitive.attributes["POSITION"]],
|
primitive.attributes["POSITION"],
|
||||||
gltf.json.accessors[primitive.attributes["NORMAL"]],
|
primitive.attributes["NORMAL"],
|
||||||
gltf.json.accessors[primitive.attributes["TEXCOORD_0"]],
|
primitive.attributes["TEXCOORD_0"],
|
||||||
|
primitive.attributes["TANGENT"],
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function vertexBufferLayouts(gltf, accessors)
|
||||||
|
{
|
||||||
const layouts = [];
|
const layouts = [];
|
||||||
|
|
||||||
for (let i = 0; i < accessors.length; i++) {
|
for (let i = 0; i < accessors.length; i++) {
|
||||||
const componentType = accessors[i].componentType;
|
const accessor = gltf.json.accessors[accessors[i]];
|
||||||
const type = accessors[i].type;
|
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 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 = {
|
const layout = {
|
||||||
arrayStride: arrayStride,
|
arrayStride: arrayStride,
|
||||||
attributes: [{
|
attributes: [{
|
||||||
@ -159,4 +165,4 @@ function primitiveVertexBufferLayouts(gltf, primitive)
|
|||||||
return layouts;
|
return layouts;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { parseGltfChunks, primitiveVertexBufferLayouts };
|
export { parseGltfChunks, vertexBufferLayouts, primitiveAccessors };
|
||||||
|
|||||||
107
index2.js
107
index2.js
@ -1,23 +1,29 @@
|
|||||||
import { getPath } from "./common.js";
|
import { getPath } from "./common.js";
|
||||||
import { parseGltfChunks, primitiveVertexBufferLayouts } from "./gltf.js";
|
import { parseGltfChunks, vertexBufferLayouts, primitiveAccessors } from "./gltf.js";
|
||||||
|
|
||||||
class GltfRenderer {
|
class GltfRenderer {
|
||||||
constructor(device, canvasFormat, shaderModule, gltf, primitive, bufferLayouts)
|
constructor(device, canvasFormat, shaderModule, gltf)
|
||||||
{
|
{
|
||||||
this.gltf = gltf;
|
this.gltf = gltf;
|
||||||
this.primitive = primitive;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// buffer
|
// buffer
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
console.assert(gltf.json.buffers[0].byteLength == gltf.bin.length);
|
this.buffers = [];
|
||||||
this.vertexBuffer = device.createBuffer({
|
|
||||||
label: "gltf vertex buffer 0",
|
console.assert(gltf.json.buffers.length === gltf.bin.length);
|
||||||
size: 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,
|
usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
||||||
});
|
});
|
||||||
device.queue.writeBuffer(this.vertexBuffer, 0, gltf.bin.buffer, gltf.bin.offset, gltf.bin.length);
|
device.queue.writeBuffer(buffer, 0,
|
||||||
|
gltf.bin[i].buffer, gltf.bin[i].offset, gltf.bin[i].length);
|
||||||
|
this.buffers.push(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// pipeline
|
// pipeline
|
||||||
@ -39,7 +45,28 @@ class GltfRenderer {
|
|||||||
bindGroupLayouts: bindGroupLayouts,
|
bindGroupLayouts: bindGroupLayouts,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.renderPipeline = device.createRenderPipeline({
|
// 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",
|
label: "gltf pipeline",
|
||||||
layout: pipelineLayout,
|
layout: pipelineLayout,
|
||||||
vertex: {
|
vertex: {
|
||||||
@ -64,6 +91,9 @@ class GltfRenderer {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.renderPipelines[key] = renderPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// bind group
|
// 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)
|
render(device, colorView, depthTexture)
|
||||||
{
|
{
|
||||||
const encoder = device.createCommandEncoder();
|
const encoder = device.createCommandEncoder();
|
||||||
@ -105,26 +156,19 @@ 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"];
|
const primitive = mesh.primitives[j];
|
||||||
for (let i = 0; i < attributes.length; i++) {
|
this.renderPrimitive(renderPass, accessors, primitive.indices);
|
||||||
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();
|
renderPass.end();
|
||||||
|
|
||||||
@ -140,20 +184,13 @@ async function loadGltf(device, canvasFormat)
|
|||||||
const gltf = parseGltfChunks(buffer);
|
const gltf = parseGltfChunks(buffer);
|
||||||
console.log(gltf);
|
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 code = await getPath("gltf.wgsl");
|
||||||
const shaderModule = device.createShaderModule({
|
const shaderModule = device.createShaderModule({
|
||||||
label: "gltf module",
|
label: "gltf module",
|
||||||
code: await code,
|
code: await code,
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf, primitive, bufferLayouts);
|
const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf);
|
||||||
|
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user