playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
87 lines (86 loc) • 3.69 kB
JavaScript
import {
BUFFER_STATIC,
INDEXFORMAT_UINT16,
INDEXFORMAT_UINT32,
SEMANTIC_COLOR,
SEMANTIC_NORMAL,
TYPE_UINT8,
TYPE_UINT16
} from "../../../../platform/graphics/constants.js";
import { IndexBuffer } from "../../../../platform/graphics/index-buffer.js";
import { VertexBuffer } from "../../../../platform/graphics/vertex-buffer.js";
import { VertexFormat } from "../../../../platform/graphics/vertex-format.js";
import { Mesh } from "../../../../scene/mesh.js";
import { dracoDecode } from "../../draco-decoder.js";
import { GltfAccessor, getPrimitiveType, gltfToEngineSemanticMap } from "../gltf-accessor.js";
import { registerMeshVariants } from "./khr-materials-variants.js";
const createDracoMesh = (device, primitive, accessors, bufferViews, meshVariants, meshDefaultMaterials, promises) => {
const result = new Mesh(device);
result.aabb = GltfAccessor.getBoundingBox(accessors[primitive.attributes.POSITION]);
promises.push(new Promise((resolve, reject) => {
const dracoExt = primitive.extensions.KHR_draco_mesh_compression;
const initialized = dracoDecode(bufferViews[dracoExt.bufferView].slice().buffer, (err, decompressedData) => {
if (err) {
console.log(err);
reject(err);
} else {
const idToSemantic = {};
for (const [name, id] of Object.entries(dracoExt.attributes)) {
idToSemantic[id] = gltfToEngineSemanticMap[name];
}
idToSemantic[-1] = SEMANTIC_NORMAL;
const vertexDesc = [];
for (const attr of decompressedData.attributes) {
const semantic = idToSemantic[attr.id];
if (semantic !== void 0) {
let normalize = false;
if (attr.id !== -1) {
for (const [name, id] of Object.entries(dracoExt.attributes)) {
if (id === attr.id && primitive.attributes[name] !== void 0) {
const accessor = accessors[primitive.attributes[name]];
normalize = accessor.normalized ?? (semantic === SEMANTIC_COLOR && (attr.dataType === TYPE_UINT8 || attr.dataType === TYPE_UINT16));
break;
}
}
}
vertexDesc.push({
semantic,
components: attr.numComponents,
type: attr.dataType,
normalize,
// use offset and stride from worker to handle cases where Draco mesh
// has additional attributes not listed in glTF
offset: attr.offset,
stride: decompressedData.stride
});
}
}
const vertexFormat = new VertexFormat(device, vertexDesc);
const numVertices = decompressedData.vertices.byteLength / decompressedData.stride;
const indexFormat = numVertices <= 65535 ? INDEXFORMAT_UINT16 : INDEXFORMAT_UINT32;
const numIndices = decompressedData.indices.byteLength / (numVertices <= 65535 ? 2 : 4);
const vertexBuffer = new VertexBuffer(device, vertexFormat, numVertices, {
data: decompressedData.vertices
});
const indexBuffer = new IndexBuffer(device, indexFormat, numIndices, BUFFER_STATIC, decompressedData.indices);
result.vertexBuffer = vertexBuffer;
result.indexBuffer[0] = indexBuffer;
result.primitive[0].type = getPrimitiveType(primitive);
result.primitive[0].base = 0;
result.primitive[0].count = indexBuffer ? numIndices : numVertices;
result.primitive[0].indexed = !!indexBuffer;
resolve();
}
});
if (!initialized) {
const message = "glTF file contains Draco compressed meshes, but the Draco decoder is not configured. Call dracoInitialize() or WasmModule.setConfig('DracoDecoderModule', ...) before loading the asset.";
reject(new Error(message));
}
}));
registerMeshVariants(primitive, result.id, meshVariants);
meshDefaultMaterials[result.id] = primitive.material;
return result;
};
export {
createDracoMesh
};