diff --git a/docs/api/loaders/ImageBitmapLoader.html b/docs/api/loaders/ImageBitmapLoader.html new file mode 100644 index 0000000000000000000000000000000000000000..5638e2ddffd48e0eeb118190356fdeadfa851395 --- /dev/null +++ b/docs/api/loaders/ImageBitmapLoader.html @@ -0,0 +1,104 @@ + + + + + + + + + + +

[name]

+ +
+ A loader for loading an [page:Image] as an [link:https://developer.mozilla.org/de/docs/Web/API/ImageBitmap ImageBitmap]. An ImageBitmap provides an asynchronous and resource efficient pathway to prepare textures for rendering in WebGL. + +
+ +

Example

+ +
+ [example:webgl_loader_imagebitmap WebGL / loader / ImageBitmap] +
+ + + // instantiate a loader + var loader = new THREE.ImageBitmapLoader(); + + // load a image resource + loader.load( + // resource URL + 'textures/skyboxsun25degtest.png', + // Function when resource is loaded + function ( imageBitmap ) { + var texture = new THREE.CanvasTexture( imageBitmap ); + var material = new THREE.MeshBasicMaterial( { map: texture } ); + }, + // Function called when download progresses + function ( xhr ) { + console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); + }, + // Function called when download errors + function ( xhr ) { + console.log( 'An error happened' ); + } + ); + + + +

Constructor

+ +

[name]( [page:LoadingManager manager] )

+
+ [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].

+ + Creates a new [name]. +
+ +

Properties

+ +

[property:LoadingManager manager]

+
+ The [page:LoadingManager loadingManager] the loader is using. Default is [page:DefaultLoadingManager]. +
+ +

[property:String options]

+
An optional object that sets options for the internally used [link:https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap createImageBitmap] factory method. Default is *undefined*.
+ +

[property:String path]

+
The base path from which files will be loaded. See [page:.setPath]. Default is *undefined*.
+ +

Methods

+ +

[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

+
+ [page:String url] — the path or URL to the file. This can also be a + [link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].
+ [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Image image].
+ [page:Function onProgress] — Will be called while load progresses. The argument will be the progress event.
+ [page:Function onError] — Will be called when load errors.
+
+
+ Begin loading from url and return the [page:ImageBitmap image] object that will contain the data. +
+ +

[method:ImageBitmapLoader setCrossOrigin]()

+
This method exists for compatibility reasons and implements no logic. It ensures that [name] has a similar interface like [page:ImageLoader].
+ +

[method:ImageBitmapLoader setOptions]( [page:Object options] )

+
+ Sets the options object for [link:https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap createImageBitmap]. +
+ +

[method:ImageBitmapLoader setPath]( [page:String path] )

+
+ Sets the base path or URL from which to load files. This can be useful if + you are loading many images from the same directory. +
+ + +

Source

+ + [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] + + diff --git a/docs/api/loaders/ImageLoader.html b/docs/api/loaders/ImageLoader.html index 3100e699b91f21d87d64edeccaa567515b64cd6b..23bb2437cc892ce0b53ed06d75d023b362790d14 100644 --- a/docs/api/loaders/ImageLoader.html +++ b/docs/api/loaders/ImageLoader.html @@ -78,12 +78,6 @@

[property:String path]

The base path from which files will be loaded. See [page:.setPath]. Default is *undefined*.
-

[property:String withCredentials]

-
- Whether the XMLHttpRequest uses credentials - see [page:.setWithCredentials]. - Default is *undefined*. -
-

Methods

[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

@@ -107,13 +101,6 @@ you are loading many images from the same directory. -

[method:FileLoader setWithCredentials]( [page:Boolean value] )

- Whether the XMLHttpRequest uses credentials such as cookies, authorization headers or - TLS client certificates. See - [link:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials XMLHttpRequest.withCredentials].
- Note that this has no effect if you are loading files locally or from the same domain. -
-

Source

[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] diff --git a/docs/api/textures/Texture.html b/docs/api/textures/Texture.html index 440c396535632f3785a5650622ef753084eb7f9a..2d38f66e388ad7c1710a34811d096e689e327e52 100644 --- a/docs/api/textures/Texture.html +++ b/docs/api/textures/Texture.html @@ -15,7 +15,7 @@

Constructor

-

[name]( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy )

+

[name]( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding )

Example

diff --git a/docs/list.js b/docs/list.js index c8c396fa7ad5b15ac08890e7a80f5e6571ee42f4..0b56008b55e461b0f40a0bfd684151c928155477 100644 --- a/docs/list.js +++ b/docs/list.js @@ -224,6 +224,7 @@ var list = { "DataTextureLoader": "api/loaders/DataTextureLoader", "FileLoader": "api/loaders/FileLoader", "FontLoader": "api/loaders/FontLoader", + "ImageBitmapLoader": "api/loaders/ImageBitmapLoader", "ImageLoader": "api/loaders/ImageLoader", "JSONLoader": "api/loaders/JSONLoader", "Loader": "api/loaders/Loader", diff --git a/examples/js/exporters/GLTFExporter.js b/examples/js/exporters/GLTFExporter.js index 0b70b1f64c48a39bfa092383c0c71b0defd729ee..fa327470ea9b84c2047dd8544820e0809c6e3f66 100644 --- a/examples/js/exporters/GLTFExporter.js +++ b/examples/js/exporters/GLTFExporter.js @@ -121,9 +121,9 @@ THREE.GLTFExporter.prototype = { } - var buffer = new ArrayBuffer( text.length * 2 ); // 2 bytes per character. + var buffer = new ArrayBuffer( text.length ); - var bufferView = new Uint16Array( buffer ); + var bufferView = new Uint8Array( buffer ); for ( var i = 0; i < text.length; ++ i ) { @@ -380,6 +380,14 @@ THREE.GLTFExporter.prototype = { canvas.width = map.image.width; canvas.height = map.image.height; var ctx = canvas.getContext( '2d' ); + + if ( map.flipY === true ) { + + ctx.translate( 0, map.image.height ); + ctx.scale( 1, -1 ); + + } + ctx.drawImage( map.image, 0, 0 ); // @TODO Embed in { bufferView } if options.binary set. diff --git a/examples/js/loaders/ColladaLoader.js b/examples/js/loaders/ColladaLoader.js index 1b2f8f20b16d625c0c0b75f3a5d6e8580674c07f..cf8515fc9ad66e7da2972207fe1590ff7e4cacb3 100644 --- a/examples/js/loaders/ColladaLoader.js +++ b/examples/js/loaders/ColladaLoader.js @@ -19,7 +19,7 @@ THREE.ColladaLoader.prototype = { var scope = this; - var path = THREE.Loader.prototype.extractUrlBase( url ); + var path = scope.path === undefined ? THREE.Loader.prototype.extractUrlBase( url ) : scope.path; var loader = new THREE.FileLoader( scope.manager ); loader.load( url, function ( text ) { @@ -30,6 +30,12 @@ THREE.ColladaLoader.prototype = { }, + setPath: function ( value ) { + + this.path = value; + + }, + options: { set convertUpAxis( value ) { diff --git a/examples/js/loaders/FBXLoader.js b/examples/js/loaders/FBXLoader.js index 018cdbb6c5b223a14f5241c3c3bf2083e94d00d7..0f650c67a58fe5db0e975789887c266b413b685f 100644 --- a/examples/js/loaders/FBXLoader.js +++ b/examples/js/loaders/FBXLoader.js @@ -304,29 +304,61 @@ // Parse individual node in FBXTree.Objects.subNodes.Texture function parseTexture( textureNode, loader, imageMap, connections ) { - var FBX_ID = textureNode.id; + var texture = loadTexture( textureNode, loader, imageMap, connections ); - var name = textureNode.attrName; + texture.FBX_ID = textureNode.id; + + texture.name = textureNode.attrName; + + var wrapModeU = textureNode.properties.WrapModeU; + var wrapModeV = textureNode.properties.WrapModeV; + + var valueU = wrapModeU !== undefined ? wrapModeU.value : 0; + var valueV = wrapModeV !== undefined ? wrapModeV.value : 0; + + // http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a + // 0: repeat(default), 1: clamp + + texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + + if ( 'Scaling' in textureNode.properties ) { + + var values = textureNode.properties.Scaling.value; + + texture.repeat.x = values[ 0 ]; + texture.repeat.y = values[ 1 ]; + + } + + return texture; + + } + + // load a texture specified as a blob or data URI, or via an external URL using THREE.TextureLoader + function loadTexture( textureNode, loader, imageMap, connections ) { var fileName; var filePath = textureNode.properties.FileName; var relativeFilePath = textureNode.properties.RelativeFilename; - var children = connections.get( FBX_ID ).children; + var children = connections.get( textureNode.id ).children; + // embedded texture if ( children !== undefined && children.length > 0 && imageMap.has( children[ 0 ].ID ) ) { fileName = imageMap.get( children[ 0 ].ID ); - } else if ( relativeFilePath !== undefined && relativeFilePath[ 0 ] !== '/' && relativeFilePath.match( /^[a-zA-Z]:/ ) === null ) { - - // use textureNode.properties.RelativeFilename - // if it exists and it doesn't seem an absolute path + } + // check that relative path is not an actually an absolute path and if so use it to load texture + else if ( relativeFilePath !== undefined && relativeFilePath[ 0 ] !== '/' && relativeFilePath.match( /^[a-zA-Z]:/ ) === null ) { fileName = relativeFilePath; - } else { + } + // texture specified by absolute path + else { var split = filePath.split( /[\\\/]/ ); @@ -351,29 +383,6 @@ } var texture = loader.load( fileName ); - texture.name = name; - texture.FBX_ID = FBX_ID; - - var wrapModeU = textureNode.properties.WrapModeU; - var wrapModeV = textureNode.properties.WrapModeV; - - var valueU = wrapModeU !== undefined ? wrapModeU.value : 0; - var valueV = wrapModeV !== undefined ? wrapModeV.value : 0; - - // http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a - // 0: repeat(default), 1: clamp - - texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; - texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; - - if ( 'Scaling' in textureNode.properties ) { - - var values = textureNode.properties.Scaling.value; - - texture.repeat.x = values[ 0 ]; - texture.repeat.y = values[ 1 ]; - - } loader.setPath( currentPath ); @@ -381,7 +390,6 @@ } - // Parse nodes in FBXTree.Objects.subNodes.Material function parseMaterials( FBXTree, textureMap, connections ) { @@ -392,7 +400,7 @@ var materialNodes = FBXTree.Objects.subNodes.Material; for ( var nodeID in materialNodes ) { - var material = parseMaterial( materialNodes[ nodeID ], textureMap, connections ); + var material = parseMaterial( FBXTree, materialNodes[ nodeID ], textureMap, connections ); if ( material !== null ) materialMap.set( parseInt( nodeID ), material ); } @@ -406,7 +414,7 @@ // Parse single node in FBXTree.Objects.subNodes.Material // Materials are connected to texture maps in FBXTree.Objects.subNodes.Textures // FBX format currently only supports Lambert and Phong shading models - function parseMaterial( materialNode, textureMap, connections ) { + function parseMaterial( FBXTree, materialNode, textureMap, connections ) { var FBX_ID = materialNode.id; var name = materialNode.attrName; @@ -424,7 +432,7 @@ var children = connections.get( FBX_ID ).children; - var parameters = parseParameters( materialNode.properties, textureMap, children ); + var parameters = parseParameters( FBXTree, materialNode.properties, textureMap, children, connections ); var material; @@ -452,7 +460,7 @@ // Parse FBX material and return parameters suitable for a three.js material // Also parse the texture map and return any textures associated with the material - function parseParameters( properties, textureMap, childrenRelationships ) { + function parseParameters( FBXTree, properties, textureMap, childrenRelationships, connections ) { var parameters = {}; @@ -520,33 +528,33 @@ break; case 'DiffuseColor': - parameters.map = textureMap.get( relationship.ID ); + parameters.map = getTexture( FBXTree, textureMap, relationship.ID, connections ); break; case 'DisplacementColor': - parameters.displacementMap = textureMap.get( relationship.ID ); + parameters.displacementMap = getTexture( FBXTree, textureMap, relationship.ID, connections ); break; case 'EmissiveColor': - parameters.emissiveMap = textureMap.get( relationship.ID ); + parameters.emissiveMap = getTexture( FBXTree, textureMap, relationship.ID, connections ); break; case 'NormalMap': - parameters.normalMap = textureMap.get( relationship.ID ); + parameters.normalMap = getTexture( FBXTree, textureMap, relationship.ID, connections ); break; case 'ReflectionColor': - parameters.envMap = textureMap.get( relationship.ID ); + parameters.envMap = getTexture( FBXTree, textureMap, relationship.ID, connections ); parameters.envMap.mapping = THREE.EquirectangularReflectionMapping; break; case 'SpecularColor': - parameters.specularMap = textureMap.get( relationship.ID ); + parameters.specularMap = getTexture( FBXTree, textureMap, relationship.ID, connections ); break; case 'TransparentColor': - parameters.alphaMap = textureMap.get( relationship.ID ); + parameters.alphaMap = getTexture( FBXTree, textureMap, relationship.ID, connections ); parameters.transparent = true; break; @@ -566,6 +574,21 @@ } + // get a texture from the textureMap for use by a material. + function getTexture( FBXTree, textureMap, id, connections ) { + + // if the texture is a layered texture, just use the first layer and issue a warning + if ( 'LayeredTexture' in FBXTree.Objects.subNodes && id in FBXTree.Objects.subNodes.LayeredTexture ) { + + console.warn( 'THREE.FBXLoader: layered textures are not supported in three.js. Discarding all but first layer.' ); + id = connections.get( id ).children[ 0 ].ID; + + } + + return textureMap.get( id ); + + } + // Parse nodes in FBXTree.Objects.subNodes.Deformer // Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here // Generates map of Skeleton-like objects for use later when generating and binding skeletons. @@ -743,7 +766,6 @@ } - var weightTable = {}; if ( deformer ) { @@ -843,7 +865,7 @@ } - var WIndex = [ 0, 0, 0, 0 ]; + var wIndex = [ 0, 0, 0, 0 ]; var Weight = [ 0, 0, 0, 0 ]; weights.forEach( function ( weight, weightIndex ) { @@ -858,8 +880,8 @@ comparedWeightArray[ comparedWeightIndex ] = currentWeight; currentWeight = comparedWeight; - var tmp = WIndex[ comparedWeightIndex ]; - WIndex[ comparedWeightIndex ] = currentIndex; + var tmp = wIndex[ comparedWeightIndex ]; + wIndex[ comparedWeightIndex ] = currentIndex; currentIndex = tmp; } @@ -868,7 +890,7 @@ } ); - weightIndices = WIndex; + weightIndices = wIndex; weights = Weight; } @@ -898,6 +920,12 @@ } + if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) { + + var materialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo )[ 0 ]; + + } + if ( uvInfo ) { for ( var i = 0; i < uvInfo.length; i ++ ) { @@ -922,7 +950,7 @@ faceLength ++; // we have reached the end of a face - it may have 4 sides though - // in which case the data is split into to represent 3 sides faces + // in which case the data is split to represent two 3 sided faces if ( endOfFace ) { for ( var i = 2; i < faceLength; i ++ ) { @@ -939,11 +967,7 @@ vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 1 ] ] ); vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 2 ] ] ); - } - - if ( deformer ) { - - for ( var i = 2; i < faceLength; i ++ ) { + if ( deformer ) { vertexWeightsBuffer.push( faceWeights[ 0 ] ); vertexWeightsBuffer.push( faceWeights[ 1 ] ); @@ -977,11 +1001,31 @@ } - } + if ( colorInfo ) { + + colorsBuffer.push( faceColors[ 0 ] ); + colorsBuffer.push( faceColors[ 1 ] ); + colorsBuffer.push( faceColors[ 2 ] ); + + colorsBuffer.push( faceColors[ ( i - 1 ) * 3 ] ); + colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 1 ] ); + colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 2 ] ); + + colorsBuffer.push( faceColors[ i * 3 ] ); + colorsBuffer.push( faceColors[ i * 3 + 1 ] ); + colorsBuffer.push( faceColors[ i * 3 + 2 ] ); + + } + + if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) { + + materialIndexBuffer.push( materialIndex ); + materialIndexBuffer.push( materialIndex ); + materialIndexBuffer.push( materialIndex ); - if ( normalInfo ) { + } - for ( var i = 2; i < faceLength; i ++ ) { + if ( normalInfo ) { normalBuffer.push( faceNormals[ 0 ] ); normalBuffer.push( faceNormals[ 1 ] ); @@ -997,15 +1041,11 @@ } - } - - if ( uvInfo ) { - - for ( var j = 0; j < uvInfo.length; j ++ ) { + if ( uvInfo ) { - if ( uvsBuffer[ j ] === undefined ) uvsBuffer[ j ] = []; + for ( var j = 0; j < uvInfo.length; j ++ ) { - for ( var i = 2; i < faceLength; i ++ ) { + if ( uvsBuffer[ j ] === undefined ) uvsBuffer[ j ] = []; uvsBuffer[ j ].push( faceUVs[ j ][ 0 ] ); uvsBuffer[ j ].push( faceUVs[ j ][ 1 ] ); @@ -1022,41 +1062,6 @@ } - if ( colorInfo ) { - - for ( var i = 2; i < faceLength; i ++ ) { - - - colorsBuffer.push( faceColors[ 0 ] ); - colorsBuffer.push( faceColors[ 1 ] ); - colorsBuffer.push( faceColors[ 2 ] ); - - colorsBuffer.push( faceColors[ ( i - 1 ) * 3 ] ); - colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 1 ] ); - colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 2 ] ); - - colorsBuffer.push( faceColors[ i * 3 ] ); - colorsBuffer.push( faceColors[ i * 3 + 1 ] ); - colorsBuffer.push( faceColors[ i * 3 + 2 ] ); - - } - - } - - if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) { - - var materialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo )[ 0 ]; - - for ( var i = 2; i < faceLength; i ++ ) { - - materialIndexBuffer.push( materialIndex ); - materialIndexBuffer.push( materialIndex ); - materialIndexBuffer.push( materialIndex ); - - } - - } - polygonIndex ++; endOfFace = false; @@ -1165,6 +1170,7 @@ } + // Parse normal from FBXTree.Objects.subNodes.Geometry.subNodes.LayerElementNormal if it exists function getNormals( NormalNode ) { @@ -1446,22 +1452,66 @@ } - - // parse nodes in FBXTree.Objects.subNodes.Model and generate a THREE.Group + // create the main THREE.Group() to be returned by the loader function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) { var sceneGraph = new THREE.Group(); - var ModelNode = FBXTree.Objects.subNodes.Model; + var modelMap = parseModels( FBXTree, deformers, geometryMap, materialMap, connections ); + + var modelNodes = FBXTree.Objects.subNodes.Model; + + modelMap.forEach( function ( model ) { + + var modelNode = modelNodes[ model.FBX_ID ]; + + setModelTransforms( FBXTree, model, modelNode, connections, sceneGraph ); + + var conns = connections.get( model.FBX_ID ); + for ( var parentIndex = 0; parentIndex < conns.parents.length; parentIndex ++ ) { + + var modelArray = Array.from( modelMap.values() ); + var pIndex = findIndex( modelArray, function ( mod ) { + + return mod.FBX_ID === conns.parents[ parentIndex ].ID; + + } ); + if ( pIndex > - 1 ) { + + modelArray[ pIndex ].add( model ); + break; + + } + + } + if ( model.parent === null ) { + + sceneGraph.add( model ); + + } + + } ); + + bindSkeleton( FBXTree, deformers, geometryMap, modelMap, connections, sceneGraph ); + + addAnimations( FBXTree, connections, sceneGraph ); + + createAmbientLight( FBXTree, sceneGraph ); - var modelArray = []; + return sceneGraph; + + } + + // parse nodes in FBXTree.Objects.subNodes.Model + function parseModels( FBXTree, deformers, geometryMap, materialMap, connections ) { var modelMap = new Map(); + var modelNodes = FBXTree.Objects.subNodes.Model; - for ( var nodeID in ModelNode ) { + for ( var nodeID in modelNodes ) { var id = parseInt( nodeID ); - var node = ModelNode[ nodeID ]; + var node = modelNodes[ nodeID ]; var conns = connections.get( id ); var model = null; @@ -1493,433 +1543,457 @@ switch ( node.attrType ) { - // create a THREE.PerspectiveCamera or THREE.OrthographicCamera case 'Camera': + model = createCamera( FBXTree, conns ); + break; + case 'Light': + model = createLight( FBXTree, conns ); + break; + case 'Mesh': + model = createMesh( FBXTree, conns, geometryMap, materialMap ); + break; + case 'NurbsCurve': + model = createCurve( conns, geometryMap ); + break; + default: + model = new THREE.Group(); + break; - var cameraAttribute; - - for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { + } - var childID = conns.children[ childrenIndex ].ID; + } - var attr = FBXTree.Objects.subNodes.NodeAttribute[ childID ]; + model.name = THREE.PropertyBinding.sanitizeNodeName( node.attrName ); + model.FBX_ID = id; - if ( attr !== undefined && attr.properties !== undefined ) { + modelMap.set( id, model ); - cameraAttribute = attr.properties; + } - } + return modelMap; - } + } - if ( cameraAttribute === undefined ) { + // create a THREE.PerspectiveCamera or THREE.OrthographicCamera + function createCamera( FBXTree, conns ) { - model = new THREE.Object3D(); + var model; + var cameraAttribute; - } else { + for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { - var type = 0; - if ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) { + var childID = conns.children[ childrenIndex ].ID; - type = 1; + var attr = FBXTree.Objects.subNodes.NodeAttribute[ childID ]; - } + if ( attr !== undefined && attr.properties !== undefined ) { - var nearClippingPlane = 1; - if ( cameraAttribute.NearPlane !== undefined ) { + cameraAttribute = attr.properties; - nearClippingPlane = cameraAttribute.NearPlane.value / 1000; + } - } + } - var farClippingPlane = 1000; - if ( cameraAttribute.FarPlane !== undefined ) { + if ( cameraAttribute === undefined ) { - farClippingPlane = cameraAttribute.FarPlane.value / 1000; + model = new THREE.Object3D(); - } + } else { + var type = 0; + if ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) { - var width = window.innerWidth; - var height = window.innerHeight; + type = 1; - if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) { + } - width = cameraAttribute.AspectWidth.value; - height = cameraAttribute.AspectHeight.value; + var nearClippingPlane = 1; + if ( cameraAttribute.NearPlane !== undefined ) { - } + nearClippingPlane = cameraAttribute.NearPlane.value / 1000; - var aspect = width / height; + } - var fov = 45; - if ( cameraAttribute.FieldOfView !== undefined ) { + var farClippingPlane = 1000; + if ( cameraAttribute.FarPlane !== undefined ) { - fov = cameraAttribute.FieldOfView.value; + farClippingPlane = cameraAttribute.FarPlane.value / 1000; - } + } - switch ( type ) { - case 0: // Perspective - model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane ); - break; + var width = window.innerWidth; + var height = window.innerHeight; - case 1: // Orthographic - model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane ); - break; + if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) { - default: - console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' ); - model = new THREE.Object3D(); - break; + width = cameraAttribute.AspectWidth.value; + height = cameraAttribute.AspectHeight.value; - } + } - } + var aspect = width / height; - break; + var fov = 45; + if ( cameraAttribute.FieldOfView !== undefined ) { + fov = cameraAttribute.FieldOfView.value; - // Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight - case 'Light': + } - var lightAttribute; + switch ( type ) { - for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { + case 0: // Perspective + model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane ); + break; - var childID = conns.children[ childrenIndex ].ID; + case 1: // Orthographic + model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane ); + break; - var attr = FBXTree.Objects.subNodes.NodeAttribute[ childID ]; + default: + console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' ); + model = new THREE.Object3D(); + break; - if ( attr !== undefined && attr.properties !== undefined ) { + } - lightAttribute = attr.properties; + } - } + return model; - } + } - if ( lightAttribute === undefined ) { + // Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight + function createLight( FBXTree, conns ) { - model = new THREE.Object3D(); + var model; + var lightAttribute; - } else { + for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { - var type; + var childID = conns.children[ childrenIndex ].ID; - // LightType can be undefined for Point lights - if ( lightAttribute.LightType === undefined ) { + var attr = FBXTree.Objects.subNodes.NodeAttribute[ childID ]; - type = 0; + if ( attr !== undefined && attr.properties !== undefined ) { - } else { + lightAttribute = attr.properties; - type = lightAttribute.LightType.value; + } - } + } - var color = 0xffffff; + if ( lightAttribute === undefined ) { - if ( lightAttribute.Color !== undefined ) { + model = new THREE.Object3D(); - color = parseColor( lightAttribute.Color ); + } else { - } + var type; - var intensity = ( lightAttribute.Intensity === undefined ) ? 1 : lightAttribute.Intensity.value / 100; + // LightType can be undefined for Point lights + if ( lightAttribute.LightType === undefined ) { - // light disabled - if ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) { + type = 0; - intensity = 0; + } else { - } + type = lightAttribute.LightType.value; - var distance = 0; - if ( lightAttribute.FarAttenuationEnd !== undefined ) { + } - if ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) { + var color = 0xffffff; - distance = 0; + if ( lightAttribute.Color !== undefined ) { - } else { + color = parseColor( lightAttribute.Color ); - distance = lightAttribute.FarAttenuationEnd.value / 1000; + } - } + var intensity = ( lightAttribute.Intensity === undefined ) ? 1 : lightAttribute.Intensity.value / 100; - } + // light disabled + if ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) { - // TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd? - var decay = 1; + intensity = 0; - switch ( type ) { + } - case 0: // Point - model = new THREE.PointLight( color, intensity, distance, decay ); - break; + var distance = 0; + if ( lightAttribute.FarAttenuationEnd !== undefined ) { - case 1: // Directional - model = new THREE.DirectionalLight( color, intensity ); - break; + if ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) { - case 2: // Spot - var angle = Math.PI / 3; + distance = 0; - if ( lightAttribute.InnerAngle !== undefined ) { + } else { - angle = THREE.Math.degToRad( lightAttribute.InnerAngle.value ); + distance = lightAttribute.FarAttenuationEnd.value / 1000; - } + } - var penumbra = 0; - if ( lightAttribute.OuterAngle !== undefined ) { + } - // TODO: this is not correct - FBX calculates outer and inner angle in degrees - // with OuterAngle > InnerAngle && OuterAngle <= Math.PI - // while three.js uses a penumbra between (0, 1) to attenuate the inner angle - penumbra = THREE.Math.degToRad( lightAttribute.OuterAngle.value ); - penumbra = Math.max( penumbra, 1 ); + // TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd? + var decay = 1; - } + switch ( type ) { - model = new THREE.SpotLight( color, intensity, distance, angle, penumbra, decay ); - break; + case 0: // Point + model = new THREE.PointLight( color, intensity, distance, decay ); + break; - default: - console.warn( 'THREE.FBXLoader: Unknown light type ' + lightAttribute.LightType.value + ', defaulting to a THREE.PointLight.' ); - model = new THREE.PointLight( color, intensity ); - break; + case 1: // Directional + model = new THREE.DirectionalLight( color, intensity ); + break; - } + case 2: // Spot + var angle = Math.PI / 3; - if ( lightAttribute.CastShadows !== undefined && lightAttribute.CastShadows.value === 1 ) { + if ( lightAttribute.InnerAngle !== undefined ) { - model.castShadow = true; + angle = THREE.Math.degToRad( lightAttribute.InnerAngle.value ); - } + } - } + var penumbra = 0; + if ( lightAttribute.OuterAngle !== undefined ) { - break; + // TODO: this is not correct - FBX calculates outer and inner angle in degrees + // with OuterAngle > InnerAngle && OuterAngle <= Math.PI + // while three.js uses a penumbra between (0, 1) to attenuate the inner angle + penumbra = THREE.Math.degToRad( lightAttribute.OuterAngle.value ); + penumbra = Math.max( penumbra, 1 ); - case 'Mesh': + } - var geometry = null; - var material = null; - var materials = []; + model = new THREE.SpotLight( color, intensity, distance, angle, penumbra, decay ); + break; - for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { + default: + console.warn( 'THREE.FBXLoader: Unknown light type ' + lightAttribute.LightType.value + ', defaulting to a THREE.PointLight.' ); + model = new THREE.PointLight( color, intensity ); + break; - var child = conns.children[ childrenIndex ]; + } - if ( geometryMap.has( child.ID ) ) { + if ( lightAttribute.CastShadows !== undefined && lightAttribute.CastShadows.value === 1 ) { - geometry = geometryMap.get( child.ID ); + model.castShadow = true; - } + } - if ( materialMap.has( child.ID ) ) { + } - materials.push( materialMap.get( child.ID ) ); + return model; - } + } - } - if ( materials.length > 1 ) { + function createMesh( FBXTree, conns, geometryMap, materialMap ) { - material = materials; + var model; + var geometry = null; + var material = null; + var materials = []; - } else if ( materials.length > 0 ) { + for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { - material = materials[ 0 ]; + var child = conns.children[ childrenIndex ]; - } else { + if ( geometryMap.has( child.ID ) ) { - material = new THREE.MeshPhongMaterial( { color: 0xcccccc } ); - materials.push( material ); + geometry = geometryMap.get( child.ID ); - } - if ( 'color' in geometry.attributes ) { + } - for ( var materialIndex = 0, numMaterials = materials.length; materialIndex < numMaterials; ++ materialIndex ) { + if ( materialMap.has( child.ID ) ) { - materials[ materialIndex ].vertexColors = THREE.VertexColors; + materials.push( materialMap.get( child.ID ) ); - } + } - } - if ( geometry.FBX_Deformer ) { + } + if ( materials.length > 1 ) { - for ( var materialsIndex = 0, materialsLength = materials.length; materialsIndex < materialsLength; ++ materialsIndex ) { + material = materials; - materials[ materialsIndex ].skinning = true; + } else if ( materials.length > 0 ) { - } - model = new THREE.SkinnedMesh( geometry, material ); + material = materials[ 0 ]; - } else { + } else { - model = new THREE.Mesh( geometry, material ); + material = new THREE.MeshPhongMaterial( { color: 0xcccccc } ); + materials.push( material ); - } - break; + } + if ( 'color' in geometry.attributes ) { - case 'NurbsCurve': - var geometry = null; + for ( var materialIndex = 0, numMaterials = materials.length; materialIndex < numMaterials; ++ materialIndex ) { - for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { + materials[ materialIndex ].vertexColors = THREE.VertexColors; - var child = conns.children[ childrenIndex ]; + } - if ( geometryMap.has( child.ID ) ) { + } + if ( geometry.FBX_Deformer ) { - geometry = geometryMap.get( child.ID ); + for ( var materialsIndex = 0, materialsLength = materials.length; materialsIndex < materialsLength; ++ materialsIndex ) { - } + materials[ materialsIndex ].skinning = true; - } + } - // FBX does not list materials for Nurbs lines, so we'll just put our own in here. - material = new THREE.LineBasicMaterial( { color: 0x3300ff, linewidth: 5 } ); - model = new THREE.Line( geometry, material ); - break; + model = new THREE.SkinnedMesh( geometry, material ); - default: - model = new THREE.Group(); - break; + } else { - } + model = new THREE.Mesh( geometry, material ); - } + } - model.name = THREE.PropertyBinding.sanitizeNodeName( node.attrName ); - model.FBX_ID = id; + return model; - modelArray.push( model ); - modelMap.set( id, model ); + } - } + function createCurve( conns, geometryMap ) { - for ( var modelArrayIndex = 0, modelArrayLength = modelArray.length; modelArrayIndex < modelArrayLength; ++ modelArrayIndex ) { + var geometry = null; - var model = modelArray[ modelArrayIndex ]; + for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { - var node = ModelNode[ model.FBX_ID ]; + var child = conns.children[ childrenIndex ]; - if ( 'Lcl_Translation' in node.properties ) { + if ( geometryMap.has( child.ID ) ) { - model.position.fromArray( node.properties.Lcl_Translation.value ); + geometry = geometryMap.get( child.ID ); } - if ( 'Lcl_Rotation' in node.properties ) { + } - var rotation = node.properties.Lcl_Rotation.value.map( THREE.Math.degToRad ); - rotation.push( 'ZYX' ); - model.rotation.fromArray( rotation ); + // FBX does not list materials for Nurbs lines, so we'll just put our own in here. + var material = new THREE.LineBasicMaterial( { color: 0x3300ff, linewidth: 1 } ); + return new THREE.Line( geometry, material ); - } + } + + // Parse ambient color in FBXTree.GlobalSettings.properties - if it's not set to black (default), create an ambient light + function createAmbientLight( FBXTree, sceneGraph ) { + + if ( 'GlobalSettings' in FBXTree && 'AmbientColor' in FBXTree.GlobalSettings.properties ) { + + var ambientColor = FBXTree.GlobalSettings.properties.AmbientColor.value; + var r = ambientColor[ 0 ]; + var g = ambientColor[ 1 ]; + var b = ambientColor[ 2 ]; - if ( 'Lcl_Scaling' in node.properties ) { + if ( r !== 0 || g !== 0 || b !== 0 ) { - model.scale.fromArray( node.properties.Lcl_Scaling.value ); + var color = new THREE.Color( r, g, b ); + sceneGraph.add( new THREE.AmbientLight( color, 1 ) ); } - if ( 'PreRotation' in node.properties ) { + } - var array = node.properties.PreRotation.value.map( THREE.Math.degToRad ); - array[ 3 ] = 'ZYX'; + } - var preRotations = new THREE.Euler().fromArray( array ); + // parse the model node for transform details and apply them to the model + function setModelTransforms( FBXTree, model, modelNode, connections, sceneGraph ) { - preRotations = new THREE.Quaternion().setFromEuler( preRotations ); - var currentRotation = new THREE.Quaternion().setFromEuler( model.rotation ); - preRotations.multiply( currentRotation ); - model.rotation.setFromQuaternion( preRotations, 'ZYX' ); + if ( 'Lcl_Translation' in modelNode.properties ) { - } + model.position.fromArray( modelNode.properties.Lcl_Translation.value ); - // allow transformed pivots - see https://github.com/mrdoob/three.js/issues/11895 - if ( 'GeometricTranslation' in node.properties ) { + } - var array = node.properties.GeometricTranslation.value; + if ( 'Lcl_Rotation' in modelNode.properties ) { - model.traverse( function ( child ) { + var rotation = modelNode.properties.Lcl_Rotation.value.map( THREE.Math.degToRad ); + rotation.push( 'ZYX' ); + model.rotation.fromArray( rotation ); - if ( child.geometry ) { + } - child.geometry.translate( array[ 0 ], array[ 1 ], array[ 2 ] ); + if ( 'Lcl_Scaling' in modelNode.properties ) { - } + model.scale.fromArray( modelNode.properties.Lcl_Scaling.value ); - } ); + } - } + if ( 'PreRotation' in modelNode.properties ) { - if ( 'LookAtProperty' in node.properties ) { + var array = modelNode.properties.PreRotation.value.map( THREE.Math.degToRad ); + array[ 3 ] = 'ZYX'; - var conns = connections.get( model.FBX_ID ); + var preRotations = new THREE.Euler().fromArray( array ); - for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { + preRotations = new THREE.Quaternion().setFromEuler( preRotations ); + var currentRotation = new THREE.Quaternion().setFromEuler( model.rotation ); + preRotations.multiply( currentRotation ); + model.rotation.setFromQuaternion( preRotations, 'ZYX' ); - var child = conns.children[ childrenIndex ]; + } - if ( child.relationship === 'LookAtProperty' ) { + // allow transformed pivots - see https://github.com/mrdoob/three.js/issues/11895 + if ( 'GeometricTranslation' in modelNode.properties ) { - var lookAtTarget = FBXTree.Objects.subNodes.Model[ child.ID ]; + var array = modelNode.properties.GeometricTranslation.value; - if ( 'Lcl_Translation' in lookAtTarget.properties ) { + model.traverse( function ( child ) { - var pos = lookAtTarget.properties.Lcl_Translation.value; + if ( child.geometry ) { - // DirectionalLight, SpotLight - if ( model.target !== undefined ) { + child.geometry.translate( array[ 0 ], array[ 1 ], array[ 2 ] ); - model.target.position.set( pos[ 0 ], pos[ 1 ], pos[ 2 ] ); - sceneGraph.add( model.target ); + } + } ); - } else { // Cameras and other Object3Ds + } - model.lookAt( new THREE.Vector3( pos[ 0 ], pos[ 1 ], pos[ 2 ] ) ); + if ( 'LookAtProperty' in modelNode.properties ) { - } + var conns = connections.get( model.FBX_ID ); - } + for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) { - } + var child = conns.children[ childrenIndex ]; - } + if ( child.relationship === 'LookAtProperty' ) { - } + var lookAtTarget = FBXTree.Objects.subNodes.Model[ child.ID ]; - var conns = connections.get( model.FBX_ID ); - for ( var parentIndex = 0; parentIndex < conns.parents.length; parentIndex ++ ) { + if ( 'Lcl_Translation' in lookAtTarget.properties ) { - var pIndex = findIndex( modelArray, function ( mod ) { + var pos = lookAtTarget.properties.Lcl_Translation.value; - return mod.FBX_ID === conns.parents[ parentIndex ].ID; + // DirectionalLight, SpotLight + if ( model.target !== undefined ) { - } ); - if ( pIndex > - 1 ) { + model.target.position.set( pos[ 0 ], pos[ 1 ], pos[ 2 ] ); + sceneGraph.add( model.target ); - modelArray[ pIndex ].add( model ); - break; - } + } else { // Cameras and other Object3Ds - } - if ( model.parent === null ) { + model.lookAt( new THREE.Vector3( pos[ 0 ], pos[ 1 ], pos[ 2 ] ) ); - sceneGraph.add( model ); + } + + } + + } } } + } + + function bindSkeleton( FBXTree, deformers, geometryMap, modelMap, connections, sceneGraph ) { // Now with the bones created, we can update the skeletons and bind them to the skinned meshes. sceneGraph.updateMatrixWorld( true ); @@ -2017,32 +2091,10 @@ // to attach animations to, since FBX treats animations as animations for the entire scene, // not just for individual objects. sceneGraph.skeleton = { - bones: modelArray - }; - - var animations = parseAnimations( FBXTree, connections, sceneGraph ); - - addAnimations( sceneGraph, animations ); - - - // Parse ambient color - if it's not set to black (default), create an ambient light - if ( 'GlobalSettings' in FBXTree && 'AmbientColor' in FBXTree.GlobalSettings.properties ) { - - var ambientColor = FBXTree.GlobalSettings.properties.AmbientColor.value; - var r = ambientColor[ 0 ]; - var g = ambientColor[ 1 ]; - var b = ambientColor[ 2 ]; - - if ( r !== 0 || g !== 0 || b !== 0 ) { - - var color = new THREE.Color( r, g, b ); - sceneGraph.add( new THREE.AmbientLight( color, 1 ) ); - } + bones: Array.from( modelMap.values() ), - } - - return sceneGraph; + }; } @@ -2410,7 +2462,7 @@ var model = rawModels[ returnObject.containerID.toString() ]; if ( 'PreRotation' in model.properties ) { - returnObject.preRotations = parseVector3( model.properties.PreRotation ).multiplyScalar( Math.PI / 180 ); + returnObject.preRotations = new THREE.Vector3().fromArray( model.properties.PreRotation.value ).multiplyScalar( Math.PI / 180 ); } break; @@ -2490,11 +2542,13 @@ } - function addAnimations( group, animations ) { + function addAnimations( FBXTree, connections, sceneGraph ) { + + var animations = parseAnimations( FBXTree, connections, sceneGraph ); - if ( group.animations === undefined ) { + if ( sceneGraph.animations === undefined ) { - group.animations = []; + sceneGraph.animations = []; } @@ -2511,7 +2565,7 @@ hierarchy: [] }; - var bones = group.skeleton.bones; + var bones = sceneGraph.skeleton.bones; for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) { @@ -2552,7 +2606,7 @@ } - group.animations.push( THREE.AnimationClip.parseAnimation( animationData, bones ) ); + sceneGraph.animations.push( THREE.AnimationClip.parseAnimation( animationData, bones ) ); } diff --git a/examples/webgl_shadowmap_pointlight.html b/examples/webgl_shadowmap_pointlight.html index d064d58fcab7ee358c3b6ef27e96a96cdd0f1b82..6869f633b290a429faaa2bc8da08cf6065092bad 100644 --- a/examples/webgl_shadowmap_pointlight.html +++ b/examples/webgl_shadowmap_pointlight.html @@ -83,8 +83,7 @@ var material = new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, alphaMap: texture, - alphaTest: 0.5, - transparent: true + alphaTest: 0.5 } ); var sphere = new THREE.Mesh( geometry, material );