123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812 |
- import { EParameterType, ETextureFilterType, ECullingType, EBlendingFunction, EShaderType } from "./glTFLoaderInterfaces.js";
- import { Quaternion, Vector3, Matrix } from "@babylonjs/core/Maths/math.vector.js";
- import { Color3 } from "@babylonjs/core/Maths/math.color.js";
- import { Tools } from "@babylonjs/core/Misc/tools.js";
- import { Camera } from "@babylonjs/core/Cameras/camera.js";
- import { FreeCamera } from "@babylonjs/core/Cameras/freeCamera.js";
- import { Animation } from "@babylonjs/core/Animations/animation.js";
- import { Bone } from "@babylonjs/core/Bones/bone.js";
- import { Skeleton } from "@babylonjs/core/Bones/skeleton.js";
- import { Effect } from "@babylonjs/core/Materials/effect.js";
- import { Material } from "@babylonjs/core/Materials/material.js";
- import { MultiMaterial } from "@babylonjs/core/Materials/multiMaterial.js";
- import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
- import { ShaderMaterial } from "@babylonjs/core/Materials/shaderMaterial.js";
- import { Texture } from "@babylonjs/core/Materials/Textures/texture.js";
- import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData.js";
- import { VertexBuffer } from "@babylonjs/core/Buffers/buffer.js";
- import { Geometry } from "@babylonjs/core/Meshes/geometry.js";
- import { SubMesh } from "@babylonjs/core/Meshes/subMesh.js";
- import { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh.js";
- import { Mesh } from "@babylonjs/core/Meshes/mesh.js";
- import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight.js";
- import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight.js";
- import { PointLight } from "@babylonjs/core/Lights/pointLight.js";
- import { SpotLight } from "@babylonjs/core/Lights/spotLight.js";
- import { GLTFUtils } from "./glTFLoaderUtils.js";
- import { GLTFFileLoader } from "../glTFFileLoader.js";
- import { Constants } from "@babylonjs/core/Engines/constants.js";
- /**
- * Tokenizer. Used for shaders compatibility
- * Automatically map world, view, projection, worldViewProjection, attributes and so on
- */
- var ETokenType;
- (function (ETokenType) {
- ETokenType[ETokenType["IDENTIFIER"] = 1] = "IDENTIFIER";
- ETokenType[ETokenType["UNKNOWN"] = 2] = "UNKNOWN";
- ETokenType[ETokenType["END_OF_INPUT"] = 3] = "END_OF_INPUT";
- })(ETokenType || (ETokenType = {}));
- class Tokenizer {
- constructor(toParse) {
- this._pos = 0;
- this.currentToken = ETokenType.UNKNOWN;
- this.currentIdentifier = "";
- this.currentString = "";
- this.isLetterOrDigitPattern = /^[a-zA-Z0-9]+$/;
- this._toParse = toParse;
- this._maxPos = toParse.length;
- }
- getNextToken() {
- if (this.isEnd()) {
- return ETokenType.END_OF_INPUT;
- }
- this.currentString = this.read();
- this.currentToken = ETokenType.UNKNOWN;
- if (this.currentString === "_" || this.isLetterOrDigitPattern.test(this.currentString)) {
- this.currentToken = ETokenType.IDENTIFIER;
- this.currentIdentifier = this.currentString;
- while (!this.isEnd() && (this.isLetterOrDigitPattern.test((this.currentString = this.peek())) || this.currentString === "_")) {
- this.currentIdentifier += this.currentString;
- this.forward();
- }
- }
- return this.currentToken;
- }
- peek() {
- return this._toParse[this._pos];
- }
- read() {
- return this._toParse[this._pos++];
- }
- forward() {
- this._pos++;
- }
- isEnd() {
- return this._pos >= this._maxPos;
- }
- }
- /**
- * Values
- */
- const glTFTransforms = ["MODEL", "VIEW", "PROJECTION", "MODELVIEW", "MODELVIEWPROJECTION", "JOINTMATRIX"];
- const babylonTransforms = ["world", "view", "projection", "worldView", "worldViewProjection", "mBones"];
- const glTFAnimationPaths = ["translation", "rotation", "scale"];
- const babylonAnimationPaths = ["position", "rotationQuaternion", "scaling"];
- /**
- * Parse
- * @param parsedBuffers
- * @param gltfRuntime
- */
- const parseBuffers = (parsedBuffers, gltfRuntime) => {
- for (const buf in parsedBuffers) {
- const parsedBuffer = parsedBuffers[buf];
- gltfRuntime.buffers[buf] = parsedBuffer;
- gltfRuntime.buffersCount++;
- }
- };
- const parseShaders = (parsedShaders, gltfRuntime) => {
- for (const sha in parsedShaders) {
- const parsedShader = parsedShaders[sha];
- gltfRuntime.shaders[sha] = parsedShader;
- gltfRuntime.shaderscount++;
- }
- };
- const parseObject = (parsedObjects, runtimeProperty, gltfRuntime) => {
- for (const object in parsedObjects) {
- const parsedObject = parsedObjects[object];
- gltfRuntime[runtimeProperty][object] = parsedObject;
- }
- };
- /**
- * Utils
- * @param buffer
- */
- const normalizeUVs = (buffer) => {
- if (!buffer) {
- return;
- }
- for (let i = 0; i < buffer.length / 2; i++) {
- buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
- }
- };
- const getAttribute = (attributeParameter) => {
- if (attributeParameter.semantic === "NORMAL") {
- return "normal";
- }
- else if (attributeParameter.semantic === "POSITION") {
- return "position";
- }
- else if (attributeParameter.semantic === "JOINT") {
- return "matricesIndices";
- }
- else if (attributeParameter.semantic === "WEIGHT") {
- return "matricesWeights";
- }
- else if (attributeParameter.semantic === "COLOR") {
- return "color";
- }
- else if (attributeParameter.semantic && attributeParameter.semantic.indexOf("TEXCOORD_") !== -1) {
- const channel = Number(attributeParameter.semantic.split("_")[1]);
- return "uv" + (channel === 0 ? "" : channel + 1);
- }
- return null;
- };
- /**
- * Loads and creates animations
- * @param gltfRuntime
- */
- const loadAnimations = (gltfRuntime) => {
- for (const anim in gltfRuntime.animations) {
- const animation = gltfRuntime.animations[anim];
- if (!animation.channels || !animation.samplers) {
- continue;
- }
- let lastAnimation = null;
- for (let i = 0; i < animation.channels.length; i++) {
- // Get parameters and load buffers
- const channel = animation.channels[i];
- const sampler = animation.samplers[channel.sampler];
- if (!sampler) {
- continue;
- }
- let inputData = null;
- let outputData = null;
- if (animation.parameters) {
- inputData = animation.parameters[sampler.input];
- outputData = animation.parameters[sampler.output];
- }
- else {
- inputData = sampler.input;
- outputData = sampler.output;
- }
- const bufferInput = GLTFUtils.GetBufferFromAccessor(gltfRuntime, gltfRuntime.accessors[inputData]);
- const bufferOutput = GLTFUtils.GetBufferFromAccessor(gltfRuntime, gltfRuntime.accessors[outputData]);
- const targetId = channel.target.id;
- let targetNode = gltfRuntime.scene.getNodeById(targetId);
- if (targetNode === null) {
- targetNode = gltfRuntime.scene.getNodeByName(targetId);
- }
- if (targetNode === null) {
- Tools.Warn("Creating animation named " + anim + ". But cannot find node named " + targetId + " to attach to");
- continue;
- }
- const isBone = targetNode instanceof Bone;
- // Get target path (position, rotation or scaling)
- let targetPath = channel.target.path;
- const targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
- if (targetPathIndex !== -1) {
- targetPath = babylonAnimationPaths[targetPathIndex];
- }
- // Determine animation type
- let animationType = Animation.ANIMATIONTYPE_MATRIX;
- if (!isBone) {
- if (targetPath === "rotationQuaternion") {
- animationType = Animation.ANIMATIONTYPE_QUATERNION;
- targetNode.rotationQuaternion = new Quaternion();
- }
- else {
- animationType = Animation.ANIMATIONTYPE_VECTOR3;
- }
- }
- // Create animation and key frames
- let babylonAnimation = null;
- const keys = [];
- let arrayOffset = 0;
- let modifyKey = false;
- if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
- babylonAnimation = lastAnimation;
- modifyKey = true;
- }
- if (!modifyKey) {
- gltfRuntime.scene._blockEntityCollection = !!gltfRuntime.assetContainer;
- babylonAnimation = new Animation(anim, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
- gltfRuntime.scene._blockEntityCollection = false;
- }
- // For each frame
- for (let j = 0; j < bufferInput.length; j++) {
- let value = null;
- if (targetPath === "rotationQuaternion") {
- // VEC4
- value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
- arrayOffset += 4;
- }
- else {
- // Position and scaling are VEC3
- value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
- arrayOffset += 3;
- }
- if (isBone) {
- const bone = targetNode;
- let translation = Vector3.Zero();
- let rotationQuaternion = new Quaternion();
- let scaling = Vector3.Zero();
- // Warning on decompose
- let mat = bone.getBaseMatrix();
- if (modifyKey && lastAnimation) {
- mat = lastAnimation.getKeys()[j].value;
- }
- mat.decompose(scaling, rotationQuaternion, translation);
- if (targetPath === "position") {
- translation = value;
- }
- else if (targetPath === "rotationQuaternion") {
- rotationQuaternion = value;
- }
- else {
- scaling = value;
- }
- value = Matrix.Compose(scaling, rotationQuaternion, translation);
- }
- if (!modifyKey) {
- keys.push({
- frame: bufferInput[j],
- value: value,
- });
- }
- else if (lastAnimation) {
- lastAnimation.getKeys()[j].value = value;
- }
- }
- // Finish
- if (!modifyKey && babylonAnimation) {
- babylonAnimation.setKeys(keys);
- targetNode.animations.push(babylonAnimation);
- }
- lastAnimation = babylonAnimation;
- gltfRuntime.scene.stopAnimation(targetNode);
- gltfRuntime.scene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
- }
- }
- };
- /**
- * @returns the bones transformation matrix
- * @param node
- */
- const configureBoneTransformation = (node) => {
- let mat = null;
- if (node.translation || node.rotation || node.scale) {
- const scale = Vector3.FromArray(node.scale || [1, 1, 1]);
- const rotation = Quaternion.FromArray(node.rotation || [0, 0, 0, 1]);
- const position = Vector3.FromArray(node.translation || [0, 0, 0]);
- mat = Matrix.Compose(scale, rotation, position);
- }
- else {
- mat = Matrix.FromArray(node.matrix);
- }
- return mat;
- };
- /**
- * Returns the parent bone
- * @param gltfRuntime
- * @param skins
- * @param jointName
- * @param newSkeleton
- * @returns the parent bone
- */
- const getParentBone = (gltfRuntime, skins, jointName, newSkeleton) => {
- // Try to find
- for (let i = 0; i < newSkeleton.bones.length; i++) {
- if (newSkeleton.bones[i].name === jointName) {
- return newSkeleton.bones[i];
- }
- }
- // Not found, search in gltf nodes
- const nodes = gltfRuntime.nodes;
- for (const nde in nodes) {
- const node = nodes[nde];
- if (!node.jointName) {
- continue;
- }
- const children = node.children;
- for (let i = 0; i < children.length; i++) {
- const child = gltfRuntime.nodes[children[i]];
- if (!child.jointName) {
- continue;
- }
- if (child.jointName === jointName) {
- const mat = configureBoneTransformation(node);
- const bone = new Bone(node.name || "", newSkeleton, getParentBone(gltfRuntime, skins, node.jointName, newSkeleton), mat);
- bone.id = nde;
- return bone;
- }
- }
- }
- return null;
- };
- /**
- * Returns the appropriate root node
- * @param nodesToRoot
- * @param id
- * @returns the root node
- */
- const getNodeToRoot = (nodesToRoot, id) => {
- for (let i = 0; i < nodesToRoot.length; i++) {
- const nodeToRoot = nodesToRoot[i];
- for (let j = 0; j < nodeToRoot.node.children.length; j++) {
- const child = nodeToRoot.node.children[j];
- if (child === id) {
- return nodeToRoot.bone;
- }
- }
- }
- return null;
- };
- /**
- * Returns the node with the joint name
- * @param gltfRuntime
- * @param jointName
- * @returns the node with the joint name
- */
- const getJointNode = (gltfRuntime, jointName) => {
- const nodes = gltfRuntime.nodes;
- let node = nodes[jointName];
- if (node) {
- return {
- node: node,
- id: jointName,
- };
- }
- for (const nde in nodes) {
- node = nodes[nde];
- if (node.jointName === jointName) {
- return {
- node: node,
- id: nde,
- };
- }
- }
- return null;
- };
- /**
- * Checks if a nodes is in joints
- * @param skins
- * @param id
- * @returns true if the node is in joints, else false
- */
- const nodeIsInJoints = (skins, id) => {
- for (let i = 0; i < skins.jointNames.length; i++) {
- if (skins.jointNames[i] === id) {
- return true;
- }
- }
- return false;
- };
- /**
- * Fills the nodes to root for bones and builds hierarchy
- * @param gltfRuntime
- * @param newSkeleton
- * @param skins
- * @param nodesToRoot
- */
- const getNodesToRoot = (gltfRuntime, newSkeleton, skins, nodesToRoot) => {
- // Creates nodes for root
- for (const nde in gltfRuntime.nodes) {
- const node = gltfRuntime.nodes[nde];
- const id = nde;
- if (!node.jointName || nodeIsInJoints(skins, node.jointName)) {
- continue;
- }
- // Create node to root bone
- const mat = configureBoneTransformation(node);
- const bone = new Bone(node.name || "", newSkeleton, null, mat);
- bone.id = id;
- nodesToRoot.push({ bone: bone, node: node, id: id });
- }
- // Parenting
- for (let i = 0; i < nodesToRoot.length; i++) {
- const nodeToRoot = nodesToRoot[i];
- const children = nodeToRoot.node.children;
- for (let j = 0; j < children.length; j++) {
- let child = null;
- for (let k = 0; k < nodesToRoot.length; k++) {
- if (nodesToRoot[k].id === children[j]) {
- child = nodesToRoot[k];
- break;
- }
- }
- if (child) {
- child.bone._parent = nodeToRoot.bone;
- nodeToRoot.bone.children.push(child.bone);
- }
- }
- }
- };
- /**
- * Imports a skeleton
- * @param gltfRuntime
- * @param skins
- * @param mesh
- * @param newSkeleton
- * @returns the bone name
- */
- const importSkeleton = (gltfRuntime, skins, mesh, newSkeleton) => {
- if (!newSkeleton) {
- newSkeleton = new Skeleton(skins.name || "", "", gltfRuntime.scene);
- }
- if (!skins.babylonSkeleton) {
- return newSkeleton;
- }
- // Find the root bones
- const nodesToRoot = [];
- const nodesToRootToAdd = [];
- getNodesToRoot(gltfRuntime, newSkeleton, skins, nodesToRoot);
- newSkeleton.bones = [];
- // Joints
- for (let i = 0; i < skins.jointNames.length; i++) {
- const jointNode = getJointNode(gltfRuntime, skins.jointNames[i]);
- if (!jointNode) {
- continue;
- }
- const node = jointNode.node;
- if (!node) {
- Tools.Warn("Joint named " + skins.jointNames[i] + " does not exist");
- continue;
- }
- const id = jointNode.id;
- // Optimize, if the bone already exists...
- const existingBone = gltfRuntime.scene.getBoneById(id);
- if (existingBone) {
- newSkeleton.bones.push(existingBone);
- continue;
- }
- // Search for parent bone
- let foundBone = false;
- let parentBone = null;
- for (let j = 0; j < i; j++) {
- const jointNode = getJointNode(gltfRuntime, skins.jointNames[j]);
- if (!jointNode) {
- continue;
- }
- const joint = jointNode.node;
- if (!joint) {
- Tools.Warn("Joint named " + skins.jointNames[j] + " does not exist when looking for parent");
- continue;
- }
- const children = joint.children;
- if (!children) {
- continue;
- }
- foundBone = false;
- for (let k = 0; k < children.length; k++) {
- if (children[k] === id) {
- parentBone = getParentBone(gltfRuntime, skins, skins.jointNames[j], newSkeleton);
- foundBone = true;
- break;
- }
- }
- if (foundBone) {
- break;
- }
- }
- // Create bone
- const mat = configureBoneTransformation(node);
- if (!parentBone && nodesToRoot.length > 0) {
- parentBone = getNodeToRoot(nodesToRoot, id);
- if (parentBone) {
- if (nodesToRootToAdd.indexOf(parentBone) === -1) {
- nodesToRootToAdd.push(parentBone);
- }
- }
- }
- const bone = new Bone(node.jointName || "", newSkeleton, parentBone, mat);
- bone.id = id;
- }
- // Polish
- const bones = newSkeleton.bones;
- newSkeleton.bones = [];
- for (let i = 0; i < skins.jointNames.length; i++) {
- const jointNode = getJointNode(gltfRuntime, skins.jointNames[i]);
- if (!jointNode) {
- continue;
- }
- for (let j = 0; j < bones.length; j++) {
- if (bones[j].id === jointNode.id) {
- newSkeleton.bones.push(bones[j]);
- break;
- }
- }
- }
- newSkeleton.prepare();
- // Finish
- for (let i = 0; i < nodesToRootToAdd.length; i++) {
- newSkeleton.bones.push(nodesToRootToAdd[i]);
- }
- return newSkeleton;
- };
- /**
- * Imports a mesh and its geometries
- * @param gltfRuntime
- * @param node
- * @param meshes
- * @param id
- * @param newMesh
- * @returns the new mesh
- */
- const importMesh = (gltfRuntime, node, meshes, id, newMesh) => {
- if (!newMesh) {
- gltfRuntime.scene._blockEntityCollection = !!gltfRuntime.assetContainer;
- newMesh = new Mesh(node.name || "", gltfRuntime.scene);
- newMesh._parentContainer = gltfRuntime.assetContainer;
- gltfRuntime.scene._blockEntityCollection = false;
- newMesh.id = id;
- }
- if (!node.babylonNode) {
- return newMesh;
- }
- const subMaterials = [];
- let vertexData = null;
- const verticesStarts = [];
- const verticesCounts = [];
- const indexStarts = [];
- const indexCounts = [];
- for (let meshIndex = 0; meshIndex < meshes.length; meshIndex++) {
- const meshId = meshes[meshIndex];
- const mesh = gltfRuntime.meshes[meshId];
- if (!mesh) {
- continue;
- }
- // Positions, normals and UVs
- for (let i = 0; i < mesh.primitives.length; i++) {
- // Temporary vertex data
- const tempVertexData = new VertexData();
- const primitive = mesh.primitives[i];
- if (primitive.mode !== 4) {
- // continue;
- }
- const attributes = primitive.attributes;
- let accessor = null;
- let buffer = null;
- // Set positions, normal and uvs
- for (const semantic in attributes) {
- // Link accessor and buffer view
- accessor = gltfRuntime.accessors[attributes[semantic]];
- buffer = GLTFUtils.GetBufferFromAccessor(gltfRuntime, accessor);
- if (semantic === "NORMAL") {
- tempVertexData.normals = new Float32Array(buffer.length);
- tempVertexData.normals.set(buffer);
- }
- else if (semantic === "POSITION") {
- if (GLTFFileLoader.HomogeneousCoordinates) {
- tempVertexData.positions = new Float32Array(buffer.length - buffer.length / 4);
- for (let j = 0; j < buffer.length; j += 4) {
- tempVertexData.positions[j] = buffer[j];
- tempVertexData.positions[j + 1] = buffer[j + 1];
- tempVertexData.positions[j + 2] = buffer[j + 2];
- }
- }
- else {
- tempVertexData.positions = new Float32Array(buffer.length);
- tempVertexData.positions.set(buffer);
- }
- verticesCounts.push(tempVertexData.positions.length);
- }
- else if (semantic.indexOf("TEXCOORD_") !== -1) {
- const channel = Number(semantic.split("_")[1]);
- const uvKind = VertexBuffer.UVKind + (channel === 0 ? "" : channel + 1);
- const uvs = new Float32Array(buffer.length);
- uvs.set(buffer);
- normalizeUVs(uvs);
- tempVertexData.set(uvs, uvKind);
- }
- else if (semantic === "JOINT") {
- tempVertexData.matricesIndices = new Float32Array(buffer.length);
- tempVertexData.matricesIndices.set(buffer);
- }
- else if (semantic === "WEIGHT") {
- tempVertexData.matricesWeights = new Float32Array(buffer.length);
- tempVertexData.matricesWeights.set(buffer);
- }
- else if (semantic === "COLOR") {
- tempVertexData.colors = new Float32Array(buffer.length);
- tempVertexData.colors.set(buffer);
- }
- }
- // Indices
- accessor = gltfRuntime.accessors[primitive.indices];
- if (accessor) {
- buffer = GLTFUtils.GetBufferFromAccessor(gltfRuntime, accessor);
- tempVertexData.indices = new Int32Array(buffer.length);
- tempVertexData.indices.set(buffer);
- indexCounts.push(tempVertexData.indices.length);
- }
- else {
- // Set indices on the fly
- const indices = [];
- for (let j = 0; j < tempVertexData.positions.length / 3; j++) {
- indices.push(j);
- }
- tempVertexData.indices = new Int32Array(indices);
- indexCounts.push(tempVertexData.indices.length);
- }
- if (!vertexData) {
- vertexData = tempVertexData;
- }
- else {
- vertexData.merge(tempVertexData);
- }
- // Sub material
- const material = gltfRuntime.scene.getMaterialById(primitive.material);
- subMaterials.push(material === null ? GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
- // Update vertices start and index start
- verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
- indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
- }
- }
- let material;
- gltfRuntime.scene._blockEntityCollection = !!gltfRuntime.assetContainer;
- if (subMaterials.length > 1) {
- material = new MultiMaterial("multimat" + id, gltfRuntime.scene);
- material.subMaterials = subMaterials;
- }
- else {
- material = new StandardMaterial("multimat" + id, gltfRuntime.scene);
- }
- if (subMaterials.length === 1) {
- material = subMaterials[0];
- }
- material._parentContainer = gltfRuntime.assetContainer;
- if (!newMesh.material) {
- newMesh.material = material;
- }
- // Apply geometry
- new Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
- newMesh.computeWorldMatrix(true);
- gltfRuntime.scene._blockEntityCollection = false;
- // Apply submeshes
- newMesh.subMeshes = [];
- let index = 0;
- for (let meshIndex = 0; meshIndex < meshes.length; meshIndex++) {
- const meshId = meshes[meshIndex];
- const mesh = gltfRuntime.meshes[meshId];
- if (!mesh) {
- continue;
- }
- for (let i = 0; i < mesh.primitives.length; i++) {
- if (mesh.primitives[i].mode !== 4) {
- //continue;
- }
- SubMesh.AddToMesh(index, verticesStarts[index], verticesCounts[index], indexStarts[index], indexCounts[index], newMesh, newMesh, true);
- index++;
- }
- }
- // Finish
- return newMesh;
- };
- /**
- * Configure node transformation from position, rotation and scaling
- * @param newNode
- * @param position
- * @param rotation
- * @param scaling
- */
- const configureNode = (newNode, position, rotation, scaling) => {
- if (newNode.position) {
- newNode.position = position;
- }
- if (newNode.rotationQuaternion || newNode.rotation) {
- newNode.rotationQuaternion = rotation;
- }
- if (newNode.scaling) {
- newNode.scaling = scaling;
- }
- };
- /**
- * Configures node from transformation matrix
- * @param newNode
- * @param node
- */
- const configureNodeFromMatrix = (newNode, node) => {
- if (node.matrix) {
- const position = new Vector3(0, 0, 0);
- const rotation = new Quaternion();
- const scaling = new Vector3(0, 0, 0);
- const mat = Matrix.FromArray(node.matrix);
- mat.decompose(scaling, rotation, position);
- configureNode(newNode, position, rotation, scaling);
- }
- else if (node.translation && node.rotation && node.scale) {
- configureNode(newNode, Vector3.FromArray(node.translation), Quaternion.FromArray(node.rotation), Vector3.FromArray(node.scale));
- }
- newNode.computeWorldMatrix(true);
- };
- /**
- * Imports a node
- * @param gltfRuntime
- * @param node
- * @param id
- * @returns the newly imported node
- */
- const importNode = (gltfRuntime, node, id) => {
- let lastNode = null;
- if (gltfRuntime.importOnlyMeshes && (node.skin || node.meshes)) {
- if (gltfRuntime.importMeshesNames && gltfRuntime.importMeshesNames.length > 0 && gltfRuntime.importMeshesNames.indexOf(node.name || "") === -1) {
- return null;
- }
- }
- // Meshes
- if (node.skin) {
- if (node.meshes) {
- const skin = gltfRuntime.skins[node.skin];
- const newMesh = importMesh(gltfRuntime, node, node.meshes, id, node.babylonNode);
- newMesh.skeleton = gltfRuntime.scene.getLastSkeletonById(node.skin);
- if (newMesh.skeleton === null) {
- newMesh.skeleton = importSkeleton(gltfRuntime, skin, newMesh, skin.babylonSkeleton);
- if (!skin.babylonSkeleton) {
- skin.babylonSkeleton = newMesh.skeleton;
- }
- }
- lastNode = newMesh;
- }
- }
- else if (node.meshes) {
- /**
- * Improve meshes property
- */
- const newMesh = importMesh(gltfRuntime, node, node.mesh ? [node.mesh] : node.meshes, id, node.babylonNode);
- lastNode = newMesh;
- }
- // Lights
- else if (node.light && !node.babylonNode && !gltfRuntime.importOnlyMeshes) {
- const light = gltfRuntime.lights[node.light];
- if (light) {
- if (light.type === "ambient") {
- const ambienLight = light[light.type];
- const hemiLight = new HemisphericLight(node.light, Vector3.Zero(), gltfRuntime.scene);
- hemiLight.name = node.name || "";
- if (ambienLight.color) {
- hemiLight.diffuse = Color3.FromArray(ambienLight.color);
- }
- lastNode = hemiLight;
- }
- else if (light.type === "directional") {
- const directionalLight = light[light.type];
- const dirLight = new DirectionalLight(node.light, Vector3.Zero(), gltfRuntime.scene);
- dirLight.name = node.name || "";
- if (directionalLight.color) {
- dirLight.diffuse = Color3.FromArray(directionalLight.color);
- }
- lastNode = dirLight;
- }
- else if (light.type === "point") {
- const pointLight = light[light.type];
- const ptLight = new PointLight(node.light, Vector3.Zero(), gltfRuntime.scene);
- ptLight.name = node.name || "";
- if (pointLight.color) {
- ptLight.diffuse = Color3.FromArray(pointLight.color);
- }
- lastNode = ptLight;
- }
- else if (light.type === "spot") {
- const spotLight = light[light.type];
- const spLight = new SpotLight(node.light, Vector3.Zero(), Vector3.Zero(), 0, 0, gltfRuntime.scene);
- spLight.name = node.name || "";
- if (spotLight.color) {
- spLight.diffuse = Color3.FromArray(spotLight.color);
- }
- if (spotLight.fallOfAngle) {
- spLight.angle = spotLight.fallOfAngle;
- }
- if (spotLight.fallOffExponent) {
- spLight.exponent = spotLight.fallOffExponent;
- }
- lastNode = spLight;
- }
- }
- }
- // Cameras
- else if (node.camera && !node.babylonNode && !gltfRuntime.importOnlyMeshes) {
- const camera = gltfRuntime.cameras[node.camera];
- if (camera) {
- gltfRuntime.scene._blockEntityCollection = !!gltfRuntime.assetContainer;
- if (camera.type === "orthographic") {
- const orthoCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene, false);
- orthoCamera.name = node.name || "";
- orthoCamera.mode = Camera.ORTHOGRAPHIC_CAMERA;
- orthoCamera.attachControl();
- lastNode = orthoCamera;
- orthoCamera._parentContainer = gltfRuntime.assetContainer;
- }
- else if (camera.type === "perspective") {
- const perspectiveCamera = camera[camera.type];
- const persCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene, false);
- persCamera.name = node.name || "";
- persCamera.attachControl();
- if (!perspectiveCamera.aspectRatio) {
- perspectiveCamera.aspectRatio = gltfRuntime.scene.getEngine().getRenderWidth() / gltfRuntime.scene.getEngine().getRenderHeight();
- }
- if (perspectiveCamera.znear && perspectiveCamera.zfar) {
- persCamera.maxZ = perspectiveCamera.zfar;
- persCamera.minZ = perspectiveCamera.znear;
- }
- lastNode = persCamera;
- persCamera._parentContainer = gltfRuntime.assetContainer;
- }
- gltfRuntime.scene._blockEntityCollection = false;
- }
- }
- // Empty node
- if (!node.jointName) {
- if (node.babylonNode) {
- return node.babylonNode;
- }
- else if (lastNode === null) {
- gltfRuntime.scene._blockEntityCollection = !!gltfRuntime.assetContainer;
- const dummy = new Mesh(node.name || "", gltfRuntime.scene);
- dummy._parentContainer = gltfRuntime.assetContainer;
- gltfRuntime.scene._blockEntityCollection = false;
- node.babylonNode = dummy;
- lastNode = dummy;
- }
- }
- if (lastNode !== null) {
- if (node.matrix && lastNode instanceof Mesh) {
- configureNodeFromMatrix(lastNode, node);
- }
- else {
- const translation = node.translation || [0, 0, 0];
- const rotation = node.rotation || [0, 0, 0, 1];
- const scale = node.scale || [1, 1, 1];
- configureNode(lastNode, Vector3.FromArray(translation), Quaternion.FromArray(rotation), Vector3.FromArray(scale));
- }
- lastNode.updateCache(true);
- node.babylonNode = lastNode;
- }
- return lastNode;
- };
- /**
- * Traverses nodes and creates them
- * @param gltfRuntime
- * @param id
- * @param parent
- * @param meshIncluded
- */
- const traverseNodes = (gltfRuntime, id, parent, meshIncluded = false) => {
- const node = gltfRuntime.nodes[id];
- let newNode = null;
- if (gltfRuntime.importOnlyMeshes && !meshIncluded && gltfRuntime.importMeshesNames) {
- if (gltfRuntime.importMeshesNames.indexOf(node.name || "") !== -1 || gltfRuntime.importMeshesNames.length === 0) {
- meshIncluded = true;
- }
- else {
- meshIncluded = false;
- }
- }
- else {
- meshIncluded = true;
- }
- if (!node.jointName && meshIncluded) {
- newNode = importNode(gltfRuntime, node, id);
- if (newNode !== null) {
- newNode.id = id;
- newNode.parent = parent;
- }
- }
- if (node.children) {
- for (let i = 0; i < node.children.length; i++) {
- traverseNodes(gltfRuntime, node.children[i], newNode, meshIncluded);
- }
- }
- };
- /**
- * do stuff after buffers, shaders are loaded (e.g. hook up materials, load animations, etc.)
- * @param gltfRuntime
- */
- const postLoad = (gltfRuntime) => {
- // Nodes
- let currentScene = gltfRuntime.currentScene;
- if (currentScene) {
- for (let i = 0; i < currentScene.nodes.length; i++) {
- traverseNodes(gltfRuntime, currentScene.nodes[i], null);
- }
- }
- else {
- for (const thing in gltfRuntime.scenes) {
- currentScene = gltfRuntime.scenes[thing];
- for (let i = 0; i < currentScene.nodes.length; i++) {
- traverseNodes(gltfRuntime, currentScene.nodes[i], null);
- }
- }
- }
- // Set animations
- loadAnimations(gltfRuntime);
- for (let i = 0; i < gltfRuntime.scene.skeletons.length; i++) {
- const skeleton = gltfRuntime.scene.skeletons[i];
- gltfRuntime.scene.beginAnimation(skeleton, 0, Number.MAX_VALUE, true, 1.0);
- }
- };
- /**
- * onBind shaderrs callback to set uniforms and matrices
- * @param mesh
- * @param gltfRuntime
- * @param unTreatedUniforms
- * @param shaderMaterial
- * @param technique
- * @param material
- * @param onSuccess
- */
- const onBindShaderMaterial = (mesh, gltfRuntime, unTreatedUniforms, shaderMaterial, technique, material, onSuccess) => {
- const materialValues = material.values || technique.parameters;
- for (const unif in unTreatedUniforms) {
- const uniform = unTreatedUniforms[unif];
- const type = uniform.type;
- if (type === EParameterType.FLOAT_MAT2 || type === EParameterType.FLOAT_MAT3 || type === EParameterType.FLOAT_MAT4) {
- if (uniform.semantic && !uniform.source && !uniform.node) {
- GLTFUtils.SetMatrix(gltfRuntime.scene, mesh, uniform, unif, shaderMaterial.getEffect());
- }
- else if (uniform.semantic && (uniform.source || uniform.node)) {
- let source = gltfRuntime.scene.getNodeByName(uniform.source || uniform.node || "");
- if (source === null) {
- source = gltfRuntime.scene.getNodeById(uniform.source || uniform.node || "");
- }
- if (source === null) {
- continue;
- }
- GLTFUtils.SetMatrix(gltfRuntime.scene, source, uniform, unif, shaderMaterial.getEffect());
- }
- }
- else {
- const value = materialValues[technique.uniforms[unif]];
- if (!value) {
- continue;
- }
- if (type === EParameterType.SAMPLER_2D) {
- const texture = gltfRuntime.textures[material.values ? value : uniform.value].babylonTexture;
- if (texture === null || texture === undefined) {
- continue;
- }
- shaderMaterial.getEffect().setTexture(unif, texture);
- }
- else {
- GLTFUtils.SetUniform(shaderMaterial.getEffect(), unif, value, type);
- }
- }
- }
- onSuccess(shaderMaterial);
- };
- /**
- * Prepare uniforms to send the only one time
- * Loads the appropriate textures
- * @param gltfRuntime
- * @param shaderMaterial
- * @param technique
- * @param material
- */
- const prepareShaderMaterialUniforms = (gltfRuntime, shaderMaterial, technique, material, unTreatedUniforms) => {
- const materialValues = material.values || technique.parameters;
- const techniqueUniforms = technique.uniforms;
- /**
- * Prepare values here (not matrices)
- */
- for (const unif in unTreatedUniforms) {
- const uniform = unTreatedUniforms[unif];
- const type = uniform.type;
- let value = materialValues[techniqueUniforms[unif]];
- if (value === undefined) {
- // In case the value is the same for all materials
- value = uniform.value;
- }
- if (!value) {
- continue;
- }
- const onLoadTexture = (uniformName) => {
- return (texture) => {
- if (uniform.value && uniformName) {
- // Static uniform
- shaderMaterial.setTexture(uniformName, texture);
- delete unTreatedUniforms[uniformName];
- }
- };
- };
- // Texture (sampler2D)
- if (type === EParameterType.SAMPLER_2D) {
- GLTFLoaderExtension.LoadTextureAsync(gltfRuntime, material.values ? value : uniform.value, onLoadTexture(unif), () => onLoadTexture(null));
- }
- // Others
- else {
- if (uniform.value && GLTFUtils.SetUniform(shaderMaterial, unif, material.values ? value : uniform.value, type)) {
- // Static uniform
- delete unTreatedUniforms[unif];
- }
- }
- }
- };
- /**
- * Shader compilation failed
- * @param program
- * @param shaderMaterial
- * @param onError
- * @returns callback when shader is compiled
- */
- const onShaderCompileError = (program, shaderMaterial, onError) => {
- return (effect, error) => {
- shaderMaterial.dispose(true);
- onError("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
- };
- };
- /**
- * Shader compilation success
- * @param gltfRuntime
- * @param shaderMaterial
- * @param technique
- * @param material
- * @param unTreatedUniforms
- * @param onSuccess
- * @returns callback when shader is compiled
- */
- const onShaderCompileSuccess = (gltfRuntime, shaderMaterial, technique, material, unTreatedUniforms, onSuccess) => {
- return (_) => {
- prepareShaderMaterialUniforms(gltfRuntime, shaderMaterial, technique, material, unTreatedUniforms);
- shaderMaterial.onBind = (mesh) => {
- onBindShaderMaterial(mesh, gltfRuntime, unTreatedUniforms, shaderMaterial, technique, material, onSuccess);
- };
- };
- };
- /**
- * Returns the appropriate uniform if already handled by babylon
- * @param tokenizer
- * @param technique
- * @param unTreatedUniforms
- * @returns the name of the uniform handled by babylon
- */
- const parseShaderUniforms = (tokenizer, technique, unTreatedUniforms) => {
- for (const unif in technique.uniforms) {
- const uniform = technique.uniforms[unif];
- const uniformParameter = technique.parameters[uniform];
- if (tokenizer.currentIdentifier === unif) {
- if (uniformParameter.semantic && !uniformParameter.source && !uniformParameter.node) {
- const transformIndex = glTFTransforms.indexOf(uniformParameter.semantic);
- if (transformIndex !== -1) {
- delete unTreatedUniforms[unif];
- return babylonTransforms[transformIndex];
- }
- }
- }
- }
- return tokenizer.currentIdentifier;
- };
- /**
- * All shaders loaded. Create materials one by one
- * @param gltfRuntime
- */
- const importMaterials = (gltfRuntime) => {
- // Create materials
- for (const mat in gltfRuntime.materials) {
- GLTFLoaderExtension.LoadMaterialAsync(gltfRuntime, mat, () => { }, () => { });
- }
- };
- /**
- * Implementation of the base glTF spec
- * @internal
- */
- export class GLTFLoaderBase {
- static CreateRuntime(parsedData, scene, rootUrl) {
- const gltfRuntime = {
- extensions: {},
- accessors: {},
- buffers: {},
- bufferViews: {},
- meshes: {},
- lights: {},
- cameras: {},
- nodes: {},
- images: {},
- textures: {},
- shaders: {},
- programs: {},
- samplers: {},
- techniques: {},
- materials: {},
- animations: {},
- skins: {},
- extensionsUsed: [],
- scenes: {},
- buffersCount: 0,
- shaderscount: 0,
- scene: scene,
- rootUrl: rootUrl,
- loadedBufferCount: 0,
- loadedBufferViews: {},
- loadedShaderCount: 0,
- importOnlyMeshes: false,
- dummyNodes: [],
- assetContainer: null,
- };
- // Parse
- if (parsedData.extensions) {
- parseObject(parsedData.extensions, "extensions", gltfRuntime);
- }
- if (parsedData.extensionsUsed) {
- parseObject(parsedData.extensionsUsed, "extensionsUsed", gltfRuntime);
- }
- if (parsedData.buffers) {
- parseBuffers(parsedData.buffers, gltfRuntime);
- }
- if (parsedData.bufferViews) {
- parseObject(parsedData.bufferViews, "bufferViews", gltfRuntime);
- }
- if (parsedData.accessors) {
- parseObject(parsedData.accessors, "accessors", gltfRuntime);
- }
- if (parsedData.meshes) {
- parseObject(parsedData.meshes, "meshes", gltfRuntime);
- }
- if (parsedData.lights) {
- parseObject(parsedData.lights, "lights", gltfRuntime);
- }
- if (parsedData.cameras) {
- parseObject(parsedData.cameras, "cameras", gltfRuntime);
- }
- if (parsedData.nodes) {
- parseObject(parsedData.nodes, "nodes", gltfRuntime);
- }
- if (parsedData.images) {
- parseObject(parsedData.images, "images", gltfRuntime);
- }
- if (parsedData.textures) {
- parseObject(parsedData.textures, "textures", gltfRuntime);
- }
- if (parsedData.shaders) {
- parseShaders(parsedData.shaders, gltfRuntime);
- }
- if (parsedData.programs) {
- parseObject(parsedData.programs, "programs", gltfRuntime);
- }
- if (parsedData.samplers) {
- parseObject(parsedData.samplers, "samplers", gltfRuntime);
- }
- if (parsedData.techniques) {
- parseObject(parsedData.techniques, "techniques", gltfRuntime);
- }
- if (parsedData.materials) {
- parseObject(parsedData.materials, "materials", gltfRuntime);
- }
- if (parsedData.animations) {
- parseObject(parsedData.animations, "animations", gltfRuntime);
- }
- if (parsedData.skins) {
- parseObject(parsedData.skins, "skins", gltfRuntime);
- }
- if (parsedData.scenes) {
- gltfRuntime.scenes = parsedData.scenes;
- }
- if (parsedData.scene && parsedData.scenes) {
- gltfRuntime.currentScene = parsedData.scenes[parsedData.scene];
- }
- return gltfRuntime;
- }
- static LoadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress) {
- const buffer = gltfRuntime.buffers[id];
- if (Tools.IsBase64(buffer.uri)) {
- setTimeout(() => onSuccess(new Uint8Array(Tools.DecodeBase64(buffer.uri))));
- }
- else {
- Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, (data) => onSuccess(new Uint8Array(data)), onProgress, undefined, true, (request) => {
- if (request) {
- onError(request.status + " " + request.statusText);
- }
- });
- }
- }
- static LoadTextureBufferAsync(gltfRuntime, id, onSuccess, onError) {
- const texture = gltfRuntime.textures[id];
- if (!texture || !texture.source) {
- onError("");
- return;
- }
- if (texture.babylonTexture) {
- onSuccess(null);
- return;
- }
- const source = gltfRuntime.images[texture.source];
- if (Tools.IsBase64(source.uri)) {
- setTimeout(() => onSuccess(new Uint8Array(Tools.DecodeBase64(source.uri))));
- }
- else {
- Tools.LoadFile(gltfRuntime.rootUrl + source.uri, (data) => onSuccess(new Uint8Array(data)), undefined, undefined, true, (request) => {
- if (request) {
- onError(request.status + " " + request.statusText);
- }
- });
- }
- }
- static CreateTextureAsync(gltfRuntime, id, buffer, onSuccess) {
- const texture = gltfRuntime.textures[id];
- if (texture.babylonTexture) {
- onSuccess(texture.babylonTexture);
- return;
- }
- const sampler = gltfRuntime.samplers[texture.sampler];
- const createMipMaps = sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_NEAREST ||
- sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_LINEAR ||
- sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_NEAREST ||
- sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_LINEAR;
- const samplingMode = Texture.BILINEAR_SAMPLINGMODE;
- const blob = buffer == null ? new Blob() : new Blob([buffer]);
- const blobURL = URL.createObjectURL(blob);
- const revokeBlobURL = () => URL.revokeObjectURL(blobURL);
- const newTexture = new Texture(blobURL, gltfRuntime.scene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
- if (sampler.wrapS !== undefined) {
- newTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
- }
- if (sampler.wrapT !== undefined) {
- newTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
- }
- newTexture.name = id;
- texture.babylonTexture = newTexture;
- onSuccess(newTexture);
- }
- static LoadShaderStringAsync(gltfRuntime, id, onSuccess, onError) {
- const shader = gltfRuntime.shaders[id];
- if (Tools.IsBase64(shader.uri)) {
- const shaderString = atob(shader.uri.split(",")[1]);
- if (onSuccess) {
- onSuccess(shaderString);
- }
- }
- else {
- Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, undefined, undefined, false, (request) => {
- if (request && onError) {
- onError(request.status + " " + request.statusText);
- }
- });
- }
- }
- static LoadMaterialAsync(gltfRuntime, id, onSuccess, onError) {
- const material = gltfRuntime.materials[id];
- if (!material.technique) {
- if (onError) {
- onError("No technique found.");
- }
- return;
- }
- const technique = gltfRuntime.techniques[material.technique];
- if (!technique) {
- gltfRuntime.scene._blockEntityCollection = !!gltfRuntime.assetContainer;
- const defaultMaterial = new StandardMaterial(id, gltfRuntime.scene);
- defaultMaterial._parentContainer = gltfRuntime.assetContainer;
- gltfRuntime.scene._blockEntityCollection = false;
- defaultMaterial.diffuseColor = new Color3(0.5, 0.5, 0.5);
- defaultMaterial.sideOrientation = Material.CounterClockWiseSideOrientation;
- onSuccess(defaultMaterial);
- return;
- }
- const program = gltfRuntime.programs[technique.program];
- const states = technique.states;
- const vertexShader = Effect.ShadersStore[program.vertexShader + "VertexShader"];
- const pixelShader = Effect.ShadersStore[program.fragmentShader + "PixelShader"];
- let newVertexShader = "";
- let newPixelShader = "";
- const vertexTokenizer = new Tokenizer(vertexShader);
- const pixelTokenizer = new Tokenizer(pixelShader);
- const unTreatedUniforms = {};
- const uniforms = [];
- const attributes = [];
- const samplers = [];
- // Fill uniform, sampler2D and attributes
- for (const unif in technique.uniforms) {
- const uniform = technique.uniforms[unif];
- const uniformParameter = technique.parameters[uniform];
- unTreatedUniforms[unif] = uniformParameter;
- if (uniformParameter.semantic && !uniformParameter.node && !uniformParameter.source) {
- const transformIndex = glTFTransforms.indexOf(uniformParameter.semantic);
- if (transformIndex !== -1) {
- uniforms.push(babylonTransforms[transformIndex]);
- delete unTreatedUniforms[unif];
- }
- else {
- uniforms.push(unif);
- }
- }
- else if (uniformParameter.type === EParameterType.SAMPLER_2D) {
- samplers.push(unif);
- }
- else {
- uniforms.push(unif);
- }
- }
- for (const attr in technique.attributes) {
- const attribute = technique.attributes[attr];
- const attributeParameter = technique.parameters[attribute];
- if (attributeParameter.semantic) {
- const name = getAttribute(attributeParameter);
- if (name) {
- attributes.push(name);
- }
- }
- }
- // Configure vertex shader
- while (!vertexTokenizer.isEnd() && vertexTokenizer.getNextToken()) {
- const tokenType = vertexTokenizer.currentToken;
- if (tokenType !== ETokenType.IDENTIFIER) {
- newVertexShader += vertexTokenizer.currentString;
- continue;
- }
- let foundAttribute = false;
- for (const attr in technique.attributes) {
- const attribute = technique.attributes[attr];
- const attributeParameter = technique.parameters[attribute];
- if (vertexTokenizer.currentIdentifier === attr && attributeParameter.semantic) {
- newVertexShader += getAttribute(attributeParameter);
- foundAttribute = true;
- break;
- }
- }
- if (foundAttribute) {
- continue;
- }
- newVertexShader += parseShaderUniforms(vertexTokenizer, technique, unTreatedUniforms);
- }
- // Configure pixel shader
- while (!pixelTokenizer.isEnd() && pixelTokenizer.getNextToken()) {
- const tokenType = pixelTokenizer.currentToken;
- if (tokenType !== ETokenType.IDENTIFIER) {
- newPixelShader += pixelTokenizer.currentString;
- continue;
- }
- newPixelShader += parseShaderUniforms(pixelTokenizer, technique, unTreatedUniforms);
- }
- // Create shader material
- const shaderPath = {
- vertex: program.vertexShader + id,
- fragment: program.fragmentShader + id,
- };
- const options = {
- attributes: attributes,
- uniforms: uniforms,
- samplers: samplers,
- needAlphaBlending: states && states.enable && states.enable.indexOf(3042) !== -1,
- };
- Effect.ShadersStore[program.vertexShader + id + "VertexShader"] = newVertexShader;
- Effect.ShadersStore[program.fragmentShader + id + "PixelShader"] = newPixelShader;
- const shaderMaterial = new ShaderMaterial(id, gltfRuntime.scene, shaderPath, options);
- shaderMaterial.onError = onShaderCompileError(program, shaderMaterial, onError);
- shaderMaterial.onCompiled = onShaderCompileSuccess(gltfRuntime, shaderMaterial, technique, material, unTreatedUniforms, onSuccess);
- shaderMaterial.sideOrientation = Material.CounterClockWiseSideOrientation;
- if (states && states.functions) {
- const functions = states.functions;
- if (functions.cullFace && functions.cullFace[0] !== ECullingType.BACK) {
- shaderMaterial.backFaceCulling = false;
- }
- const blendFunc = functions.blendFuncSeparate;
- if (blendFunc) {
- if (blendFunc[0] === EBlendingFunction.SRC_ALPHA &&
- blendFunc[1] === EBlendingFunction.ONE_MINUS_SRC_ALPHA &&
- blendFunc[2] === EBlendingFunction.ONE &&
- blendFunc[3] === EBlendingFunction.ONE) {
- shaderMaterial.alphaMode = Constants.ALPHA_COMBINE;
- }
- else if (blendFunc[0] === EBlendingFunction.ONE &&
- blendFunc[1] === EBlendingFunction.ONE &&
- blendFunc[2] === EBlendingFunction.ZERO &&
- blendFunc[3] === EBlendingFunction.ONE) {
- shaderMaterial.alphaMode = Constants.ALPHA_ONEONE;
- }
- else if (blendFunc[0] === EBlendingFunction.SRC_ALPHA &&
- blendFunc[1] === EBlendingFunction.ONE &&
- blendFunc[2] === EBlendingFunction.ZERO &&
- blendFunc[3] === EBlendingFunction.ONE) {
- shaderMaterial.alphaMode = Constants.ALPHA_ADD;
- }
- else if (blendFunc[0] === EBlendingFunction.ZERO &&
- blendFunc[1] === EBlendingFunction.ONE_MINUS_SRC_COLOR &&
- blendFunc[2] === EBlendingFunction.ONE &&
- blendFunc[3] === EBlendingFunction.ONE) {
- shaderMaterial.alphaMode = Constants.ALPHA_SUBTRACT;
- }
- else if (blendFunc[0] === EBlendingFunction.DST_COLOR &&
- blendFunc[1] === EBlendingFunction.ZERO &&
- blendFunc[2] === EBlendingFunction.ONE &&
- blendFunc[3] === EBlendingFunction.ONE) {
- shaderMaterial.alphaMode = Constants.ALPHA_MULTIPLY;
- }
- else if (blendFunc[0] === EBlendingFunction.SRC_ALPHA &&
- blendFunc[1] === EBlendingFunction.ONE_MINUS_SRC_COLOR &&
- blendFunc[2] === EBlendingFunction.ONE &&
- blendFunc[3] === EBlendingFunction.ONE) {
- shaderMaterial.alphaMode = Constants.ALPHA_MAXIMIZED;
- }
- }
- }
- }
- }
- /**
- * glTF V1 Loader
- * @internal
- * @deprecated
- */
- export class GLTFLoader {
- static RegisterExtension(extension) {
- if (GLTFLoader.Extensions[extension.name]) {
- Tools.Error('Tool with the same name "' + extension.name + '" already exists');
- return;
- }
- GLTFLoader.Extensions[extension.name] = extension;
- }
- dispose() {
- // do nothing
- }
- _importMeshAsync(meshesNames, scene, data, rootUrl, assetContainer, onSuccess, onProgress, onError) {
- scene.useRightHandedSystem = true;
- GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, (gltfRuntime) => {
- gltfRuntime.assetContainer = assetContainer;
- gltfRuntime.importOnlyMeshes = true;
- if (meshesNames === "") {
- gltfRuntime.importMeshesNames = [];
- }
- else if (typeof meshesNames === "string") {
- gltfRuntime.importMeshesNames = [meshesNames];
- }
- else if (meshesNames && !(meshesNames instanceof Array)) {
- gltfRuntime.importMeshesNames = [meshesNames];
- }
- else {
- gltfRuntime.importMeshesNames = [];
- Tools.Warn("Argument meshesNames must be of type string or string[]");
- }
- // Create nodes
- this._createNodes(gltfRuntime);
- const meshes = [];
- const skeletons = [];
- // Fill arrays of meshes and skeletons
- for (const nde in gltfRuntime.nodes) {
- const node = gltfRuntime.nodes[nde];
- if (node.babylonNode instanceof AbstractMesh) {
- meshes.push(node.babylonNode);
- }
- }
- for (const skl in gltfRuntime.skins) {
- const skin = gltfRuntime.skins[skl];
- if (skin.babylonSkeleton instanceof Skeleton) {
- skeletons.push(skin.babylonSkeleton);
- }
- }
- // Load buffers, shaders, materials, etc.
- this._loadBuffersAsync(gltfRuntime, () => {
- this._loadShadersAsync(gltfRuntime, () => {
- importMaterials(gltfRuntime);
- postLoad(gltfRuntime);
- if (!GLTFFileLoader.IncrementalLoading && onSuccess) {
- onSuccess(meshes, skeletons);
- }
- });
- });
- if (GLTFFileLoader.IncrementalLoading && onSuccess) {
- onSuccess(meshes, skeletons);
- }
- }, onError);
- return true;
- }
- /**
- * Imports one or more meshes from a loaded gltf file and adds them to the scene
- * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
- * @param scene the scene the meshes should be added to
- * @param assetContainer defines the asset container to use (can be null)
- * @param data gltf data containing information of the meshes in a loaded file
- * @param rootUrl root url to load from
- * @param onProgress event that fires when loading progress has occured
- * @returns a promise containg the loaded meshes, particles, skeletons and animations
- */
- importMeshAsync(meshesNames, scene, assetContainer, data, rootUrl, onProgress) {
- return new Promise((resolve, reject) => {
- this._importMeshAsync(meshesNames, scene, data, rootUrl, assetContainer, (meshes, skeletons) => {
- resolve({
- meshes: meshes,
- particleSystems: [],
- skeletons: skeletons,
- animationGroups: [],
- lights: [],
- transformNodes: [],
- geometries: [],
- spriteManagers: [],
- });
- }, onProgress, (message) => {
- reject(new Error(message));
- });
- });
- }
- _loadAsync(scene, data, rootUrl, onSuccess, onProgress, onError) {
- scene.useRightHandedSystem = true;
- GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, (gltfRuntime) => {
- // Load runtime extensios
- GLTFLoaderExtension.LoadRuntimeExtensionsAsync(gltfRuntime, () => {
- // Create nodes
- this._createNodes(gltfRuntime);
- // Load buffers, shaders, materials, etc.
- this._loadBuffersAsync(gltfRuntime, () => {
- this._loadShadersAsync(gltfRuntime, () => {
- importMaterials(gltfRuntime);
- postLoad(gltfRuntime);
- if (!GLTFFileLoader.IncrementalLoading) {
- onSuccess();
- }
- });
- });
- if (GLTFFileLoader.IncrementalLoading) {
- onSuccess();
- }
- }, onError);
- }, onError);
- }
- /**
- * Imports all objects from a loaded gltf file and adds them to the scene
- * @param scene the scene the objects should be added to
- * @param data gltf data containing information of the meshes in a loaded file
- * @param rootUrl root url to load from
- * @param onProgress event that fires when loading progress has occured
- * @returns a promise which completes when objects have been loaded to the scene
- */
- loadAsync(scene, data, rootUrl, onProgress) {
- return new Promise((resolve, reject) => {
- this._loadAsync(scene, data, rootUrl, () => {
- resolve();
- }, onProgress, (message) => {
- reject(new Error(message));
- });
- });
- }
- _loadShadersAsync(gltfRuntime, onload) {
- let hasShaders = false;
- const processShader = (sha, shader) => {
- GLTFLoaderExtension.LoadShaderStringAsync(gltfRuntime, sha, (shaderString) => {
- if (shaderString instanceof ArrayBuffer) {
- return;
- }
- gltfRuntime.loadedShaderCount++;
- if (shaderString) {
- Effect.ShadersStore[sha + (shader.type === EShaderType.VERTEX ? "VertexShader" : "PixelShader")] = shaderString;
- }
- if (gltfRuntime.loadedShaderCount === gltfRuntime.shaderscount) {
- onload();
- }
- }, () => {
- Tools.Error("Error when loading shader program named " + sha + " located at " + shader.uri);
- });
- };
- for (const sha in gltfRuntime.shaders) {
- hasShaders = true;
- const shader = gltfRuntime.shaders[sha];
- if (shader) {
- processShader.bind(this, sha, shader)();
- }
- else {
- Tools.Error("No shader named: " + sha);
- }
- }
- if (!hasShaders) {
- onload();
- }
- }
- _loadBuffersAsync(gltfRuntime, onLoad) {
- let hasBuffers = false;
- const processBuffer = (buf, buffer) => {
- GLTFLoaderExtension.LoadBufferAsync(gltfRuntime, buf, (bufferView) => {
- gltfRuntime.loadedBufferCount++;
- if (bufferView) {
- if (bufferView.byteLength != gltfRuntime.buffers[buf].byteLength) {
- Tools.Error("Buffer named " + buf + " is length " + bufferView.byteLength + ". Expected: " + buffer.byteLength); // Improve error message
- }
- gltfRuntime.loadedBufferViews[buf] = bufferView;
- }
- if (gltfRuntime.loadedBufferCount === gltfRuntime.buffersCount) {
- onLoad();
- }
- }, () => {
- Tools.Error("Error when loading buffer named " + buf + " located at " + buffer.uri);
- });
- };
- for (const buf in gltfRuntime.buffers) {
- hasBuffers = true;
- const buffer = gltfRuntime.buffers[buf];
- if (buffer) {
- processBuffer.bind(this, buf, buffer)();
- }
- else {
- Tools.Error("No buffer named: " + buf);
- }
- }
- if (!hasBuffers) {
- onLoad();
- }
- }
- _createNodes(gltfRuntime) {
- let currentScene = gltfRuntime.currentScene;
- if (currentScene) {
- // Only one scene even if multiple scenes are defined
- for (let i = 0; i < currentScene.nodes.length; i++) {
- traverseNodes(gltfRuntime, currentScene.nodes[i], null);
- }
- }
- else {
- // Load all scenes
- for (const thing in gltfRuntime.scenes) {
- currentScene = gltfRuntime.scenes[thing];
- for (let i = 0; i < currentScene.nodes.length; i++) {
- traverseNodes(gltfRuntime, currentScene.nodes[i], null);
- }
- }
- }
- }
- }
- GLTFLoader.Extensions = {};
- /** @internal */
- export class GLTFLoaderExtension {
- constructor(name) {
- this._name = name;
- }
- get name() {
- return this._name;
- }
- /**
- * Defines an override for loading the runtime
- * Return true to stop further extensions from loading the runtime
- * @param scene
- * @param data
- * @param rootUrl
- * @param onSuccess
- * @param onError
- * @returns true to stop further extensions from loading the runtime
- */
- loadRuntimeAsync(scene, data, rootUrl, onSuccess, onError) {
- return false;
- }
- /**
- * Defines an onverride for creating gltf runtime
- * Return true to stop further extensions from creating the runtime
- * @param gltfRuntime
- * @param onSuccess
- * @param onError
- * @returns true to stop further extensions from creating the runtime
- */
- loadRuntimeExtensionsAsync(gltfRuntime, onSuccess, onError) {
- return false;
- }
- /**
- * Defines an override for loading buffers
- * Return true to stop further extensions from loading this buffer
- * @param gltfRuntime
- * @param id
- * @param onSuccess
- * @param onError
- * @param onProgress
- * @returns true to stop further extensions from loading this buffer
- */
- loadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress) {
- return false;
- }
- /**
- * Defines an override for loading texture buffers
- * Return true to stop further extensions from loading this texture data
- * @param gltfRuntime
- * @param id
- * @param onSuccess
- * @param onError
- * @returns true to stop further extensions from loading this texture data
- */
- loadTextureBufferAsync(gltfRuntime, id, onSuccess, onError) {
- return false;
- }
- /**
- * Defines an override for creating textures
- * Return true to stop further extensions from loading this texture
- * @param gltfRuntime
- * @param id
- * @param buffer
- * @param onSuccess
- * @param onError
- * @returns true to stop further extensions from loading this texture
- */
- createTextureAsync(gltfRuntime, id, buffer, onSuccess, onError) {
- return false;
- }
- /**
- * Defines an override for loading shader strings
- * Return true to stop further extensions from loading this shader data
- * @param gltfRuntime
- * @param id
- * @param onSuccess
- * @param onError
- * @returns true to stop further extensions from loading this shader data
- */
- loadShaderStringAsync(gltfRuntime, id, onSuccess, onError) {
- return false;
- }
- /**
- * Defines an override for loading materials
- * Return true to stop further extensions from loading this material
- * @param gltfRuntime
- * @param id
- * @param onSuccess
- * @param onError
- * @returns true to stop further extensions from loading this material
- */
- loadMaterialAsync(gltfRuntime, id, onSuccess, onError) {
- return false;
- }
- // ---------
- // Utilities
- // ---------
- static LoadRuntimeAsync(scene, data, rootUrl, onSuccess, onError) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.loadRuntimeAsync(scene, data, rootUrl, onSuccess, onError);
- }, () => {
- setTimeout(() => {
- if (!onSuccess) {
- return;
- }
- onSuccess(GLTFLoaderBase.CreateRuntime(data.json, scene, rootUrl));
- });
- });
- }
- static LoadRuntimeExtensionsAsync(gltfRuntime, onSuccess, onError) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.loadRuntimeExtensionsAsync(gltfRuntime, onSuccess, onError);
- }, () => {
- setTimeout(() => {
- onSuccess();
- });
- });
- }
- static LoadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.loadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress);
- }, () => {
- GLTFLoaderBase.LoadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress);
- });
- }
- static LoadTextureAsync(gltfRuntime, id, onSuccess, onError) {
- GLTFLoaderExtension._LoadTextureBufferAsync(gltfRuntime, id, (buffer) => {
- if (buffer) {
- GLTFLoaderExtension._CreateTextureAsync(gltfRuntime, id, buffer, onSuccess, onError);
- }
- }, onError);
- }
- static LoadShaderStringAsync(gltfRuntime, id, onSuccess, onError) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.loadShaderStringAsync(gltfRuntime, id, onSuccess, onError);
- }, () => {
- GLTFLoaderBase.LoadShaderStringAsync(gltfRuntime, id, onSuccess, onError);
- });
- }
- static LoadMaterialAsync(gltfRuntime, id, onSuccess, onError) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.loadMaterialAsync(gltfRuntime, id, onSuccess, onError);
- }, () => {
- GLTFLoaderBase.LoadMaterialAsync(gltfRuntime, id, onSuccess, onError);
- });
- }
- static _LoadTextureBufferAsync(gltfRuntime, id, onSuccess, onError) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.loadTextureBufferAsync(gltfRuntime, id, onSuccess, onError);
- }, () => {
- GLTFLoaderBase.LoadTextureBufferAsync(gltfRuntime, id, onSuccess, onError);
- });
- }
- static _CreateTextureAsync(gltfRuntime, id, buffer, onSuccess, onError) {
- GLTFLoaderExtension._ApplyExtensions((loaderExtension) => {
- return loaderExtension.createTextureAsync(gltfRuntime, id, buffer, onSuccess, onError);
- }, () => {
- GLTFLoaderBase.CreateTextureAsync(gltfRuntime, id, buffer, onSuccess);
- });
- }
- static _ApplyExtensions(func, defaultFunc) {
- for (const extensionName in GLTFLoader.Extensions) {
- const loaderExtension = GLTFLoader.Extensions[extensionName];
- if (func(loaderExtension)) {
- return;
- }
- }
- defaultFunc();
- }
- }
- GLTFFileLoader._CreateGLTF1Loader = () => new GLTFLoader();
- //# sourceMappingURL=glTFLoader.js.map
|