12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556 |
- /**
- * @author Tony Parisi / http://www.tonyparisi.com/
- */
- THREE.glTFLoader = function (showStatus) {
- this.meshesRequested = 0;
- this.meshesLoaded = 0;
- this.pendingMeshes = [];
- this.animationsRequested = 0;
- this.animationsLoaded = 0;
- this.animations = [];
- this.shadersRequested = 0;
- this.shadersLoaded = 0;
- this.shaders = {};
- THREE.Loader.call( this, showStatus );
- }
- THREE.glTFLoader.prototype = Object.create( THREE.Loader.prototype );
- THREE.glTFLoader.prototype.constructor = THREE.glTFLoader;
- THREE.glTFLoader.prototype.load = function( url, callback ) {
-
- var theLoader = this;
- // Utilities
- function RgbArraytoHex(colorArray) {
- if (!colorArray) return 0xFFFFFFFF;
- var r = Math.floor(colorArray[0] * 255),
- g = Math.floor(colorArray[1] * 255),
- b = Math.floor(colorArray[2] * 255),
- a = 255;
- var color = (a << 24) + (r << 16) + (g << 8) + b;
- return color;
- }
-
- function convertAxisAngleToQuaternion(rotations, count)
- {
- var q = new THREE.Quaternion;
- var axis = new THREE.Vector3;
- var euler = new THREE.Vector3;
-
- var i;
- for (i = 0; i < count; i ++) {
- axis.set(rotations[i * 4], rotations[i * 4 + 1],
- rotations[i * 4 + 2]).normalize();
- var angle = rotations[i * 4 + 3];
- q.setFromAxisAngle(axis, angle);
- rotations[i * 4] = q.x;
- rotations[i * 4 + 1] = q.y;
- rotations[i * 4 + 2] = q.z;
- rotations[i * 4 + 3] = q.w;
- }
- }
- function componentsPerElementForGLType(glType) {
- switch (glType) {
- case WebGLRenderingContext.FLOAT :
- case WebGLRenderingContext.UNSIGNED_BYTE :
- case WebGLRenderingContext.UNSIGNED_SHORT :
- return 1;
- case WebGLRenderingContext.FLOAT_VEC2 :
- return 2;
- case WebGLRenderingContext.FLOAT_VEC3 :
- return 3;
- case WebGLRenderingContext.FLOAT_VEC4 :
- return 4;
- case WebGLRenderingContext.FLOAT_MAT4 :
- return 16;
- default:
- return null;
- }
- }
- function LoadTexture(src) {
- if (!src) { return null; }
- return THREE.ImageUtils.loadTexture(src);
- }
- // Geometry processing
- var ClassicGeometry = function() {
- this.geometry = new THREE.BufferGeometry;
- this.totalAttributes = 0;
- this.loadedAttributes = 0;
- this.indicesLoaded = false;
- this.finished = false;
- this.onload = null;
- this.uvs = null;
- this.indexArray = null;
- };
- ClassicGeometry.prototype.constructor = ClassicGeometry;
- ClassicGeometry.prototype.buildBufferGeometry = function() {
- // Build indexed mesh
- var geometry = this.geometry;
- geometry.addAttribute( 'index', new THREE.BufferAttribute( this.indexArray, 1 ) );
- geometry.addDrawCall( 0, this.indexArray.length, 0 );
- geometry.computeBoundingSphere();
- }
-
- ClassicGeometry.prototype.checkFinished = function() {
- if (this.indexArray && this.loadedAttributes === this.totalAttributes) {
-
- this.buildBufferGeometry();
-
- this.finished = true;
- if (this.onload) {
- this.onload();
- }
- }
- };
- // Delegate for processing index buffers
- var IndicesDelegate = function() {};
- IndicesDelegate.prototype.handleError = function(errorCode, info) {
- // FIXME: report error
- console.log("ERROR(IndicesDelegate):" + errorCode + ":" + info);
- };
- IndicesDelegate.prototype.convert = function(resource, ctx) {
- return new Uint16Array(resource, 0, ctx.indices.count);
- };
- IndicesDelegate.prototype.resourceAvailable = function(glResource, ctx) {
- var geometry = ctx.geometry;
- geometry.indexArray = glResource;
- geometry.checkFinished();
- return true;
- };
- var indicesDelegate = new IndicesDelegate();
- var IndicesContext = function(indices, geometry) {
- this.indices = indices;
- this.geometry = geometry;
- };
-
- // Delegate for processing vertex attribute buffers
- var VertexAttributeDelegate = function() {};
- VertexAttributeDelegate.prototype.handleError = function(errorCode, info) {
- // FIXME: report error
- console.log("ERROR(VertexAttributeDelegate):" + errorCode + ":" + info);
- };
- VertexAttributeDelegate.prototype.convert = function(resource, ctx) {
- return resource;
- };
- VertexAttributeDelegate.prototype.arrayResourceAvailable = function(glResource, ctx) {
- var geom = ctx.geometry;
- var attribute = ctx.attribute;
- var semantic = ctx.semantic;
- var floatArray;
- var i, l;
- //FIXME: Float32 is assumed here, but should be checked.
- if (semantic == "POSITION") {
- // TODO: Should be easy to take strides into account here
- floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
- for (i = 0, l = floatArray.length; i < l; i += 3) {
- geom.geometry.vertices.push( new THREE.Vector3( floatArray[i], floatArray[i + 1], floatArray[i + 2] ) );
- }
- } else if (semantic == "NORMAL") {
- geom.geometry.normals = [];
- floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
- for (i = 0, l = floatArray.length; i < l; i += 3) {
- geom.geometry.normals.push( new THREE.Vector3( floatArray[i], floatArray[i + 1], floatArray[i + 2] ) );
- }
- } else if ((semantic == "TEXCOORD_0") || (semantic == "TEXCOORD" )) {
- geom.uvs = [];
- floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
- for (i = 0, l = floatArray.length; i < l; i += 2) {
- geom.uvs.push( new THREE.Vector2( floatArray[i], 1.0 - floatArray[i + 1] ) );
- }
- }
- else if (semantic == "WEIGHT") {
- nComponents = componentsPerElementForGLType(attribute.type);
- floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
- for (i = 0, l = floatArray.length; i < l; i += 4) {
- geom.geometry.skinWeights.push( new THREE.Vector4( floatArray[i], floatArray[i + 1], floatArray[i + 2], floatArray[i + 3] ) );
- }
- }
- else if (semantic == "JOINT") {
- nComponents = componentsPerElementForGLType(attribute.type);
- floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
- for (i = 0, l = floatArray.length; i < l; i += 4) {
- geom.geometry.skinIndices.push( new THREE.Vector4( floatArray[i], floatArray[i + 1], floatArray[i + 2], floatArray[i + 3] ) );
- }
- }
- }
-
- VertexAttributeDelegate.prototype.bufferResourceAvailable = function(glResource, ctx) {
- var geom = ctx.geometry;
- var attribute = ctx.attribute;
- var semantic = ctx.semantic;
- var floatArray;
- var i, l;
- var nComponents;
- //FIXME: Float32 is assumed here, but should be checked.
- if (semantic == "POSITION") {
- // TODO: Should be easy to take strides into account here
- floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
- geom.geometry.addAttribute( 'position', new THREE.BufferAttribute( floatArray, 3 ) );
- } else if (semantic == "NORMAL") {
- floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
- geom.geometry.addAttribute( 'normal', new THREE.BufferAttribute( floatArray, 3 ) );
- } else if ((semantic == "TEXCOORD_0") || (semantic == "TEXCOORD" )) {
-
- nComponents = componentsPerElementForGLType(attribute.type);
- floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
- // N.B.: flip Y value... should we just set texture.flipY everywhere?
- for (i = 0; i < floatArray.length / 2; i ++) {
- floatArray[i * 2 + 1] = 1.0 - floatArray[i * 2 + 1];
- }
- geom.geometry.addAttribute( 'uv', new THREE.BufferAttribute( floatArray, nComponents ) );
- }
- else if (semantic == "WEIGHT") {
- nComponents = componentsPerElementForGLType(attribute.type);
- floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
- geom.geometry.addAttribute( 'skinWeight', new THREE.BufferAttribute( floatArray, nComponents ) );
- }
- else if (semantic == "JOINT") {
- nComponents = componentsPerElementForGLType(attribute.type);
- floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
- geom.geometry.addAttribute( 'skinIndex', new THREE.BufferAttribute( floatArray, nComponents ) );
- }
- }
-
- VertexAttributeDelegate.prototype.resourceAvailable = function(glResource, ctx) {
- this.bufferResourceAvailable(glResource, ctx);
-
- var geom = ctx.geometry;
- geom.loadedAttributes ++;
- geom.checkFinished();
- return true;
- };
- var vertexAttributeDelegate = new VertexAttributeDelegate();
- var VertexAttributeContext = function(attribute, semantic, geometry) {
- this.attribute = attribute;
- this.semantic = semantic;
- this.geometry = geometry;
- };
- var Mesh = function() {
- this.primitives = [];
- this.materialsPending = [];
- this.loadedGeometry = 0;
- this.onCompleteCallbacks = [];
- };
- Mesh.prototype.addPrimitive = function(geometry, material) {
-
- var self = this;
- geometry.onload = function() {
- self.loadedGeometry ++;
- self.checkComplete();
- };
-
- this.primitives.push({
- geometry: geometry,
- material: material,
- mesh: null
- });
- };
- Mesh.prototype.onComplete = function(callback) {
- this.onCompleteCallbacks.push(callback);
- this.checkComplete();
- };
- Mesh.prototype.checkComplete = function() {
- var self = this;
- if (this.onCompleteCallbacks.length && this.primitives.length == this.loadedGeometry) {
- this.onCompleteCallbacks.forEach(function(callback) {
- callback(self);
- });
- this.onCompleteCallbacks = [];
- }
- };
- Mesh.prototype.attachToNode = function(threeNode) {
- // Assumes that the geometry is complete
- this.primitives.forEach(function(primitive) {
- /*if(!primitive.mesh) {
- primitive.mesh = new THREE.Mesh(primitive.geometry, primitive.material);
- }*/
- var material = primitive.material;
- if (!(material instanceof THREE.Material)) {
- material = theLoader.createShaderMaterial(material);
- }
- var threeMesh = new THREE.Mesh(primitive.geometry.geometry, material);
- threeMesh.castShadow = true;
- threeNode.add(threeMesh);
- });
- };
- // Delayed-loaded material
- var Material = function(params) {
- this.params = params;
- };
-
- // Delegate for processing animation parameter buffers
- var AnimationParameterDelegate = function() {};
- AnimationParameterDelegate.prototype.handleError = function(errorCode, info) {
- // FIXME: report error
- console.log("ERROR(AnimationParameterDelegate):" + errorCode + ":" + info);
- };
- AnimationParameterDelegate.prototype.convert = function(resource, ctx) {
- var parameter = ctx.parameter;
- var glResource = null;
- switch (parameter.type) {
- case WebGLRenderingContext.FLOAT :
- case WebGLRenderingContext.FLOAT_VEC2 :
- case WebGLRenderingContext.FLOAT_VEC3 :
- case WebGLRenderingContext.FLOAT_VEC4 :
- glResource = new Float32Array(resource, 0, parameter.count * componentsPerElementForGLType(parameter.type));
- break;
- default:
- break;
- }
-
- return glResource;
- };
- AnimationParameterDelegate.prototype.resourceAvailable = function(glResource, ctx) {
- var animation = ctx.animation;
- var parameter = ctx.parameter;
- parameter.data = glResource;
- animation.handleParameterLoaded(parameter);
- return true;
- };
- var animationParameterDelegate = new AnimationParameterDelegate();
- var AnimationParameterContext = function(parameter, animation) {
- this.parameter = parameter;
- this.animation = animation;
- };
- // Animations
- var Animation = function() {
- // create Three.js keyframe here
- this.totalParameters = 0;
- this.loadedParameters = 0;
- this.parameters = {};
- this.finishedLoading = false;
- this.onload = null;
- };
- Animation.prototype.constructor = Animation;
- Animation.prototype.handleParameterLoaded = function(parameter) {
- this.parameters[parameter.name] = parameter;
- this.loadedParameters ++;
- this.checkFinished();
- };
-
- Animation.prototype.checkFinished = function() {
- if (this.loadedParameters === this.totalParameters) {
- // Build animation
- this.finishedLoading = true;
- if (this.onload) {
- this.onload();
- }
- }
- };
-
- // Delegate for processing inverse bind matrices buffer
- var InverseBindMatricesDelegate = function() {};
- InverseBindMatricesDelegate.prototype.handleError = function(errorCode, info) {
- // FIXME: report error
- console.log("ERROR(InverseBindMatricesDelegate):" + errorCode + ":" + info);
- };
- InverseBindMatricesDelegate.prototype.convert = function(resource, ctx) {
- var parameter = ctx.parameter;
- var glResource = null;
- switch (parameter.type) {
- case WebGLRenderingContext.FLOAT_MAT4 :
- glResource = new Float32Array(resource, 0, parameter.count * componentsPerElementForGLType(parameter.type));
- break;
- default:
- break;
- }
-
- return glResource;
- };
- InverseBindMatricesDelegate.prototype.resourceAvailable = function(glResource, ctx) {
- var skin = ctx.skin;
- skin.inverseBindMatrices = glResource;
- return true;
- };
- var inverseBindMatricesDelegate = new InverseBindMatricesDelegate();
- var InverseBindMatricesContext = function(param, skin) {
- this.parameter = param;
- this.skin = skin;
- };
- // Delegate for processing shaders from external files
- var ShaderDelegate = function() {};
- ShaderDelegate.prototype.handleError = function(errorCode, info) {
- // FIXME: report error
- console.log("ERROR(ShaderDelegate):" + errorCode + ":" + info);
- };
- ShaderDelegate.prototype.convert = function(resource, ctx) {
- return resource;
- }
-
- ShaderDelegate.prototype.resourceAvailable = function(data, ctx) {
- theLoader.shadersLoaded ++;
- theLoader.shaders[ctx.id] = data;
- return true;
- };
- var shaderDelegate = new ShaderDelegate();
- var ShaderContext = function(id, path) {
- this.id = id;
- this.path = path;
- };
-
- // Resource management
- var ResourceEntry = function(entryID, object, description) {
- this.entryID = entryID;
- this.object = object;
- this.description = description;
- };
- var Resources = function() {
- this._entries = {};
- };
- Resources.prototype.setEntry = function(entryID, object, description) {
- if (!entryID) {
- console.error("No EntryID provided, cannot store", description);
- return;
- }
- if (this._entries[entryID]) {
- console.warn("entry[" + entryID + "] is being overwritten");
- }
-
- this._entries[entryID] = new ResourceEntry(entryID, object, description );
- };
-
- Resources.prototype.getEntry = function(entryID) {
- return this._entries[entryID];
- };
- Resources.prototype.clearEntries = function() {
- this._entries = {};
- };
- LoadDelegate = function() {
- }
-
- LoadDelegate.prototype.loadCompleted = function(callback, obj) {
- callback.call(Window, obj);
- }
-
- // Loader
- var ThreeGLTFLoader = Object.create(glTFParser, {
- load: {
- enumerable: true,
- value: function(userInfo, options) {
- this.resources = new Resources();
- this.cameras = [];
- this.lights = [];
- this.animations = [];
- this.joints = {};
- this.skeltons = {};
- THREE.GLTFLoaderUtils.init();
- glTFParser.load.call(this, userInfo, options);
- }
- },
- cameras: {
- enumerable: true,
- writable: true,
- value : []
- },
- lights: {
- enumerable: true,
- writable: true,
- value : []
- },
-
- animations: {
- enumerable: true,
- writable: true,
- value : []
- },
-
- // Implement WebGLTFLoader handlers
- handleBuffer: {
- value: function(entryID, description, userInfo) {
- this.resources.setEntry(entryID, null, description);
- description.type = "ArrayBuffer";
- return true;
- }
- },
- handleBufferView: {
- value: function(entryID, description, userInfo) {
- this.resources.setEntry(entryID, null, description);
- var buffer = this.resources.getEntry(description.buffer);
- description.type = "ArrayBufferView";
- var bufferViewEntry = this.resources.getEntry(entryID);
- bufferViewEntry.buffer = buffer;
- return true;
- }
- },
- handleShader: {
- value: function(entryID, description, userInfo) {
- this.resources.setEntry(entryID, null, description);
- var shaderRequest = {
- id : entryID,
- path : description.path,
- };
- var shaderContext = new ShaderContext(entryID, description.path);
- theLoader.shadersRequested ++;
- THREE.GLTFLoaderUtils.getFile(shaderRequest, shaderDelegate, shaderContext);
-
- return true;
- }
- },
- handleProgram: {
- value: function(entryID, description, userInfo) {
- this.resources.setEntry(entryID, null, description);
- return true;
- }
- },
- handleTechnique: {
- value: function(entryID, description, userInfo) {
- this.resources.setEntry(entryID, null, description);
- return true;
- }
- },
- createShaderMaterial : {
- value: function(material) {
-
- var fragmentShader = theLoader.shaders[material.params.fragmentShader];
- if (!fragmentShader) {
- console.log("ERROR: Missing fragment shader definition:", material.params.fragmentShader);
- return new THREE.MeshPhongMaterial;
- }
-
- var vertexShader = theLoader.shaders[material.params.vertexShader];
- if (!fragmentShader) {
- console.log("ERROR: Missing vertex shader definition:", material.params.vertexShader);
- return new THREE.MeshPhongMaterial;
- }
-
- var uniforms = {};
- var shaderMaterial = new THREE.ShaderMaterial( {
- fragmentShader: fragmentShader,
- vertexShader: vertexShader,
- uniforms: uniforms,
- } );
- return new THREE.MeshPhongMaterial(material.params);
- }
- },
-
- createShaderParams : {
- value: function(materialId, values, params, instanceProgram) {
- var program = this.resources.getEntry(instanceProgram.program);
-
- if (program) {
- params.fragmentShader = program.description.fragmentShader;
- params.vertexShader = program.description.vertexShader;
- params.attributes = instanceProgram.attributes;
- params.uniforms = instanceProgram.uniforms;
- }
- }
- },
-
- threeJSMaterialType : {
- value: function(materialId, technique, values, params) {
-
- var materialType = THREE.MeshPhongMaterial;
- var defaultPass = null;
- if (technique && technique.description && technique.description.passes)
- defaultPass = technique.description.passes.defaultPass;
-
- if (defaultPass) {
- if (defaultPass.details && defaultPass.details.commonProfile) {
- var profile = technique.description.passes.defaultPass.details.commonProfile;
- if (profile)
- {
- switch (profile.lightingModel)
- {
- case 'Blinn' :
- case 'Phong' :
- materialType = THREE.MeshPhongMaterial;
- break;
-
- case 'Lambert' :
- materialType = THREE.MeshLambertMaterial;
- break;
-
- default :
- materialType = THREE.MeshBasicMaterial;
- break;
- }
-
- if (profile.extras && profile.extras.doubleSided)
- {
- params.side = THREE.DoubleSide;
- }
- }
- }
- else if (defaultPass.instanceProgram) {
-
- var instanceProgram = defaultPass.instanceProgram;
- this.createShaderParams(materialId, values, params, instanceProgram);
-
- var loadshaders = true;
-
- if (loadshaders) {
- materialType = Material;
- }
- }
- }
-
- var texturePath = null;
- var textureParams = null;
- var diffuse = values.diffuse;
- if (diffuse)
- {
- var texture = diffuse;
- if (texture) {
- var textureEntry = this.resources.getEntry(texture);
- if (textureEntry) {
- {
- var imageEntry = this.resources.getEntry(textureEntry.description.source);
- if (imageEntry) {
- texturePath = imageEntry.description.path;
- }
-
- var samplerEntry = this.resources.getEntry(textureEntry.description.sampler);
- if (samplerEntry) {
- textureParams = samplerEntry.description;
- }
- }
- }
- }
- }
- var texture = LoadTexture(texturePath);
- if (texture && textureParams) {
-
- if (textureParams.wrapS == WebGLRenderingContext.REPEAT)
- texture.wrapS = THREE.RepeatWrapping;
- if (textureParams.wrapT == WebGLRenderingContext.REPEAT)
- texture.wrapT = THREE.RepeatWrapping;
-
- if (textureParams.magFilter == WebGLRenderingContext.LINEAR)
- texture.magFilter = THREE.LinearFilter;
- // if (textureParams.minFilter == "LINEAR")
- // texture.minFilter = THREE.LinearFilter;
-
- params.map = texture;
- }
- var envMapPath = null;
- var envMapParams = null;
- var reflective = values.reflective;
- if (reflective)
- {
- var texture = reflective;
- if (texture) {
- var textureEntry = this.resources.getEntry(texture);
- if (textureEntry) {
- {
- var imageEntry = this.resources.getEntry(textureEntry.description.source);
- if (imageEntry) {
- envMapPath = imageEntry.description.path;
- }
-
- var samplerEntry = this.resources.getEntry(textureEntry.description.sampler);
- if (samplerEntry) {
- envMapParams = samplerEntry.description;
- }
- }
- }
- }
- }
- var texture = LoadTexture(envMapPath);
- if (texture && envMapParams) {
-
- if (envMapParams.wrapS == WebGLRenderingContext.REPEAT)
- texture.wrapS = THREE.RepeatWrapping;
- if (envMapParams.wrapT == WebGLRenderingContext.REPEAT)
- texture.wrapT = THREE.RepeatWrapping;
-
- if (envMapParams.magFilter == WebGLRenderingContext.LINEAR)
- texture.magFilter = THREE.LinearFilter;
- // if (envMapParams.minFilter == WebGLRenderingContext.LINEAR)
- // texture.minFilter = THREE.LinearFilter;
-
- params.envMap = texture;
- }
-
- var shininess = values.shininesss || values.shininess; // N.B.: typo in converter!
- if (shininess)
- {
- shininess = shininess;
- }
-
- var diffuseColor = !texturePath ? diffuse : null;
- var opacity = 1.0;
- if (values.hasOwnProperty("transparency"))
- {
- var USE_A_ONE = true; // for now, hack because file format isn't telling us
- opacity = USE_A_ONE ? values.transparency : (1.0 - values.transparency);
- }
-
- // if (diffuseColor) diffuseColor = [0, 1, 0];
-
- params.color = RgbArraytoHex(diffuseColor);
- params.opacity = opacity;
- params.transparent = opacity < 1.0;
- // hack hack hack
- if (texturePath && texturePath.toLowerCase().indexOf(".png") != -1)
- params.transparent = true;
-
- if (!(shininess === undefined))
- {
- params.shininess = shininess;
- }
-
- if (!(values.emission === undefined))
- {
- params.emissive = RgbArraytoHex(values.emission);
- }
-
- if (!(values.specular === undefined))
- {
- params.specular = RgbArraytoHex(values.specular);
- }
- return materialType;
-
- }
- },
-
- handleMaterial: {
- value: function(entryID, description, userInfo) {
- //this should be rewritten using the meta datas that actually create the shader.
- //here we will infer what needs to be pass to Three.js by looking inside the technique parameters.
- var technique = this.resources.getEntry(description.instanceTechnique.technique);
- var materialParams = {};
- var values = description.instanceTechnique.values;
-
- var materialType = this.threeJSMaterialType(entryID, technique, values, materialParams);
- var material = new materialType(materialParams);
-
- this.resources.setEntry(entryID, material, description);
- return true;
- }
- },
- handleMesh: {
- value: function(entryID, description, userInfo) {
- var mesh = new Mesh();
- this.resources.setEntry(entryID, mesh, description);
- var primitivesDescription = description.primitives;
- if (!primitivesDescription) {
- //FIXME: not implemented in delegate
- console.log("MISSING_PRIMITIVES for mesh:" + entryID);
- return false;
- }
- for (var i = 0 ; i < primitivesDescription.length ; i ++) {
- var primitiveDescription = primitivesDescription[i];
-
- if (primitiveDescription.primitive === WebGLRenderingContext.TRIANGLES) {
- var geometry = new ClassicGeometry();
- var materialEntry = this.resources.getEntry(primitiveDescription.material);
- mesh.addPrimitive(geometry, materialEntry.object);
- var indices = this.resources.getEntry(primitiveDescription.indices);
- var bufferEntry = this.resources.getEntry(indices.description.bufferView);
- var indicesObject = {
- bufferView : bufferEntry,
- byteOffset : indices.description.byteOffset,
- count : indices.description.count,
- id : indices.entryID,
- type : indices.description.type
- };
-
- var indicesContext = new IndicesContext(indicesObject, geometry);
- var alreadyProcessedIndices = THREE.GLTFLoaderUtils.getBuffer(indicesObject, indicesDelegate, indicesContext);
- /*if(alreadyProcessedIndices) {
- indicesDelegate.resourceAvailable(alreadyProcessedIndices, indicesContext);
- }*/
- // Load Vertex Attributes
- var allAttributes = Object.keys(primitiveDescription.attributes);
- allAttributes.forEach( function(semantic) {
- geometry.totalAttributes ++;
- var attribute;
- var attributeID = primitiveDescription.attributes[semantic];
- var attributeEntry = this.resources.getEntry(attributeID);
- if (!attributeEntry) {
- //let's just use an anonymous object for the attribute
- attribute = description.attributes[attributeID];
- attribute.id = attributeID;
- this.resources.setEntry(attributeID, attribute, attribute);
-
- var bufferEntry = this.resources.getEntry(attribute.bufferView);
- attributeEntry = this.resources.getEntry(attributeID);
- } else {
- attribute = attributeEntry.object;
- attribute.id = attributeID;
- var bufferEntry = this.resources.getEntry(attribute.bufferView);
- }
- var attributeObject = {
- bufferView : bufferEntry,
- byteOffset : attribute.byteOffset,
- byteStride : attribute.byteStride,
- count : attribute.count,
- max : attribute.max,
- min : attribute.min,
- type : attribute.type,
- id : attributeID
- };
-
- var attribContext = new VertexAttributeContext(attributeObject, semantic, geometry);
- var alreadyProcessedAttribute = THREE.GLTFLoaderUtils.getBuffer(attributeObject, vertexAttributeDelegate, attribContext);
- /*if(alreadyProcessedAttribute) {
- vertexAttributeDelegate.resourceAvailable(alreadyProcessedAttribute, attribContext);
- }*/
- }, this);
- }
- }
- return true;
- }
- },
- handleCamera: {
- value: function(entryID, description, userInfo) {
- var camera;
- if (description.type == "perspective")
- {
- var znear = description.perspective.znear;
- var zfar = description.perspective.zfar;
- var yfov = description.perspective.yfov;
- var xfov = description.perspective.xfov;
- var aspect_ratio = description.perspective.aspect_ratio;
- if (!aspect_ratio)
- aspect_ratio = 1;
-
- if (yfov === undefined)
- {
- if (xfov)
- {
- // According to COLLADA spec...
- // aspect_ratio = xfov / yfov
- yfov = xfov / aspect_ratio;
- }
-
- }
-
- if (yfov)
- {
- camera = new THREE.PerspectiveCamera(yfov, aspect_ratio, znear, zfar);
- }
- }
- else
- {
- camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, znear, zfar );
- }
-
- if (camera)
- {
- this.resources.setEntry(entryID, camera, description);
- }
-
- return true;
- }
- },
- handleLight: {
- value: function(entryID, description, userInfo) {
- var light = null;
- var type = description.type;
- if (type && description[type])
- {
- var lparams = description[type];
- var color = RgbArraytoHex(lparams.color);
-
- switch (type) {
- case "directional" :
- light = new THREE.DirectionalLight(color);
- light.position.set(0, 0, 1);
- break;
-
- case "point" :
- light = new THREE.PointLight(color);
- break;
-
- case "spot " :
- light = new THREE.SpotLight(color);
- light.position.set(0, 0, 1);
- break;
-
- case "ambient" :
- light = new THREE.AmbientLight(color);
- break;
- }
- }
- if (light)
- {
- this.resources.setEntry(entryID, light, description);
- }
-
- return true;
- }
- },
- addPendingMesh: {
- value: function(mesh, threeNode) {
- theLoader.pendingMeshes.push({
- mesh: mesh,
- node: threeNode
- });
- }
- },
-
- handleNode: {
- value: function(entryID, description, userInfo) {
- var threeNode = null;
- if (description.jointId) {
- threeNode = new THREE.Bone();
- threeNode.jointId = description.jointId;
- this.joints[description.jointId] = entryID;
- }
- else {
- threeNode = new THREE.Object3D();
- }
-
- threeNode.name = description.name;
-
- this.resources.setEntry(entryID, threeNode, description);
- var m = description.matrix;
- if (m) {
- threeNode.applyMatrix(new THREE.Matrix4().fromArray( m ));
- threeNode.matrixAutoUpdate = false;
- threeNode.matrixWorldNeedsUpdate = true;
- }
- else {
- var t = description.translation;
- var r = description.rotation;
- var s = description.scale;
-
- var position = t ? new THREE.Vector3(t[0], t[1], t[2]) :
- new THREE.Vector3;
- if (r) {
- convertAxisAngleToQuaternion(r, 1);
- }
- var rotation = r ? new THREE.Quaternion(r[0], r[1], r[2], r[3]) :
- new THREE.Quaternion;
- var scale = s ? new THREE.Vector3(s[0], s[1], s[2]) :
- new THREE.Vector3;
-
- var matrix = new THREE.Matrix4;
- matrix.compose(position, rotation, scale);
- threeNode.matrixAutoUpdate = false;
- threeNode.matrixWorldNeedsUpdate = true;
- threeNode.applyMatrix(matrix);
- }
- var self = this;
-
- // Iterate through all node meshes and attach the appropriate objects
- //FIXME: decision needs to be made between these 2 ways, probably meshes will be discarded.
- var meshEntry;
- if (description.mesh) {
- meshEntry = this.resources.getEntry(description.mesh);
- theLoader.meshesRequested ++;
- meshEntry.object.onComplete(function(mesh) {
- self.addPendingMesh(mesh, threeNode);
- theLoader.meshesLoaded ++;
- theLoader.checkComplete();
- });
- }
- if (description.meshes) {
- description.meshes.forEach( function(meshID) {
- meshEntry = this.resources.getEntry(meshID);
- theLoader.meshesRequested ++;
- meshEntry.object.onComplete(function(mesh) {
- self.addPendingMesh(mesh, threeNode);
- theLoader.meshesLoaded ++;
- theLoader.checkComplete();
- });
- }, this);
- }
- if (description.instanceSkin) {
- var skinEntry = this.resources.getEntry(description.instanceSkin.skin);
-
- if (skinEntry) {
- var skin = skinEntry.object;
- description.instanceSkin.skin = skin;
- threeNode.instanceSkin = description.instanceSkin;
- var sources = description.instanceSkin.sources;
- skin.meshes = [];
- sources.forEach( function(meshID) {
- meshEntry = this.resources.getEntry(meshID);
- theLoader.meshesRequested ++;
- meshEntry.object.onComplete(function(mesh) {
-
- skin.meshes.push(mesh);
- theLoader.meshesLoaded ++;
- theLoader.checkComplete();
- });
- }, this);
-
- }
- }
-
- if (description.camera) {
- var cameraEntry = this.resources.getEntry(description.camera);
- if (cameraEntry) {
- threeNode.add(cameraEntry.object);
- this.cameras.push(cameraEntry.object);
- }
- }
- if (description.light) {
- var lightEntry = this.resources.getEntry(description.light);
- if (lightEntry) {
- threeNode.add(lightEntry.object);
- this.lights.push(lightEntry.object);
- }
- }
-
- return true;
- }
- },
-
- buildNodeHirerachy: {
- value: function(nodeEntryId, parentThreeNode) {
- var nodeEntry = this.resources.getEntry(nodeEntryId);
- var threeNode = nodeEntry.object;
- parentThreeNode.add(threeNode);
- var children = nodeEntry.description.children;
- if (children) {
- children.forEach( function(childID) {
- this.buildNodeHirerachy(childID, threeNode);
- }, this);
- }
- return threeNode;
- }
- },
- buildSkin: {
- value: function(node) {
-
- var skin = node.instanceSkin.skin;
- if (skin) {
- node.instanceSkin.skeletons.forEach(function(skeleton) {
- var nodeEntry = this.resources.getEntry(skeleton);
- if (nodeEntry) {
- var rootSkeleton = nodeEntry.object;
- var dobones = true;
- var i, len = skin.meshes.length;
- for (i = 0; i < len; i ++) {
- var mesh = skin.meshes[i];
- var threeMesh = null;
- mesh.primitives.forEach(function(primitive) {
- var material = primitive.material;
- if (!(material instanceof THREE.Material)) {
- material = this.createShaderMaterial(material);
- }
- threeMesh = new THREE.SkinnedMesh(primitive.geometry.geometry, material, false);
- threeMesh.add(rootSkeleton);
-
- var geometry = primitive.geometry.geometry;
- var j;
- if (geometry.vertices) {
- for ( j = 0; j < geometry.vertices.length; j ++ ) {
- geometry.vertices[j].applyMatrix4( skin.bindShapeMatrix );
- }
- }
- else if (geometry.attributes.position) {
- var a = geometry.attributes.position.array;
- var v = new THREE.Vector3;
- for ( j = 0; j < a.length / 3; j ++ ) {
- v.set(a[j * 3], a[j * 3 + 1], a[j * 3 + 2]);
- v.applyMatrix4( skin.bindShapeMatrix );
- a[j * 3] = v.x;
- a[j * 3 + 1] = v.y;
- a[j * 3 + 2] = v.z;
- }
- }
- if (threeMesh && dobones) {
- material.skinning = true;
-
- threeMesh.boneInverses = [];
- var jointsIds = skin.jointsIds;
- var bones = [];
- var boneInverses = [];
- var i, len = jointsIds.length;
- for (i = 0; i < len; i ++) {
- var jointId = jointsIds[i];
- var nodeForJoint = this.joints[jointId];
- var joint = this.resources.getEntry(nodeForJoint).object;
- if (joint) {
-
- joint.skin = threeMesh;
- bones.push(joint);
-
- var m = skin.inverseBindMatrices;
- var mat = new THREE.Matrix4().set(
- m[i * 16 + 0], m[i * 16 + 4], m[i * 16 + 8], m[i * 16 + 12],
- m[i * 16 + 1], m[i * 16 + 5], m[i * 16 + 9], m[i * 16 + 13],
- m[i * 16 + 2], m[i * 16 + 6], m[i * 16 + 10], m[i * 16 + 14],
- m[i * 16 + 3], m[i * 16 + 7], m[i * 16 + 11], m[i * 16 + 15]
- );
- boneInverses.push(mat);
-
- } else {
- console.log("WARNING: jointId:" + jointId + " cannot be found in skeleton:" + skeleton);
- }
- }
- threeMesh.bind(new THREE.Skeleton(bones, boneInverses, false));
- }
-
- if (threeMesh) {
- threeMesh.castShadow = true;
- node.add(threeMesh);
- }
-
- }, this);
- }
-
- }
-
- }, this);
-
- }
- }
- },
-
- buildSkins: {
- value: function(node) {
- if (node.instanceSkin)
- this.buildSkin(node);
-
- var children = node.children;
- if (children) {
- children.forEach( function(child) {
- this.buildSkins(child);
- }, this);
- }
- }
- },
-
- createMeshAnimations : {
- value : function(root) {
- this.buildSkins(root);
- }
- },
- handleScene: {
- value: function(entryID, description, userInfo) {
- if (!description.nodes) {
- console.log("ERROR: invalid file required nodes property is missing from scene");
- return false;
- }
- description.nodes.forEach( function(nodeUID) {
- this.buildNodeHirerachy(nodeUID, userInfo.rootObj);
- }, this);
- if (this.delegate) {
- this.delegate.loadCompleted(userInfo.callback, userInfo.rootObj);
- }
- return true;
- }
- },
- handleImage: {
- value: function(entryID, description, userInfo) {
- this.resources.setEntry(entryID, null, description);
- return true;
- }
- },
-
- addNodeAnimationChannel : {
- value : function(name, channel, interp) {
- if (!this.nodeAnimationChannels)
- this.nodeAnimationChannels = {};
-
- if (!this.nodeAnimationChannels[name]) {
- this.nodeAnimationChannels[name] = [];
- }
-
- this.nodeAnimationChannels[name].push(interp);
- },
- },
-
- createAnimations : {
- value : function() {
- for (var name in this.nodeAnimationChannels) {
- var nodeAnimationChannels = this.nodeAnimationChannels[name];
- var i, len = nodeAnimationChannels.length;
- //console.log(" animation channels for node " + name);
- //for (i = 0; i < len; i++) {
- // console.log(nodeAnimationChannels[i]);
- //}
- var anim = new THREE.glTFAnimation(nodeAnimationChannels);
- anim.name = "animation_" + name;
- this.animations.push(anim);
- }
- }
- },
-
- buildAnimation: {
- value : function(animation) {
-
- var interps = [];
- var i, len = animation.channels.length;
- for (i = 0; i < len; i ++) {
-
- var channel = animation.channels[i];
- var sampler = animation.samplers[channel.sampler];
- if (sampler) {
-
- var input = animation.parameters[sampler.input];
- if (input && input.data) {
-
- var output = animation.parameters[sampler.output];
- if (output && output.data) {
-
- var target = channel.target;
- var node = this.resources.getEntry(target.id);
- if (node) {
- var path = target.path;
-
- if (path == "rotation")
- {
- convertAxisAngleToQuaternion(output.data, output.count);
- }
-
- var interp = {
- keys : input.data,
- values : output.data,
- count : input.count,
- target : node.object,
- path : path,
- type : sampler.interpolation
- };
-
- this.addNodeAnimationChannel(target.id, channel, interp);
- interps.push(interp);
- }
- }
- }
- }
- }
- }
- },
-
- handleAnimation: {
- value: function(entryID, description, userInfo) {
-
- var self = this;
- theLoader.animationsRequested ++;
- var animation = new Animation();
- animation.name = entryID;
- animation.onload = function() {
- // self.buildAnimation(animation);
- theLoader.animationsLoaded ++;
- theLoader.animations.push(animation);
- theLoader.checkComplete();
- };
-
- animation.channels = description.channels;
- animation.samplers = description.samplers;
- this.resources.setEntry(entryID, animation, description);
- var parameters = description.parameters;
- if (!parameters) {
- //FIXME: not implemented in delegate
- console.log("MISSING_PARAMETERS for animation:" + entryID);
- return false;
- }
-
- // Load parameter buffers
- var params = Object.keys(parameters);
- params.forEach( function(param) {
- animation.totalParameters ++;
- var parameter = parameters[param];
- var accessor = this.resources.getEntry(parameter);
- if (!accessor)
- debugger;
- accessor = accessor.object;
- var bufferView = this.resources.getEntry(accessor.bufferView);
- var paramObject = {
- bufferView : bufferView,
- byteOffset : accessor.byteOffset,
- count : accessor.count,
- type : accessor.type,
- id : accessor.bufferView,
- name : param
- };
-
- var paramContext = new AnimationParameterContext(paramObject, animation);
- var alreadyProcessedAttribute = THREE.GLTFLoaderUtils.getBuffer(paramObject, animationParameterDelegate, paramContext);
- /*if(alreadyProcessedAttribute) {
- vertexAttributeDelegate.resourceAvailable(alreadyProcessedAttribute, attribContext);
- }*/
- }, this);
- return true;
- }
- },
- handleAccessor: {
- value: function(entryID, description, userInfo) {
- // Save attribute entry
- this.resources.setEntry(entryID, description, description);
- return true;
- }
- },
- handleSkin: {
- value: function(entryID, description, userInfo) {
- // Save skin entry
-
- var skin = {
- };
-
- var m = description.bindShapeMatrix;
- skin.bindShapeMatrix = new THREE.Matrix4().fromArray( m );
-
- skin.jointsIds = description.joints;
- var inverseBindMatricesDescription = description.inverseBindMatrices;
- skin.inverseBindMatricesDescription = inverseBindMatricesDescription;
- skin.inverseBindMatricesDescription.id = entryID + "_inverseBindMatrices";
- var bufferEntry = this.resources.getEntry(inverseBindMatricesDescription.bufferView);
- var paramObject = {
- bufferView : bufferEntry,
- byteOffset : inverseBindMatricesDescription.byteOffset,
- count : inverseBindMatricesDescription.count,
- type : inverseBindMatricesDescription.type,
- id : inverseBindMatricesDescription.bufferView,
- name : skin.inverseBindMatricesDescription.id
- };
-
- var context = new InverseBindMatricesContext(paramObject, skin);
- var alreadyProcessedAttribute = THREE.GLTFLoaderUtils.getBuffer(paramObject, inverseBindMatricesDelegate, context);
- var bufferView = this.resources.getEntry(skin.inverseBindMatricesDescription.bufferView);
- skin.inverseBindMatricesDescription.bufferView =
- bufferView.object;
- this.resources.setEntry(entryID, skin, description);
- return true;
- }
- },
- handleSampler: {
- value: function(entryID, description, userInfo) {
- // Save attribute entry
- this.resources.setEntry(entryID, description, description);
- return true;
- }
- },
- handleTexture: {
- value: function(entryID, description, userInfo) {
- // Save attribute entry
- this.resources.setEntry(entryID, null, description);
- return true;
- }
- },
-
- handleError: {
- value: function(msg) {
- throw new Error(msg);
- return true;
- }
- },
-
- _delegate: {
- value: new LoadDelegate,
- writable: true
- },
- delegate: {
- enumerable: true,
- get: function() {
- return this._delegate;
- },
- set: function(value) {
- this._delegate = value;
- }
- }
- });
- // Loader
- var Context = function(rootObj, callback) {
- this.rootObj = rootObj;
- this.callback = callback;
- };
- var rootObj = new THREE.Object3D();
- var self = this;
-
- var loader = Object.create(ThreeGLTFLoader);
- loader.initWithPath(url);
- loader.load(new Context(rootObj,
- function(obj) {
- }),
- null);
- this.loader = loader;
- this.callback = callback;
- this.rootObj = rootObj;
- return rootObj;
- }
- THREE.glTFLoader.prototype.callLoadedCallback = function() {
- var result = {
- scene : this.rootObj,
- cameras : this.loader.cameras,
- animations : this.loader.animations,
- };
-
- this.callback(result);
- }
- THREE.glTFLoader.prototype.checkComplete = function() {
- if (this.meshesLoaded == this.meshesRequested
- && this.shadersLoaded == this.shadersRequested
- && this.animationsLoaded == this.animationsRequested)
- {
-
- for (var i = 0; i < this.pendingMeshes.length; i ++) {
- var pending = this.pendingMeshes[i];
- pending.mesh.attachToNode(pending.node);
- }
-
- for (var i = 0; i < this.animationsLoaded; i ++) {
- var animation = this.animations[i];
- this.loader.buildAnimation(animation);
- }
- this.loader.createAnimations();
- this.loader.createMeshAnimations(this.rootObj);
-
- this.callLoadedCallback();
- }
- }
|