Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Ablesons
three.js
提交
a1e574b5
T
three.js
项目概览
Ablesons
/
three.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
three.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
a1e574b5
编写于
8月 16, 2017
作者:
M
Mr.doob
提交者:
GitHub
8月 16, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #11961 from donmccurdy/feat-gltf2-merge
GLTF2Loader: Rename to GLTFLoader.
上级
f296313a
0548b13c
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
1146 addition
and
3361 deletion
+1146
-3361
docs/examples/loaders/GLTFLoader.html
docs/examples/loaders/GLTFLoader.html
+4
-4
docs/list.js
docs/list.js
+1
-1
docs/manual/introduction/Animation-system.html
docs/manual/introduction/Animation-system.html
+1
-1
editor/index.html
editor/index.html
+1
-1
editor/js/Loader.js
editor/js/Loader.js
+1
-1
examples/files.js
examples/files.js
+2
-2
examples/js/exporters/GLTFExporter.js
examples/js/exporters/GLTFExporter.js
+1
-1
examples/js/loaders/GLTF2Loader.js
examples/js/loaders/GLTF2Loader.js
+0
-2405
examples/js/loaders/GLTFLoader.js
examples/js/loaders/GLTFLoader.js
+1132
-942
examples/webgl_exporter_gltf.html
examples/webgl_exporter_gltf.html
+1
-1
examples/webgl_loader_gltf.html
examples/webgl_loader_gltf.html
+2
-2
未找到文件。
docs/examples/loaders/GLTF
2
Loader.html
→
docs/examples/loaders/GLTFLoader.html
浏览文件 @
a1e574b5
...
...
@@ -25,7 +25,7 @@
<h2>
Extensions
</h2>
<div>
GLTF
2
Loader supports the following glTF extensions:
GLTFLoader supports the following glTF extensions:
</div>
<ul>
...
...
@@ -49,7 +49,7 @@
<code>
// Instantiate a loader
var loader = new THREE.GLTF
2
Loader();
var loader = new THREE.GLTFLoader();
// Load a glTF resource
loader.load( 'models/gltf/duck/duck.gltf', function ( gltf ) {
...
...
@@ -62,7 +62,7 @@
} );
</code>
[example:webgl_loader_gltf
2
]
[example:webgl_loader_gltf]
<h2>
Constructor
</h2>
...
...
@@ -115,6 +115,6 @@
<h2>
Source
</h2>
[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/GLTF
2Loader.js examples/js/loaders/GLTF2
Loader.js]
[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/GLTF
Loader.js examples/js/loaders/GLTF
Loader.js]
</body>
</html>
docs/list.js
浏览文件 @
a1e574b5
...
...
@@ -341,7 +341,7 @@ var list = {
"
Loaders
"
:
{
"
BabylonLoader
"
:
"
examples/loaders/BabylonLoader
"
,
"
ColladaLoader
"
:
"
examples/loaders/ColladaLoader
"
,
"
GLTF
2Loader
"
:
"
examples/loaders/GLTF2
Loader
"
,
"
GLTF
Loader
"
:
"
examples/loaders/GLTF
Loader
"
,
"
MTLLoader
"
:
"
examples/loaders/MTLLoader
"
,
"
OBJLoader
"
:
"
examples/loaders/OBJLoader
"
,
"
OBJLoader2
"
:
"
examples/loaders/OBJLoader2
"
,
...
...
docs/manual/introduction/Animation-system.html
浏览文件 @
a1e574b5
...
...
@@ -111,7 +111,7 @@
<li>
[page:ObjectLoader THREE.ObjectLoader]
</li>
<li>
THREE.BVHLoader
</li>
<li>
THREE.FBXLoader
</li>
<li>
[page:GLTF
2Loader THREE.GLTF2
Loader]
</li>
<li>
[page:GLTF
Loader THREE.GLTF
Loader]
</li>
<li>
THREE.MMDLoader
</li>
<li>
THREE.SEA3DLoader
</li>
</ul>
...
...
editor/index.html
浏览文件 @
a1e574b5
...
...
@@ -23,7 +23,7 @@
<script
src=
"../examples/js/loaders/BabylonLoader.js"
></script>
<script
src=
"../examples/js/loaders/ColladaLoader2.js"
></script>
<script
src=
"../examples/js/loaders/FBXLoader.js"
></script>
<script
src=
"../examples/js/loaders/GLTF
2
Loader.js"
></script>
<script
src=
"../examples/js/loaders/GLTFLoader.js"
></script>
<script
src=
"../examples/js/loaders/KMZLoader.js"
></script>
<script
src=
"../examples/js/loaders/MD2Loader.js"
></script>
<script
src=
"../examples/js/loaders/OBJLoader.js"
></script>
...
...
editor/js/Loader.js
浏览文件 @
a1e574b5
...
...
@@ -176,7 +176,7 @@ var Loader = function ( editor ) {
var
contents
=
event
.
target
.
result
;
var
loader
=
new
THREE
.
GLTF
2
Loader
();
var
loader
=
new
THREE
.
GLTFLoader
();
loader
.
parse
(
contents
,
''
,
function
(
result
)
{
result
.
scene
.
name
=
filename
;
...
...
examples/files.js
浏览文件 @
a1e574b5
...
...
@@ -18,7 +18,7 @@ var files = {
"
webgl_effects_parallaxbarrier
"
,
"
webgl_effects_peppersghost
"
,
"
webgl_effects_stereo
"
,
"
webgl_exporter_gltf
2
"
,
"
webgl_exporter_gltf
"
,
"
webgl_exporter_obj
"
,
"
webgl_geometries
"
,
"
webgl_geometries2
"
,
...
...
@@ -92,7 +92,7 @@ var files = {
"
webgl_loader_ctm_materials
"
,
"
webgl_loader_draco
"
,
"
webgl_loader_fbx
"
,
"
webgl_loader_gltf
2
"
,
"
webgl_loader_gltf
"
,
"
webgl_loader_imagebitmap
"
,
"
webgl_loader_json_blender
"
,
"
webgl_loader_json_claraio
"
,
...
...
examples/js/exporters/GLTFExporter.js
浏览文件 @
a1e574b5
...
...
@@ -233,7 +233,7 @@ THREE.GLTFExporter.prototype = {
}
else
{
throw
new
Error
(
'
THREE.GLTF
2
Exporter: Unsupported bufferAttribute component type.
'
);
throw
new
Error
(
'
THREE.GLTFExporter: Unsupported bufferAttribute component type.
'
);
}
...
...
examples/js/loaders/GLTF2Loader.js
已删除
100644 → 0
浏览文件 @
f296313a
/**
* @author Rich Tibbett / https://github.com/richtr
* @author mrdoob / http://mrdoob.com/
* @author Tony Parisi / http://www.tonyparisi.com/
* @author Takahiro / https://github.com/takahirox
* @author Don McCurdy / https://www.donmccurdy.com
*/
THREE
.
GLTF2Loader
=
(
function
()
{
function
GLTF2Loader
(
manager
)
{
this
.
manager
=
(
manager
!==
undefined
)
?
manager
:
THREE
.
DefaultLoadingManager
;
}
GLTF2Loader
.
prototype
=
{
constructor
:
GLTF2Loader
,
crossOrigin
:
'
Anonymous
'
,
load
:
function
(
url
,
onLoad
,
onProgress
,
onError
)
{
var
scope
=
this
;
var
path
=
this
.
path
&&
(
typeof
this
.
path
===
'
string
'
)
?
this
.
path
:
THREE
.
Loader
.
prototype
.
extractUrlBase
(
url
);
var
loader
=
new
THREE
.
FileLoader
(
scope
.
manager
);
loader
.
setResponseType
(
'
arraybuffer
'
);
loader
.
load
(
url
,
function
(
data
)
{
try
{
scope
.
parse
(
data
,
path
,
onLoad
,
onError
);
}
catch
(
e
)
{
// For SyntaxError or TypeError, return a generic failure message.
onError
(
e
.
constructor
===
Error
?
e
:
new
Error
(
'
THREE.GLTF2Loader: Unable to parse model.
'
)
);
}
},
onProgress
,
onError
);
},
setCrossOrigin
:
function
(
value
)
{
this
.
crossOrigin
=
value
;
},
setPath
:
function
(
value
)
{
this
.
path
=
value
;
},
parse
:
function
(
data
,
path
,
onLoad
,
onError
)
{
var
content
;
var
extensions
=
{};
var
magic
=
convertUint8ArrayToString
(
new
Uint8Array
(
data
,
0
,
4
)
);
if
(
magic
===
BINARY_EXTENSION_HEADER_MAGIC
)
{
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
]
=
new
GLTFBinaryExtension
(
data
);
content
=
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
content
;
}
else
{
content
=
convertUint8ArrayToString
(
new
Uint8Array
(
data
)
);
}
var
json
=
JSON
.
parse
(
content
);
if
(
json
.
asset
===
undefined
||
json
.
asset
.
version
[
0
]
<
2
)
{
onError
(
new
Error
(
'
THREE.GLTF2Loader: Legacy glTF detected. Use THREE.GLTFLoader instead.
'
)
);
return
;
}
if
(
json
.
extensionsUsed
)
{
if
(
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_LIGHTS
)
>=
0
)
{
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
=
new
GLTFLightsExtension
(
json
);
}
if
(
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_MATERIALS_COMMON
)
>=
0
)
{
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
=
new
GLTFMaterialsCommonExtension
(
json
);
}
if
(
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
)
>=
0
)
{
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
]
=
new
GLTFMaterialsPbrSpecularGlossinessExtension
();
}
}
console
.
time
(
'
GLTF2Loader
'
);
var
parser
=
new
GLTFParser
(
json
,
extensions
,
{
path
:
path
||
this
.
path
,
crossOrigin
:
this
.
crossOrigin
}
);
parser
.
parse
(
function
(
scene
,
scenes
,
cameras
,
animations
)
{
console
.
timeEnd
(
'
GLTF2Loader
'
);
var
glTF
=
{
scene
:
scene
,
scenes
:
scenes
,
cameras
:
cameras
,
animations
:
animations
};
onLoad
(
glTF
);
},
onError
);
}
};
/* GLTFREGISTRY */
function
GLTFRegistry
()
{
var
objects
=
{};
return
{
get
:
function
(
key
)
{
return
objects
[
key
];
},
add
:
function
(
key
,
object
)
{
objects
[
key
]
=
object
;
},
remove
:
function
(
key
)
{
delete
objects
[
key
];
},
removeAll
:
function
()
{
objects
=
{};
},
update
:
function
(
scene
,
camera
)
{
for
(
var
name
in
objects
)
{
var
object
=
objects
[
name
];
if
(
object
.
update
)
{
object
.
update
(
scene
,
camera
);
}
}
}
};
}
/*********************************/
/********** EXTENSIONS ***********/
/*********************************/
var
EXTENSIONS
=
{
KHR_BINARY_GLTF
:
'
KHR_binary_glTF
'
,
KHR_LIGHTS
:
'
KHR_lights
'
,
KHR_MATERIALS_COMMON
:
'
KHR_materials_common
'
,
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
:
'
KHR_materials_pbrSpecularGlossiness
'
};
/**
* Lights Extension
*
* Specification: PENDING
*/
function
GLTFLightsExtension
(
json
)
{
this
.
name
=
EXTENSIONS
.
KHR_LIGHTS
;
this
.
lights
=
{};
var
extension
=
(
json
.
extensions
&&
json
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
)
||
{};
var
lights
=
extension
.
lights
||
{};
for
(
var
lightId
in
lights
)
{
var
light
=
lights
[
lightId
];
var
lightNode
;
var
color
=
new
THREE
.
Color
().
fromArray
(
light
.
color
);
switch
(
light
.
type
)
{
case
'
directional
'
:
lightNode
=
new
THREE
.
DirectionalLight
(
color
);
lightNode
.
position
.
set
(
0
,
0
,
1
);
break
;
case
'
point
'
:
lightNode
=
new
THREE
.
PointLight
(
color
);
break
;
case
'
spot
'
:
lightNode
=
new
THREE
.
SpotLight
(
color
);
lightNode
.
position
.
set
(
0
,
0
,
1
);
break
;
case
'
ambient
'
:
lightNode
=
new
THREE
.
AmbientLight
(
color
);
break
;
}
if
(
lightNode
)
{
if
(
light
.
constantAttenuation
!==
undefined
)
{
lightNode
.
intensity
=
light
.
constantAttenuation
;
}
if
(
light
.
linearAttenuation
!==
undefined
)
{
lightNode
.
distance
=
1
/
light
.
linearAttenuation
;
}
if
(
light
.
quadraticAttenuation
!==
undefined
)
{
lightNode
.
decay
=
light
.
quadraticAttenuation
;
}
if
(
light
.
fallOffAngle
!==
undefined
)
{
lightNode
.
angle
=
light
.
fallOffAngle
;
}
if
(
light
.
fallOffExponent
!==
undefined
)
{
console
.
warn
(
'
THREE.GLTF2Loader:: light.fallOffExponent not currently supported.
'
);
}
lightNode
.
name
=
light
.
name
||
(
'
light_
'
+
lightId
);
this
.
lights
[
lightId
]
=
lightNode
;
}
}
}
/**
* Common Materials Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_common
*/
function
GLTFMaterialsCommonExtension
(
json
)
{
this
.
name
=
EXTENSIONS
.
KHR_MATERIALS_COMMON
;
}
GLTFMaterialsCommonExtension
.
prototype
.
getMaterialType
=
function
(
material
)
{
var
khrMaterial
=
material
.
extensions
[
this
.
name
];
switch
(
khrMaterial
.
type
)
{
case
'
commonBlinn
'
:
case
'
commonPhong
'
:
return
THREE
.
MeshPhongMaterial
;
case
'
commonLambert
'
:
return
THREE
.
MeshLambertMaterial
;
case
'
commonConstant
'
:
default
:
return
THREE
.
MeshBasicMaterial
;
}
};
GLTFMaterialsCommonExtension
.
prototype
.
extendParams
=
function
(
materialParams
,
material
,
parser
)
{
var
khrMaterial
=
material
.
extensions
[
this
.
name
];
var
pending
=
[];
var
keys
=
[];
// TODO: Currently ignored: 'ambientFactor', 'ambientTexture'
switch
(
khrMaterial
.
type
)
{
case
'
commonBlinn
'
:
case
'
commonPhong
'
:
keys
.
push
(
'
diffuseFactor
'
,
'
diffuseTexture
'
,
'
specularFactor
'
,
'
specularTexture
'
,
'
shininessFactor
'
);
break
;
case
'
commonLambert
'
:
keys
.
push
(
'
diffuseFactor
'
,
'
diffuseTexture
'
);
break
;
case
'
commonConstant
'
:
default
:
break
;
}
var
materialValues
=
{};
keys
.
forEach
(
function
(
v
)
{
if
(
khrMaterial
[
v
]
!==
undefined
)
materialValues
[
v
]
=
khrMaterial
[
v
];
}
);
if
(
materialValues
.
diffuseFactor
!==
undefined
)
{
materialParams
.
color
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
diffuseFactor
);
materialParams
.
opacity
=
materialValues
.
diffuseFactor
[
3
];
}
if
(
materialValues
.
diffuseTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
map
'
,
materialValues
.
diffuseTexture
.
index
)
);
}
if
(
materialValues
.
specularFactor
!==
undefined
)
{
materialParams
.
specular
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
specularFactor
);
}
if
(
materialValues
.
specularTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
specularMap
'
,
materialValues
.
specularTexture
.
index
)
);
}
if
(
materialValues
.
shininessFactor
!==
undefined
)
{
materialParams
.
shininess
=
materialValues
.
shininessFactor
;
}
return
Promise
.
all
(
pending
);
};
/* BINARY EXTENSION */
var
BINARY_EXTENSION_BUFFER_NAME
=
'
binary_glTF
'
;
var
BINARY_EXTENSION_HEADER_MAGIC
=
'
glTF
'
;
var
BINARY_EXTENSION_HEADER_LENGTH
=
12
;
var
BINARY_EXTENSION_CHUNK_TYPES
=
{
JSON
:
0x4E4F534A
,
BIN
:
0x004E4942
};
function
GLTFBinaryExtension
(
data
)
{
this
.
name
=
EXTENSIONS
.
KHR_BINARY_GLTF
;
this
.
content
=
null
;
this
.
body
=
null
;
var
headerView
=
new
DataView
(
data
,
0
,
BINARY_EXTENSION_HEADER_LENGTH
);
this
.
header
=
{
magic
:
convertUint8ArrayToString
(
new
Uint8Array
(
data
.
slice
(
0
,
4
)
)
),
version
:
headerView
.
getUint32
(
4
,
true
),
length
:
headerView
.
getUint32
(
8
,
true
)
};
if
(
this
.
header
.
magic
!==
BINARY_EXTENSION_HEADER_MAGIC
)
{
throw
new
Error
(
'
THREE.GLTF2Loader: Unsupported glTF-Binary header.
'
);
}
else
if
(
this
.
header
.
version
<
2.0
)
{
throw
new
Error
(
'
THREE.GLTF2Loader: Legacy binary file detected. Use GLTFLoader instead.
'
);
}
var
chunkView
=
new
DataView
(
data
,
BINARY_EXTENSION_HEADER_LENGTH
);
var
chunkIndex
=
0
;
while
(
chunkIndex
<
chunkView
.
byteLength
)
{
var
chunkLength
=
chunkView
.
getUint32
(
chunkIndex
,
true
);
chunkIndex
+=
4
;
var
chunkType
=
chunkView
.
getUint32
(
chunkIndex
,
true
);
chunkIndex
+=
4
;
if
(
chunkType
===
BINARY_EXTENSION_CHUNK_TYPES
.
JSON
)
{
var
contentArray
=
new
Uint8Array
(
data
,
BINARY_EXTENSION_HEADER_LENGTH
+
chunkIndex
,
chunkLength
);
this
.
content
=
convertUint8ArrayToString
(
contentArray
);
}
else
if
(
chunkType
===
BINARY_EXTENSION_CHUNK_TYPES
.
BIN
)
{
var
byteOffset
=
BINARY_EXTENSION_HEADER_LENGTH
+
chunkIndex
;
this
.
body
=
data
.
slice
(
byteOffset
,
byteOffset
+
chunkLength
);
}
// Clients must ignore chunks with unknown types.
chunkIndex
+=
chunkLength
;
}
if
(
this
.
content
===
null
)
{
throw
new
Error
(
'
THREE.GLTF2Loader: JSON content not found.
'
);
}
}
/**
* Specular-Glossiness Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_pbrSpecularGlossiness
*/
function
GLTFMaterialsPbrSpecularGlossinessExtension
()
{
return
{
name
:
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
,
getMaterialType
:
function
()
{
return
THREE
.
ShaderMaterial
;
},
extendParams
:
function
(
params
,
material
,
parser
)
{
var
pbrSpecularGlossiness
=
material
.
extensions
[
this
.
name
];
var
shader
=
THREE
.
ShaderLib
[
'
standard
'
];
var
uniforms
=
THREE
.
UniformsUtils
.
clone
(
shader
.
uniforms
);
var
specularMapParsFragmentChunk
=
[
'
#ifdef USE_SPECULARMAP
'
,
'
uniform sampler2D specularMap;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
glossinessMapParsFragmentChunk
=
[
'
#ifdef USE_GLOSSINESSMAP
'
,
'
uniform sampler2D glossinessMap;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
specularMapFragmentChunk
=
[
'
vec3 specularFactor = specular;
'
,
'
#ifdef USE_SPECULARMAP
'
,
'
vec4 texelSpecular = texture2D( specularMap, vUv );
'
,
'
// reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture
'
,
'
specularFactor *= texelSpecular.rgb;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
glossinessMapFragmentChunk
=
[
'
float glossinessFactor = glossiness;
'
,
'
#ifdef USE_GLOSSINESSMAP
'
,
'
vec4 texelGlossiness = texture2D( glossinessMap, vUv );
'
,
'
// reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture
'
,
'
glossinessFactor *= texelGlossiness.a;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
lightPhysicalFragmentChunk
=
[
'
PhysicalMaterial material;
'
,
'
material.diffuseColor = diffuseColor.rgb;
'
,
'
material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );
'
,
'
material.specularColor = specularFactor.rgb;
'
,
].
join
(
'
\n
'
);
var
fragmentShader
=
shader
.
fragmentShader
.
replace
(
'
#include <specularmap_fragment>
'
,
''
)
.
replace
(
'
uniform float roughness;
'
,
'
uniform vec3 specular;
'
)
.
replace
(
'
uniform float metalness;
'
,
'
uniform float glossiness;
'
)
.
replace
(
'
#include <roughnessmap_pars_fragment>
'
,
specularMapParsFragmentChunk
)
.
replace
(
'
#include <metalnessmap_pars_fragment>
'
,
glossinessMapParsFragmentChunk
)
.
replace
(
'
#include <roughnessmap_fragment>
'
,
specularMapFragmentChunk
)
.
replace
(
'
#include <metalnessmap_fragment>
'
,
glossinessMapFragmentChunk
)
.
replace
(
'
#include <lights_physical_fragment>
'
,
lightPhysicalFragmentChunk
);
delete
uniforms
.
roughness
;
delete
uniforms
.
metalness
;
delete
uniforms
.
roughnessMap
;
delete
uniforms
.
metalnessMap
;
uniforms
.
specular
=
{
value
:
new
THREE
.
Color
().
setHex
(
0x111111
)
};
uniforms
.
glossiness
=
{
value
:
0.5
};
uniforms
.
specularMap
=
{
value
:
null
};
uniforms
.
glossinessMap
=
{
value
:
null
};
params
.
vertexShader
=
shader
.
vertexShader
;
params
.
fragmentShader
=
fragmentShader
;
params
.
uniforms
=
uniforms
;
params
.
defines
=
{
'
STANDARD
'
:
''
};
params
.
color
=
new
THREE
.
Color
(
1.0
,
1.0
,
1.0
);
params
.
opacity
=
1.0
;
var
pending
=
[];
if
(
Array
.
isArray
(
pbrSpecularGlossiness
.
diffuseFactor
)
)
{
var
array
=
pbrSpecularGlossiness
.
diffuseFactor
;
params
.
color
.
fromArray
(
array
);
params
.
opacity
=
array
[
3
];
}
if
(
pbrSpecularGlossiness
.
diffuseTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
params
,
'
map
'
,
pbrSpecularGlossiness
.
diffuseTexture
.
index
)
);
}
params
.
emissive
=
new
THREE
.
Color
(
0.0
,
0.0
,
0.0
);
params
.
glossiness
=
pbrSpecularGlossiness
.
glossinessFactor
!==
undefined
?
pbrSpecularGlossiness
.
glossinessFactor
:
1.0
;
params
.
specular
=
new
THREE
.
Color
(
1.0
,
1.0
,
1.0
);
if
(
Array
.
isArray
(
pbrSpecularGlossiness
.
specularFactor
)
)
{
params
.
specular
.
fromArray
(
pbrSpecularGlossiness
.
specularFactor
);
}
if
(
pbrSpecularGlossiness
.
specularGlossinessTexture
!==
undefined
)
{
var
specGlossIndex
=
pbrSpecularGlossiness
.
specularGlossinessTexture
.
index
;
pending
.
push
(
parser
.
assignTexture
(
params
,
'
glossinessMap
'
,
specGlossIndex
)
);
pending
.
push
(
parser
.
assignTexture
(
params
,
'
specularMap
'
,
specGlossIndex
)
);
}
return
Promise
.
all
(
pending
);
},
createMaterial
:
function
(
params
)
{
// setup material properties based on MeshStandardMaterial for Specular-Glossiness
var
material
=
new
THREE
.
ShaderMaterial
(
{
defines
:
params
.
defines
,
vertexShader
:
params
.
vertexShader
,
fragmentShader
:
params
.
fragmentShader
,
uniforms
:
params
.
uniforms
,
fog
:
true
,
lights
:
true
,
opacity
:
params
.
opacity
,
transparent
:
params
.
transparent
}
);
material
.
isGLTFSpecularGlossinessMaterial
=
true
;
material
.
color
=
params
.
color
;
material
.
map
=
params
.
map
===
undefined
?
null
:
params
.
map
;
material
.
lightMap
=
null
;
material
.
lightMapIntensity
=
1.0
;
material
.
aoMap
=
params
.
aoMap
===
undefined
?
null
:
params
.
aoMap
;
material
.
aoMapIntensity
=
1.0
;
material
.
emissive
=
params
.
emissive
;
material
.
emissiveIntensity
=
1.0
;
material
.
emissiveMap
=
params
.
emissiveMap
===
undefined
?
null
:
params
.
emissiveMap
;
material
.
bumpMap
=
params
.
bumpMap
===
undefined
?
null
:
params
.
bumpMap
;
material
.
bumpScale
=
1
;
material
.
normalMap
=
params
.
normalMap
===
undefined
?
null
:
params
.
normalMap
;
material
.
normalScale
=
new
THREE
.
Vector2
(
1
,
1
);
material
.
displacementMap
=
null
;
material
.
displacementScale
=
1
;
material
.
displacementBias
=
0
;
material
.
specularMap
=
params
.
specularMap
===
undefined
?
null
:
params
.
specularMap
;
material
.
specular
=
params
.
specular
;
material
.
glossinessMap
=
params
.
glossinessMap
===
undefined
?
null
:
params
.
glossinessMap
;
material
.
glossiness
=
params
.
glossiness
;
material
.
alphaMap
=
null
;
material
.
envMap
=
params
.
envMap
===
undefined
?
null
:
params
.
envMap
;
material
.
envMapIntensity
=
1.0
;
material
.
refractionRatio
=
0.98
;
material
.
extensions
.
derivatives
=
true
;
return
material
;
},
// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.
refreshUniforms
:
function
(
renderer
,
scene
,
camera
,
geometry
,
material
,
group
)
{
var
uniforms
=
material
.
uniforms
;
var
defines
=
material
.
defines
;
uniforms
.
opacity
.
value
=
material
.
opacity
;
uniforms
.
diffuse
.
value
.
copy
(
material
.
color
);
uniforms
.
emissive
.
value
.
copy
(
material
.
emissive
).
multiplyScalar
(
material
.
emissiveIntensity
);
uniforms
.
map
.
value
=
material
.
map
;
uniforms
.
specularMap
.
value
=
material
.
specularMap
;
uniforms
.
alphaMap
.
value
=
material
.
alphaMap
;
uniforms
.
lightMap
.
value
=
material
.
lightMap
;
uniforms
.
lightMapIntensity
.
value
=
material
.
lightMapIntensity
;
uniforms
.
aoMap
.
value
=
material
.
aoMap
;
uniforms
.
aoMapIntensity
.
value
=
material
.
aoMapIntensity
;
// uv repeat and offset setting priorities
// 1. color map
// 2. specular map
// 3. normal map
// 4. bump map
// 5. alpha map
// 6. emissive map
var
uvScaleMap
;
if
(
material
.
map
)
{
uvScaleMap
=
material
.
map
;
}
else
if
(
material
.
specularMap
)
{
uvScaleMap
=
material
.
specularMap
;
}
else
if
(
material
.
displacementMap
)
{
uvScaleMap
=
material
.
displacementMap
;
}
else
if
(
material
.
normalMap
)
{
uvScaleMap
=
material
.
normalMap
;
}
else
if
(
material
.
bumpMap
)
{
uvScaleMap
=
material
.
bumpMap
;
}
else
if
(
material
.
glossinessMap
)
{
uvScaleMap
=
material
.
glossinessMap
;
}
else
if
(
material
.
alphaMap
)
{
uvScaleMap
=
material
.
alphaMap
;
}
else
if
(
material
.
emissiveMap
)
{
uvScaleMap
=
material
.
emissiveMap
;
}
if
(
uvScaleMap
!==
undefined
)
{
// backwards compatibility
if
(
uvScaleMap
.
isWebGLRenderTarget
)
{
uvScaleMap
=
uvScaleMap
.
texture
;
}
var
offset
=
uvScaleMap
.
offset
;
var
repeat
=
uvScaleMap
.
repeat
;
uniforms
.
offsetRepeat
.
value
.
set
(
offset
.
x
,
offset
.
y
,
repeat
.
x
,
repeat
.
y
);
}
uniforms
.
envMap
.
value
=
material
.
envMap
;
uniforms
.
envMapIntensity
.
value
=
material
.
envMapIntensity
;
uniforms
.
flipEnvMap
.
value
=
(
material
.
envMap
&&
material
.
envMap
.
isCubeTexture
)
?
-
1
:
1
;
uniforms
.
refractionRatio
.
value
=
material
.
refractionRatio
;
uniforms
.
specular
.
value
.
copy
(
material
.
specular
);
uniforms
.
glossiness
.
value
=
material
.
glossiness
;
uniforms
.
glossinessMap
.
value
=
material
.
glossinessMap
;
uniforms
.
emissiveMap
.
value
=
material
.
emissiveMap
;
uniforms
.
bumpMap
.
value
=
material
.
bumpMap
;
uniforms
.
normalMap
.
value
=
material
.
normalMap
;
uniforms
.
displacementMap
.
value
=
material
.
displacementMap
;
uniforms
.
displacementScale
.
value
=
material
.
displacementScale
;
uniforms
.
displacementBias
.
value
=
material
.
displacementBias
;
if
(
uniforms
.
glossinessMap
.
value
!==
null
&&
defines
.
USE_GLOSSINESSMAP
===
undefined
)
{
defines
.
USE_GLOSSINESSMAP
=
''
;
// set USE_ROUGHNESSMAP to enable vUv
defines
.
USE_ROUGHNESSMAP
=
''
;
}
if
(
uniforms
.
glossinessMap
.
value
===
null
&&
defines
.
USE_GLOSSINESSMAP
!==
undefined
)
{
delete
defines
.
USE_GLOSSINESSMAP
;
delete
defines
.
USE_ROUGHNESSMAP
;
}
}
};
}
/*********************************/
/********** INTERNALS ************/
/*********************************/
/* CONSTANTS */
var
WEBGL_CONSTANTS
=
{
FLOAT
:
5126
,
//FLOAT_MAT2: 35674,
FLOAT_MAT3
:
35675
,
FLOAT_MAT4
:
35676
,
FLOAT_VEC2
:
35664
,
FLOAT_VEC3
:
35665
,
FLOAT_VEC4
:
35666
,
LINEAR
:
9729
,
REPEAT
:
10497
,
SAMPLER_2D
:
35678
,
POINTS
:
0
,
LINES
:
1
,
LINE_LOOP
:
2
,
LINE_STRIP
:
3
,
TRIANGLES
:
4
,
TRIANGLE_STRIP
:
5
,
TRIANGLE_FAN
:
6
,
UNSIGNED_BYTE
:
5121
,
UNSIGNED_SHORT
:
5123
};
var
WEBGL_TYPE
=
{
5126
:
Number
,
//35674: THREE.Matrix2,
35675
:
THREE
.
Matrix3
,
35676
:
THREE
.
Matrix4
,
35664
:
THREE
.
Vector2
,
35665
:
THREE
.
Vector3
,
35666
:
THREE
.
Vector4
,
35678
:
THREE
.
Texture
};
var
WEBGL_COMPONENT_TYPES
=
{
5120
:
Int8Array
,
5121
:
Uint8Array
,
5122
:
Int16Array
,
5123
:
Uint16Array
,
5125
:
Uint32Array
,
5126
:
Float32Array
};
var
WEBGL_FILTERS
=
{
9728
:
THREE
.
NearestFilter
,
9729
:
THREE
.
LinearFilter
,
9984
:
THREE
.
NearestMipMapNearestFilter
,
9985
:
THREE
.
LinearMipMapNearestFilter
,
9986
:
THREE
.
NearestMipMapLinearFilter
,
9987
:
THREE
.
LinearMipMapLinearFilter
};
var
WEBGL_WRAPPINGS
=
{
33071
:
THREE
.
ClampToEdgeWrapping
,
33648
:
THREE
.
MirroredRepeatWrapping
,
10497
:
THREE
.
RepeatWrapping
};
var
WEBGL_TEXTURE_FORMATS
=
{
6406
:
THREE
.
AlphaFormat
,
6407
:
THREE
.
RGBFormat
,
6408
:
THREE
.
RGBAFormat
,
6409
:
THREE
.
LuminanceFormat
,
6410
:
THREE
.
LuminanceAlphaFormat
};
var
WEBGL_TEXTURE_DATATYPES
=
{
5121
:
THREE
.
UnsignedByteType
,
32819
:
THREE
.
UnsignedShort4444Type
,
32820
:
THREE
.
UnsignedShort5551Type
,
33635
:
THREE
.
UnsignedShort565Type
};
var
WEBGL_SIDES
=
{
1028
:
THREE
.
BackSide
,
// Culling front
1029
:
THREE
.
FrontSide
// Culling back
//1032: THREE.NoSide // Culling front and back, what to do?
};
var
WEBGL_DEPTH_FUNCS
=
{
512
:
THREE
.
NeverDepth
,
513
:
THREE
.
LessDepth
,
514
:
THREE
.
EqualDepth
,
515
:
THREE
.
LessEqualDepth
,
516
:
THREE
.
GreaterEqualDepth
,
517
:
THREE
.
NotEqualDepth
,
518
:
THREE
.
GreaterEqualDepth
,
519
:
THREE
.
AlwaysDepth
};
var
WEBGL_BLEND_EQUATIONS
=
{
32774
:
THREE
.
AddEquation
,
32778
:
THREE
.
SubtractEquation
,
32779
:
THREE
.
ReverseSubtractEquation
};
var
WEBGL_BLEND_FUNCS
=
{
0
:
THREE
.
ZeroFactor
,
1
:
THREE
.
OneFactor
,
768
:
THREE
.
SrcColorFactor
,
769
:
THREE
.
OneMinusSrcColorFactor
,
770
:
THREE
.
SrcAlphaFactor
,
771
:
THREE
.
OneMinusSrcAlphaFactor
,
772
:
THREE
.
DstAlphaFactor
,
773
:
THREE
.
OneMinusDstAlphaFactor
,
774
:
THREE
.
DstColorFactor
,
775
:
THREE
.
OneMinusDstColorFactor
,
776
:
THREE
.
SrcAlphaSaturateFactor
// The followings are not supported by Three.js yet
//32769: CONSTANT_COLOR,
//32770: ONE_MINUS_CONSTANT_COLOR,
//32771: CONSTANT_ALPHA,
//32772: ONE_MINUS_CONSTANT_COLOR
};
var
WEBGL_TYPE_SIZES
=
{
'
SCALAR
'
:
1
,
'
VEC2
'
:
2
,
'
VEC3
'
:
3
,
'
VEC4
'
:
4
,
'
MAT2
'
:
4
,
'
MAT3
'
:
9
,
'
MAT4
'
:
16
};
var
PATH_PROPERTIES
=
{
scale
:
'
scale
'
,
translation
:
'
position
'
,
rotation
:
'
quaternion
'
,
weights
:
'
morphTargetInfluences
'
};
var
INTERPOLATION
=
{
CATMULLROMSPLINE
:
THREE
.
InterpolateSmooth
,
CUBICSPLINE
:
THREE
.
InterpolateSmooth
,
LINEAR
:
THREE
.
InterpolateLinear
,
STEP
:
THREE
.
InterpolateDiscrete
};
var
STATES_ENABLES
=
{
2884
:
'
CULL_FACE
'
,
2929
:
'
DEPTH_TEST
'
,
3042
:
'
BLEND
'
,
3089
:
'
SCISSOR_TEST
'
,
32823
:
'
POLYGON_OFFSET_FILL
'
,
32926
:
'
SAMPLE_ALPHA_TO_COVERAGE
'
};
var
ALPHA_MODES
=
{
OPAQUE
:
'
OPAQUE
'
,
MASK
:
'
MASK
'
,
BLEND
:
'
BLEND
'
};
/* UTILITY FUNCTIONS */
function
_each
(
object
,
callback
,
thisObj
)
{
if
(
!
object
)
{
return
Promise
.
resolve
();
}
var
results
;
var
fns
=
[];
if
(
Object
.
prototype
.
toString
.
call
(
object
)
===
'
[object Array]
'
)
{
results
=
[];
var
length
=
object
.
length
;
for
(
var
idx
=
0
;
idx
<
length
;
idx
++
)
{
var
value
=
callback
.
call
(
thisObj
||
this
,
object
[
idx
],
idx
);
if
(
value
)
{
fns
.
push
(
value
);
if
(
value
instanceof
Promise
)
{
value
.
then
(
function
(
key
,
value
)
{
results
[
key
]
=
value
;
}.
bind
(
this
,
idx
));
}
else
{
results
[
idx
]
=
value
;
}
}
}
}
else
{
results
=
{};
for
(
var
key
in
object
)
{
if
(
object
.
hasOwnProperty
(
key
)
)
{
var
value
=
callback
.
call
(
thisObj
||
this
,
object
[
key
],
key
);
if
(
value
)
{
fns
.
push
(
value
);
if
(
value
instanceof
Promise
)
{
value
.
then
(
function
(
key
,
value
)
{
results
[
key
]
=
value
;
}.
bind
(
this
,
key
));
}
else
{
results
[
key
]
=
value
;
}
}
}
}
}
return
Promise
.
all
(
fns
).
then
(
function
()
{
return
results
;
});
}
function
resolveURL
(
url
,
path
)
{
// Invalid URL
if
(
typeof
url
!==
'
string
'
||
url
===
''
)
return
''
;
// Absolute URL http://,https://,//
if
(
/^
(
https
?
:
)?\/\/
/i
.
test
(
url
)
)
{
return
url
;
}
// Data URI
if
(
/^data:.*,.*$/i
.
test
(
url
)
)
{
return
url
;
}
// Blob URL
if
(
/^blob:.*$/i
.
test
(
url
)
)
{
return
url
;
}
// Relative URL
return
(
path
||
''
)
+
url
;
}
function
convertUint8ArrayToString
(
array
)
{
if
(
window
.
TextDecoder
!==
undefined
)
{
return
new
TextDecoder
().
decode
(
array
);
}
// Avoid the String.fromCharCode.apply(null, array) shortcut, which
// throws a "maximum call stack size exceeded" error for large arrays.
var
s
=
''
;
for
(
var
i
=
0
,
il
=
array
.
length
;
i
<
il
;
i
++
)
{
s
+=
String
.
fromCharCode
(
array
[
i
]
);
}
return
s
;
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
*/
function
createDefaultMaterial
()
{
return
new
THREE
.
MeshStandardMaterial
(
{
color
:
0xFFFFFF
,
emissive
:
0x000000
,
metalness
:
1
,
roughness
:
1
,
transparent
:
false
,
depthTest
:
true
,
side
:
THREE
.
FrontSide
}
);
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
* @param {THREE.Mesh} mesh
* @param {GLTF.Mesh} meshDef
* @param {GLTF.Primitive} primitiveDef
* @param {Object} dependencies
*/
function
addMorphTargets
(
mesh
,
meshDef
,
primitiveDef
,
dependencies
)
{
var
geometry
=
mesh
.
geometry
;
var
material
=
mesh
.
material
;
var
targets
=
primitiveDef
.
targets
;
var
morphAttributes
=
geometry
.
morphAttributes
;
morphAttributes
.
position
=
[];
morphAttributes
.
normal
=
[];
material
.
morphTargets
=
true
;
for
(
var
i
=
0
,
il
=
targets
.
length
;
i
<
il
;
i
++
)
{
var
target
=
targets
[
i
];
var
attributeName
=
'
morphTarget
'
+
i
;
var
positionAttribute
,
normalAttribute
;
if
(
target
.
POSITION
!==
undefined
)
{
// Three.js morph formula is
// position
// + weight0 * ( morphTarget0 - position )
// + weight1 * ( morphTarget1 - position )
// ...
// while the glTF one is
// position
// + weight0 * morphTarget0
// + weight1 * morphTarget1
// ...
// then adding position to morphTarget.
// So morphTarget value will depend on mesh's position, then cloning attribute
// for the case if attribute is shared among two or more meshes.
positionAttribute
=
dependencies
.
accessors
[
target
.
POSITION
].
clone
();
var
position
=
geometry
.
attributes
.
position
;
for
(
var
j
=
0
,
jl
=
positionAttribute
.
count
;
j
<
jl
;
j
++
)
{
positionAttribute
.
setXYZ
(
j
,
positionAttribute
.
getX
(
j
)
+
position
.
getX
(
j
),
positionAttribute
.
getY
(
j
)
+
position
.
getY
(
j
),
positionAttribute
.
getZ
(
j
)
+
position
.
getZ
(
j
)
);
}
}
else
{
// Copying the original position not to affect the final position.
// See the formula above.
positionAttribute
=
geometry
.
attributes
.
position
.
clone
();
}
if
(
target
.
NORMAL
!==
undefined
)
{
material
.
morphNormals
=
true
;
// see target.POSITION's comment
normalAttribute
=
dependencies
.
accessors
[
target
.
NORMAL
].
clone
();
var
normal
=
geometry
.
attributes
.
normal
;
for
(
var
j
=
0
,
jl
=
normalAttribute
.
count
;
j
<
jl
;
j
++
)
{
normalAttribute
.
setXYZ
(
j
,
normalAttribute
.
getX
(
j
)
+
normal
.
getX
(
j
),
normalAttribute
.
getY
(
j
)
+
normal
.
getY
(
j
),
normalAttribute
.
getZ
(
j
)
+
normal
.
getZ
(
j
)
);
}
}
else
{
normalAttribute
=
geometry
.
attributes
.
normal
.
clone
();
}
if
(
target
.
TANGENT
!==
undefined
)
{
// TODO: implement
}
positionAttribute
.
name
=
attributeName
;
normalAttribute
.
name
=
attributeName
;
morphAttributes
.
position
.
push
(
positionAttribute
);
morphAttributes
.
normal
.
push
(
normalAttribute
);
}
mesh
.
updateMorphTargets
();
if
(
meshDef
.
weights
!==
undefined
)
{
for
(
var
i
=
0
,
il
=
meshDef
.
weights
.
length
;
i
<
il
;
i
++
)
{
mesh
.
morphTargetInfluences
[
i
]
=
meshDef
.
weights
[
i
];
}
}
}
/* GLTF PARSER */
function
GLTFParser
(
json
,
extensions
,
options
)
{
this
.
json
=
json
||
{};
this
.
extensions
=
extensions
||
{};
this
.
options
=
options
||
{};
// loader object cache
this
.
cache
=
new
GLTFRegistry
();
}
GLTFParser
.
prototype
.
_withDependencies
=
function
(
dependencies
)
{
var
_dependencies
=
{};
for
(
var
i
=
0
;
i
<
dependencies
.
length
;
i
++
)
{
var
dependency
=
dependencies
[
i
];
var
fnName
=
'
load
'
+
dependency
.
charAt
(
0
).
toUpperCase
()
+
dependency
.
slice
(
1
);
var
cached
=
this
.
cache
.
get
(
dependency
);
if
(
cached
!==
undefined
)
{
_dependencies
[
dependency
]
=
cached
;
}
else
if
(
this
[
fnName
]
)
{
var
fn
=
this
[
fnName
]();
this
.
cache
.
add
(
dependency
,
fn
);
_dependencies
[
dependency
]
=
fn
;
}
}
return
_each
(
_dependencies
,
function
(
dependency
)
{
return
dependency
;
}
);
};
GLTFParser
.
prototype
.
parse
=
function
(
onLoad
,
onError
)
{
var
json
=
this
.
json
;
// Clear the loader cache
this
.
cache
.
removeAll
();
// Fire the callback on complete
this
.
_withDependencies
(
[
'
scenes
'
,
'
cameras
'
,
'
animations
'
]
).
then
(
function
(
dependencies
)
{
var
scenes
=
[];
for
(
var
name
in
dependencies
.
scenes
)
{
scenes
.
push
(
dependencies
.
scenes
[
name
]
);
}
var
scene
=
json
.
scene
!==
undefined
?
dependencies
.
scenes
[
json
.
scene
]
:
scenes
[
0
];
var
cameras
=
[];
for
(
var
name
in
dependencies
.
cameras
)
{
var
camera
=
dependencies
.
cameras
[
name
];
cameras
.
push
(
camera
);
}
var
animations
=
[];
for
(
var
name
in
dependencies
.
animations
)
{
animations
.
push
(
dependencies
.
animations
[
name
]
);
}
onLoad
(
scene
,
scenes
,
cameras
,
animations
);
}
).
catch
(
onError
);
};
/**
* Requests the specified dependency asynchronously, with caching.
* @param {string} type
* @param {number} index
* @return {Promise<Object>}
*/
GLTFParser
.
prototype
.
getDependency
=
function
(
type
,
index
)
{
var
cacheKey
=
type
+
'
:
'
+
index
;
var
dependency
=
this
.
cache
.
get
(
cacheKey
);
if
(
!
dependency
)
{
var
fnName
=
'
load
'
+
type
.
charAt
(
0
).
toUpperCase
()
+
type
.
slice
(
1
);
dependency
=
this
[
fnName
](
index
);
this
.
cache
.
add
(
cacheKey
,
dependency
);
}
return
dependency
;
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
* @param {number} bufferIndex
* @return {Promise<ArrayBuffer>}
*/
GLTFParser
.
prototype
.
loadBuffer
=
function
(
bufferIndex
)
{
var
bufferDef
=
this
.
json
.
buffers
[
bufferIndex
];
if
(
bufferDef
.
type
&&
bufferDef
.
type
!==
'
arraybuffer
'
)
{
throw
new
Error
(
'
THREE.GLTF2Loader: %s buffer type is not supported.
'
,
bufferDef
.
type
);
}
// If present, GLB container is required to be the first buffer.
if
(
bufferDef
.
uri
===
undefined
&&
bufferIndex
===
0
)
{
return
Promise
.
resolve
(
this
.
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
body
);
}
var
options
=
this
.
options
;
return
new
Promise
(
function
(
resolve
)
{
var
loader
=
new
THREE
.
FileLoader
();
loader
.
setResponseType
(
'
arraybuffer
'
);
loader
.
load
(
resolveURL
(
bufferDef
.
uri
,
options
.
path
),
resolve
);
}
);
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
* @param {number} bufferViewIndex
* @return {Promise<ArrayBuffer>}
*/
GLTFParser
.
prototype
.
loadBufferView
=
function
(
bufferViewIndex
)
{
var
bufferViewDef
=
this
.
json
.
bufferViews
[
bufferViewIndex
];
return
this
.
getDependency
(
'
buffer
'
,
bufferViewDef
.
buffer
).
then
(
function
(
buffer
)
{
var
byteLength
=
bufferViewDef
.
byteLength
||
0
;
var
byteOffset
=
bufferViewDef
.
byteOffset
||
0
;
return
buffer
.
slice
(
byteOffset
,
byteOffset
+
byteLength
);
}
);
};
GLTFParser
.
prototype
.
loadAccessors
=
function
()
{
var
parser
=
this
;
var
json
=
this
.
json
;
return
_each
(
json
.
accessors
,
function
(
accessor
)
{
return
parser
.
getDependency
(
'
bufferView
'
,
accessor
.
bufferView
).
then
(
function
(
bufferView
)
{
var
itemSize
=
WEBGL_TYPE_SIZES
[
accessor
.
type
];
var
TypedArray
=
WEBGL_COMPONENT_TYPES
[
accessor
.
componentType
];
// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
var
elementBytes
=
TypedArray
.
BYTES_PER_ELEMENT
;
var
itemBytes
=
elementBytes
*
itemSize
;
var
byteStride
=
json
.
bufferViews
[
accessor
.
bufferView
].
byteStride
;
var
array
;
// The buffer is not interleaved if the stride is the item size in bytes.
if
(
byteStride
&&
byteStride
!==
itemBytes
)
{
// Use the full buffer if it's interleaved.
array
=
new
TypedArray
(
bufferView
);
// Integer parameters to IB/IBA are in array elements, not bytes.
var
ib
=
new
THREE
.
InterleavedBuffer
(
array
,
byteStride
/
elementBytes
);
return
new
THREE
.
InterleavedBufferAttribute
(
ib
,
itemSize
,
accessor
.
byteOffset
/
elementBytes
);
}
else
{
array
=
new
TypedArray
(
bufferView
,
accessor
.
byteOffset
,
accessor
.
count
*
itemSize
);
return
new
THREE
.
BufferAttribute
(
array
,
itemSize
);
}
}
);
}
);
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
* @param {number} textureIndex
* @return {Promise<THREE.Texture>}
*/
GLTFParser
.
prototype
.
loadTexture
=
function
(
textureIndex
)
{
var
parser
=
this
;
var
json
=
this
.
json
;
var
options
=
this
.
options
;
var
URL
=
window
.
URL
||
window
.
webkitURL
;
var
textureDef
=
json
.
textures
[
textureIndex
];
var
source
=
json
.
images
[
textureDef
.
source
];
var
sourceURI
=
source
.
uri
;
var
isObjectURL
=
false
;
if
(
source
.
bufferView
!==
undefined
)
{
// Load binary image data from bufferView, if provided.
sourceURI
=
parser
.
getDependency
(
'
bufferView
'
,
source
.
bufferView
)
.
then
(
function
(
bufferView
)
{
isObjectURL
=
true
;
var
blob
=
new
Blob
(
[
bufferView
],
{
type
:
source
.
mimeType
}
);
sourceURI
=
URL
.
createObjectURL
(
blob
);
return
sourceURI
;
}
);
}
return
Promise
.
resolve
(
sourceURI
).
then
(
function
(
sourceURI
)
{
// Load Texture resource.
var
textureLoader
=
THREE
.
Loader
.
Handlers
.
get
(
sourceURI
)
||
new
THREE
.
TextureLoader
();
textureLoader
.
setCrossOrigin
(
options
.
crossOrigin
);
return
new
Promise
(
function
(
resolve
,
reject
)
{
textureLoader
.
load
(
resolveURL
(
sourceURI
,
options
.
path
),
resolve
,
undefined
,
reject
);
}
);
}
).
then
(
function
(
texture
)
{
// Clean up resources and configure Texture.
if
(
isObjectURL
!==
undefined
)
{
URL
.
revokeObjectURL
(
sourceURI
);
}
texture
.
flipY
=
false
;
if
(
textureDef
.
name
!==
undefined
)
texture
.
name
=
textureDef
.
name
;
texture
.
format
=
textureDef
.
format
!==
undefined
?
WEBGL_TEXTURE_FORMATS
[
textureDef
.
format
]
:
THREE
.
RGBAFormat
;
if
(
textureDef
.
internalFormat
!==
undefined
&&
texture
.
format
!==
WEBGL_TEXTURE_FORMATS
[
textureDef
.
internalFormat
]
)
{
console
.
warn
(
'
THREE.GLTF2Loader: Three.js does not support texture internalFormat which is different from texture format.
'
+
'
internalFormat will be forced to be the same value as format.
'
);
}
texture
.
type
=
textureDef
.
type
!==
undefined
?
WEBGL_TEXTURE_DATATYPES
[
textureDef
.
type
]
:
THREE
.
UnsignedByteType
;
var
samplers
=
json
.
samplers
||
{};
var
sampler
=
samplers
[
textureDef
.
sampler
]
||
{};
texture
.
magFilter
=
WEBGL_FILTERS
[
sampler
.
magFilter
]
||
THREE
.
LinearFilter
;
texture
.
minFilter
=
WEBGL_FILTERS
[
sampler
.
minFilter
]
||
THREE
.
LinearMipMapLinearFilter
;
texture
.
wrapS
=
WEBGL_WRAPPINGS
[
sampler
.
wrapS
]
||
THREE
.
RepeatWrapping
;
texture
.
wrapT
=
WEBGL_WRAPPINGS
[
sampler
.
wrapT
]
||
THREE
.
RepeatWrapping
;
return
texture
;
}
);
};
/**
* Asynchronously assigns a texture to the given material parameters.
* @param {Object} materialParams
* @param {string} textureName
* @param {number} textureIndex
* @return {Promise}
*/
GLTFParser
.
prototype
.
assignTexture
=
function
(
materialParams
,
textureName
,
textureIndex
)
{
return
this
.
getDependency
(
'
texture
'
,
textureIndex
).
then
(
function
(
texture
)
{
materialParams
[
textureName
]
=
texture
;
}
);
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
* @return {Promise<Array<THREE.Material>>}
*/
GLTFParser
.
prototype
.
loadMaterials
=
function
()
{
var
parser
=
this
;
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
return
_each
(
json
.
materials
,
function
(
material
)
{
var
materialType
;
var
materialParams
=
{};
var
materialExtensions
=
material
.
extensions
||
{};
var
pending
=
[];
if
(
materialExtensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
)
{
var
khcExtension
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
];
materialType
=
khcExtension
.
getMaterialType
(
material
);
pending
.
push
(
khcExtension
.
extendParams
(
materialParams
,
material
,
parser
)
);
}
else
if
(
materialExtensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
]
)
{
var
sgExtension
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
];
materialType
=
sgExtension
.
getMaterialType
(
material
);
pending
.
push
(
sgExtension
.
extendParams
(
materialParams
,
material
,
parser
)
);
}
else
if
(
material
.
pbrMetallicRoughness
!==
undefined
)
{
// Specification:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
materialType
=
THREE
.
MeshStandardMaterial
;
var
metallicRoughness
=
material
.
pbrMetallicRoughness
;
materialParams
.
color
=
new
THREE
.
Color
(
1.0
,
1.0
,
1.0
);
materialParams
.
opacity
=
1.0
;
if
(
Array
.
isArray
(
metallicRoughness
.
baseColorFactor
)
)
{
var
array
=
metallicRoughness
.
baseColorFactor
;
materialParams
.
color
.
fromArray
(
array
);
materialParams
.
opacity
=
array
[
3
];
}
if
(
metallicRoughness
.
baseColorTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
map
'
,
metallicRoughness
.
baseColorTexture
.
index
)
);
}
materialParams
.
metalness
=
metallicRoughness
.
metallicFactor
!==
undefined
?
metallicRoughness
.
metallicFactor
:
1.0
;
materialParams
.
roughness
=
metallicRoughness
.
roughnessFactor
!==
undefined
?
metallicRoughness
.
roughnessFactor
:
1.0
;
if
(
metallicRoughness
.
metallicRoughnessTexture
!==
undefined
)
{
var
textureIndex
=
metallicRoughness
.
metallicRoughnessTexture
.
index
;
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
metalnessMap
'
,
textureIndex
)
);
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
roughnessMap
'
,
textureIndex
)
);
}
}
else
{
materialType
=
THREE
.
MeshPhongMaterial
;
}
if
(
material
.
doubleSided
===
true
)
{
materialParams
.
side
=
THREE
.
DoubleSide
;
}
var
alphaMode
=
material
.
alphaMode
||
ALPHA_MODES
.
OPAQUE
;
if
(
alphaMode
!==
ALPHA_MODES
.
OPAQUE
)
{
materialParams
.
transparent
=
true
;
}
else
{
materialParams
.
transparent
=
false
;
}
if
(
material
.
normalTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
normalMap
'
,
material
.
normalTexture
.
index
)
);
}
if
(
material
.
occlusionTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
aoMap
'
,
material
.
occlusionTexture
.
index
)
);
}
if
(
material
.
emissiveFactor
!==
undefined
)
{
if
(
materialType
===
THREE
.
MeshBasicMaterial
)
{
materialParams
.
color
=
new
THREE
.
Color
().
fromArray
(
material
.
emissiveFactor
);
}
else
{
materialParams
.
emissive
=
new
THREE
.
Color
().
fromArray
(
material
.
emissiveFactor
);
}
}
if
(
material
.
emissiveTexture
!==
undefined
)
{
if
(
materialType
===
THREE
.
MeshBasicMaterial
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
map
'
,
material
.
emissiveTexture
.
index
)
);
}
else
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
emissiveMap
'
,
material
.
emissiveTexture
.
index
)
);
}
}
return
Promise
.
all
(
pending
).
then
(
function
()
{
var
_material
;
if
(
materialType
===
THREE
.
ShaderMaterial
)
{
_material
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
].
createMaterial
(
materialParams
);
}
else
{
_material
=
new
materialType
(
materialParams
);
}
if
(
material
.
name
!==
undefined
)
_material
.
name
=
material
.
name
;
// Normal map textures use OpenGL conventions:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture
_material
.
normalScale
.
x
=
-
1
;
_material
.
userData
=
material
.
extras
;
return
_material
;
}
);
}
);
};
GLTFParser
.
prototype
.
loadGeometries
=
function
(
primitives
)
{
return
this
.
_withDependencies
(
[
'
accessors
'
,
]
).
then
(
function
(
dependencies
)
{
return
_each
(
primitives
,
function
(
primitive
)
{
var
geometry
=
new
THREE
.
BufferGeometry
();
var
attributes
=
primitive
.
attributes
;
for
(
var
attributeId
in
attributes
)
{
var
attributeEntry
=
attributes
[
attributeId
];
if
(
attributeEntry
===
undefined
)
return
;
var
bufferAttribute
=
dependencies
.
accessors
[
attributeEntry
];
switch
(
attributeId
)
{
case
'
POSITION
'
:
geometry
.
addAttribute
(
'
position
'
,
bufferAttribute
);
break
;
case
'
NORMAL
'
:
geometry
.
addAttribute
(
'
normal
'
,
bufferAttribute
);
break
;
case
'
TEXCOORD_0
'
:
case
'
TEXCOORD0
'
:
case
'
TEXCOORD
'
:
geometry
.
addAttribute
(
'
uv
'
,
bufferAttribute
);
break
;
case
'
TEXCOORD_1
'
:
geometry
.
addAttribute
(
'
uv2
'
,
bufferAttribute
);
break
;
case
'
COLOR_0
'
:
case
'
COLOR0
'
:
case
'
COLOR
'
:
geometry
.
addAttribute
(
'
color
'
,
bufferAttribute
);
break
;
case
'
WEIGHTS_0
'
:
case
'
WEIGHT
'
:
// WEIGHT semantic deprecated.
geometry
.
addAttribute
(
'
skinWeight
'
,
bufferAttribute
);
break
;
case
'
JOINTS_0
'
:
case
'
JOINT
'
:
// JOINT semantic deprecated.
geometry
.
addAttribute
(
'
skinIndex
'
,
bufferAttribute
);
break
;
}
}
if
(
primitive
.
indices
!==
undefined
)
{
geometry
.
setIndex
(
dependencies
.
accessors
[
primitive
.
indices
]
);
}
return
geometry
;
}
);
}
);
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
*/
GLTFParser
.
prototype
.
loadMeshes
=
function
()
{
var
scope
=
this
;
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
'
accessors
'
,
'
materials
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
meshes
,
function
(
meshDef
)
{
var
group
=
new
THREE
.
Group
();
if
(
meshDef
.
name
!==
undefined
)
group
.
name
=
meshDef
.
name
;
if
(
meshDef
.
extras
)
group
.
userData
=
meshDef
.
extras
;
var
primitives
=
meshDef
.
primitives
||
[];
return
scope
.
loadGeometries
(
primitives
).
then
(
function
(
geometries
)
{
for
(
var
name
in
primitives
)
{
var
primitive
=
primitives
[
name
];
var
geometry
=
geometries
[
name
];
var
material
=
primitive
.
material
===
undefined
?
createDefaultMaterial
()
:
dependencies
.
materials
[
primitive
.
material
];
if
(
material
.
aoMap
&&
geometry
.
attributes
.
uv2
===
undefined
&&
geometry
.
attributes
.
uv
!==
undefined
)
{
console
.
log
(
'
THREE.GLTF2Loader: Duplicating UVs to support aoMap.
'
);
geometry
.
addAttribute
(
'
uv2
'
,
new
THREE
.
BufferAttribute
(
geometry
.
attributes
.
uv
.
array
,
2
)
);
}
if
(
geometry
.
attributes
.
color
!==
undefined
)
{
material
.
vertexColors
=
THREE
.
VertexColors
;
material
.
needsUpdate
=
true
;
}
if
(
geometry
.
attributes
.
normal
===
undefined
)
{
if
(
material
.
flatShading
!==
undefined
)
{
material
.
flatShading
=
true
;
}
else
{
// TODO: Remove this backwards-compatibility fix after r87 release.
material
.
shading
=
THREE
.
FlatShading
;
}
}
var
mesh
;
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLES
||
primitive
.
mode
===
undefined
)
{
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLE_STRIP
)
{
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
mesh
.
drawMode
=
THREE
.
TriangleStripDrawMode
;
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLE_FAN
)
{
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
mesh
.
drawMode
=
THREE
.
TriangleFanDrawMode
;
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINES
)
{
mesh
=
new
THREE
.
LineSegments
(
geometry
,
material
);
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINE_STRIP
)
{
mesh
=
new
THREE
.
Line
(
geometry
,
material
);
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINE_LOOP
)
{
mesh
=
new
THREE
.
LineLoop
(
geometry
,
material
);
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
POINTS
)
{
mesh
=
new
THREE
.
Points
(
geometry
,
material
);
}
else
{
throw
new
Error
(
'
THREE.GLTF2Loader: Primitive mode unsupported:
'
,
primitive
.
mode
);
}
mesh
.
name
=
group
.
name
+
'
_
'
+
name
;
if
(
primitive
.
targets
!==
undefined
)
{
addMorphTargets
(
mesh
,
meshDef
,
primitive
,
dependencies
);
}
if
(
primitive
.
extras
)
mesh
.
userData
=
primitive
.
extras
;
group
.
add
(
mesh
);
}
return
group
;
}
);
}
);
}
);
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
*/
GLTFParser
.
prototype
.
loadCameras
=
function
()
{
var
json
=
this
.
json
;
return
_each
(
json
.
cameras
,
function
(
camera
)
{
var
_camera
;
var
params
=
camera
[
camera
.
type
];
if
(
!
params
)
{
console
.
warn
(
'
THREE.GLTF2Loader: Missing camera parameters.
'
);
return
;
}
if
(
camera
.
type
===
'
perspective
'
)
{
var
aspectRatio
=
params
.
aspectRatio
||
1
;
var
xfov
=
params
.
yfov
*
aspectRatio
;
_camera
=
new
THREE
.
PerspectiveCamera
(
THREE
.
Math
.
radToDeg
(
xfov
),
aspectRatio
,
params
.
znear
||
1
,
params
.
zfar
||
2
e6
);
}
else
if
(
camera
.
type
===
'
orthographic
'
)
{
_camera
=
new
THREE
.
OrthographicCamera
(
params
.
xmag
/
-
2
,
params
.
xmag
/
2
,
params
.
ymag
/
2
,
params
.
ymag
/
-
2
,
params
.
znear
,
params
.
zfar
);
}
if
(
camera
.
name
!==
undefined
)
_camera
.
name
=
camera
.
name
;
if
(
camera
.
extras
)
_camera
.
userData
=
camera
.
extras
;
return
_camera
;
}
);
};
GLTFParser
.
prototype
.
loadSkins
=
function
()
{
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
'
accessors
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
skins
,
function
(
skin
)
{
var
_skin
=
{
joints
:
skin
.
joints
,
inverseBindMatrices
:
dependencies
.
accessors
[
skin
.
inverseBindMatrices
]
};
return
_skin
;
}
);
}
);
};
GLTFParser
.
prototype
.
loadAnimations
=
function
()
{
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
'
accessors
'
,
'
nodes
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
animations
,
function
(
animation
,
animationId
)
{
var
tracks
=
[];
for
(
var
channelId
in
animation
.
channels
)
{
var
channel
=
animation
.
channels
[
channelId
];
var
sampler
=
animation
.
samplers
[
channel
.
sampler
];
if
(
sampler
)
{
var
target
=
channel
.
target
;
var
name
=
target
.
node
!==
undefined
?
target
.
node
:
target
.
id
;
// NOTE: target.id is deprecated.
var
input
=
animation
.
parameters
!==
undefined
?
animation
.
parameters
[
sampler
.
input
]
:
sampler
.
input
;
var
output
=
animation
.
parameters
!==
undefined
?
animation
.
parameters
[
sampler
.
output
]
:
sampler
.
output
;
var
inputAccessor
=
dependencies
.
accessors
[
input
];
var
outputAccessor
=
dependencies
.
accessors
[
output
];
var
node
=
dependencies
.
nodes
[
name
];
if
(
node
)
{
node
.
updateMatrix
();
node
.
matrixAutoUpdate
=
true
;
var
TypedKeyframeTrack
;
switch
(
PATH_PROPERTIES
[
target
.
path
]
)
{
case
PATH_PROPERTIES
.
weights
:
TypedKeyframeTrack
=
THREE
.
NumberKeyframeTrack
;
break
;
case
PATH_PROPERTIES
.
rotation
:
TypedKeyframeTrack
=
THREE
.
QuaternionKeyframeTrack
;
break
;
case
PATH_PROPERTIES
.
position
:
case
PATH_PROPERTIES
.
scale
:
default
:
TypedKeyframeTrack
=
THREE
.
VectorKeyframeTrack
;
break
;
}
var
targetName
=
node
.
name
?
node
.
name
:
node
.
uuid
;
if
(
sampler
.
interpolation
===
'
CATMULLROMSPLINE
'
)
{
console
.
warn
(
'
THREE.GLTF2Loader: CATMULLROMSPLINE interpolation is not supported. Using CUBICSPLINE instead.
'
);
}
var
interpolation
=
sampler
.
interpolation
!==
undefined
?
INTERPOLATION
[
sampler
.
interpolation
]
:
THREE
.
InterpolateLinear
;
var
targetNames
=
[];
if
(
PATH_PROPERTIES
[
target
.
path
]
===
PATH_PROPERTIES
.
weights
)
{
// node should be THREE.Group here but
// PATH_PROPERTIES.weights(morphTargetInfluences) should be
// the property of a mesh object under node.
// So finding targets here.
node
.
traverse
(
function
(
object
)
{
if
(
object
.
isMesh
===
true
&&
object
.
material
.
morphTargets
===
true
)
{
targetNames
.
push
(
object
.
name
?
object
.
name
:
object
.
uuid
);
}
}
);
}
else
{
targetNames
.
push
(
targetName
);
}
// KeyframeTrack.optimize() will modify given 'times' and 'values'
// buffers before creating a truncated copy to keep. Because buffers may
// be reused by other tracks, make copies here.
for
(
var
i
=
0
,
il
=
targetNames
.
length
;
i
<
il
;
i
++
)
{
tracks
.
push
(
new
TypedKeyframeTrack
(
targetNames
[
i
]
+
'
.
'
+
PATH_PROPERTIES
[
target
.
path
],
THREE
.
AnimationUtils
.
arraySlice
(
inputAccessor
.
array
,
0
),
THREE
.
AnimationUtils
.
arraySlice
(
outputAccessor
.
array
,
0
),
interpolation
)
);
}
}
}
}
var
name
=
animation
.
name
!==
undefined
?
animation
.
name
:
'
animation_
'
+
animationId
;
return
new
THREE
.
AnimationClip
(
name
,
undefined
,
tracks
);
}
);
}
);
};
GLTFParser
.
prototype
.
loadNodes
=
function
()
{
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
var
scope
=
this
;
var
nodes
=
json
.
nodes
||
[];
var
skins
=
json
.
skins
||
[];
// Nothing in the node definition indicates whether it is a Bone or an
// Object3D. Use the skins' joint references to mark bones.
skins
.
forEach
(
function
(
skin
)
{
skin
.
joints
.
forEach
(
function
(
id
)
{
nodes
[
id
].
isBone
=
true
;
}
);
}
);
return
_each
(
json
.
nodes
,
function
(
node
)
{
var
matrix
=
new
THREE
.
Matrix4
();
var
_node
=
node
.
isBone
===
true
?
new
THREE
.
Bone
()
:
new
THREE
.
Object3D
();
if
(
node
.
name
!==
undefined
)
{
_node
.
name
=
THREE
.
PropertyBinding
.
sanitizeNodeName
(
node
.
name
);
}
if
(
node
.
extras
)
_node
.
userData
=
node
.
extras
;
if
(
node
.
matrix
!==
undefined
)
{
matrix
.
fromArray
(
node
.
matrix
);
_node
.
applyMatrix
(
matrix
);
}
else
{
if
(
node
.
translation
!==
undefined
)
{
_node
.
position
.
fromArray
(
node
.
translation
);
}
if
(
node
.
rotation
!==
undefined
)
{
_node
.
quaternion
.
fromArray
(
node
.
rotation
);
}
if
(
node
.
scale
!==
undefined
)
{
_node
.
scale
.
fromArray
(
node
.
scale
);
}
}
return
_node
;
}
).
then
(
function
(
__nodes
)
{
return
scope
.
_withDependencies
(
[
'
meshes
'
,
'
skins
'
,
'
cameras
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
__nodes
,
function
(
_node
,
nodeId
)
{
var
node
=
json
.
nodes
[
nodeId
];
var
meshes
;
if
(
node
.
mesh
!==
undefined
)
{
meshes
=
[
node
.
mesh
];
}
else
if
(
node
.
meshes
!==
undefined
)
{
console
.
warn
(
'
THREE.GLTF2Loader: Legacy glTF file detected. Nodes may have no more than one mesh.
'
);
meshes
=
node
.
meshes
;
}
if
(
meshes
!==
undefined
)
{
for
(
var
meshId
in
meshes
)
{
var
mesh
=
meshes
[
meshId
];
var
group
=
dependencies
.
meshes
[
mesh
];
if
(
group
===
undefined
)
{
console
.
warn
(
'
THREE.GLTF2Loader: Could not find node "
'
+
mesh
+
'
".
'
);
continue
;
}
// do not clone children as they will be replaced anyway
var
clonedgroup
=
group
.
clone
(
false
);
for
(
var
childrenId
in
group
.
children
)
{
var
child
=
group
.
children
[
childrenId
];
var
originalChild
=
child
;
// clone Mesh to add to _node
var
originalMaterial
=
child
.
material
;
var
originalGeometry
=
child
.
geometry
;
var
originalInfluences
=
child
.
morphTargetInfluences
;
var
originalUserData
=
child
.
userData
;
var
originalName
=
child
.
name
;
var
material
=
originalMaterial
;
switch
(
child
.
type
)
{
case
'
LineSegments
'
:
child
=
new
THREE
.
LineSegments
(
originalGeometry
,
material
);
break
;
case
'
LineLoop
'
:
child
=
new
THREE
.
LineLoop
(
originalGeometry
,
material
);
break
;
case
'
Line
'
:
child
=
new
THREE
.
Line
(
originalGeometry
,
material
);
break
;
case
'
Points
'
:
child
=
new
THREE
.
Points
(
originalGeometry
,
material
);
break
;
default
:
child
=
new
THREE
.
Mesh
(
originalGeometry
,
material
);
child
.
drawMode
=
originalChild
.
drawMode
;
}
child
.
castShadow
=
true
;
child
.
morphTargetInfluences
=
originalInfluences
;
child
.
userData
=
originalUserData
;
child
.
name
=
originalName
;
var
skinEntry
;
if
(
node
.
skin
!==
undefined
)
{
skinEntry
=
dependencies
.
skins
[
node
.
skin
];
}
// Replace Mesh with SkinnedMesh in library
if
(
skinEntry
)
{
var
geometry
=
originalGeometry
;
material
=
originalMaterial
;
material
.
skinning
=
true
;
child
=
new
THREE
.
SkinnedMesh
(
geometry
,
material
);
child
.
castShadow
=
true
;
child
.
userData
=
originalUserData
;
child
.
name
=
originalName
;
var
bones
=
[];
var
boneInverses
=
[];
for
(
var
i
=
0
,
l
=
skinEntry
.
joints
.
length
;
i
<
l
;
i
++
)
{
var
jointId
=
skinEntry
.
joints
[
i
];
var
jointNode
=
__nodes
[
jointId
];
if
(
jointNode
)
{
bones
.
push
(
jointNode
);
var
m
=
skinEntry
.
inverseBindMatrices
.
array
;
var
mat
=
new
THREE
.
Matrix4
().
fromArray
(
m
,
i
*
16
);
boneInverses
.
push
(
mat
);
}
else
{
console
.
warn
(
'
THREE.GLTF2Loader: Joint "%s" could not be found.
'
,
jointId
);
}
}
child
.
bind
(
new
THREE
.
Skeleton
(
bones
,
boneInverses
),
child
.
matrixWorld
);
}
clonedgroup
.
add
(
child
);
}
_node
.
add
(
clonedgroup
);
}
}
if
(
node
.
camera
!==
undefined
)
{
var
camera
=
dependencies
.
cameras
[
node
.
camera
];
_node
.
add
(
camera
);
}
if
(
node
.
extensions
&&
node
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
&&
node
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
!==
undefined
)
{
var
lights
=
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
lights
;
_node
.
add
(
lights
[
node
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
]
);
}
return
_node
;
}
);
}
);
}
);
};
GLTFParser
.
prototype
.
loadScenes
=
function
()
{
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
// scene node hierachy builder
function
buildNodeHierachy
(
nodeId
,
parentObject
,
allNodes
)
{
var
_node
=
allNodes
[
nodeId
];
parentObject
.
add
(
_node
);
var
node
=
json
.
nodes
[
nodeId
];
if
(
node
.
children
)
{
var
children
=
node
.
children
;
for
(
var
i
=
0
,
l
=
children
.
length
;
i
<
l
;
i
++
)
{
var
child
=
children
[
i
];
buildNodeHierachy
(
child
,
_node
,
allNodes
);
}
}
}
return
this
.
_withDependencies
(
[
'
nodes
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
scenes
,
function
(
scene
)
{
var
_scene
=
new
THREE
.
Scene
();
if
(
scene
.
name
!==
undefined
)
_scene
.
name
=
scene
.
name
;
if
(
scene
.
extras
)
_scene
.
userData
=
scene
.
extras
;
var
nodes
=
scene
.
nodes
||
[];
for
(
var
i
=
0
,
l
=
nodes
.
length
;
i
<
l
;
i
++
)
{
var
nodeId
=
nodes
[
i
];
buildNodeHierachy
(
nodeId
,
_scene
,
dependencies
.
nodes
);
}
_scene
.
traverse
(
function
(
child
)
{
// for Specular-Glossiness.
if
(
child
.
material
&&
child
.
material
.
isGLTFSpecularGlossinessMaterial
)
{
child
.
onBeforeRender
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
].
refreshUniforms
;
}
}
);
// Ambient lighting, if present, is always attached to the scene root.
if
(
scene
.
extensions
&&
scene
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
&&
scene
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
!==
undefined
)
{
var
lights
=
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
lights
;
_scene
.
add
(
lights
[
scene
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
]
);
}
return
_scene
;
}
);
}
);
};
return
GLTF2Loader
;
}
)();
examples/js/loaders/GLTFLoader.js
浏览文件 @
a1e574b5
...
...
@@ -3,6 +3,7 @@
* @author mrdoob / http://mrdoob.com/
* @author Tony Parisi / http://www.tonyparisi.com/
* @author Takahiro / https://github.com/takahirox
* @author Don McCurdy / https://www.donmccurdy.com
*/
THREE
.
GLTFLoader
=
(
function
()
{
...
...
@@ -23,7 +24,7 @@ THREE.GLTFLoader = ( function () {
var
scope
=
this
;
var
path
=
this
.
path
&&
(
typeof
this
.
path
===
"
string
"
)
?
this
.
path
:
THREE
.
Loader
.
prototype
.
extractUrlBase
(
url
);
var
path
=
this
.
path
&&
(
typeof
this
.
path
===
'
string
'
)
?
this
.
path
:
THREE
.
Loader
.
prototype
.
extractUrlBase
(
url
);
var
loader
=
new
THREE
.
FileLoader
(
scope
.
manager
);
...
...
@@ -31,7 +32,16 @@ THREE.GLTFLoader = ( function () {
loader
.
load
(
url
,
function
(
data
)
{
scope
.
parse
(
data
,
onLoad
,
path
);
try
{
scope
.
parse
(
data
,
path
,
onLoad
,
onError
);
}
catch
(
e
)
{
// For SyntaxError or TypeError, return a generic failure message.
onError
(
e
.
constructor
===
Error
?
e
:
new
Error
(
'
THREE.GLTFLoader: Unable to parse model.
'
)
);
}
},
onProgress
,
onError
);
...
...
@@ -49,14 +59,14 @@ THREE.GLTFLoader = ( function () {
},
parse
:
function
(
data
,
callback
,
path
)
{
parse
:
function
(
data
,
path
,
onLoad
,
onError
)
{
var
content
;
var
extensions
=
{};
var
magic
=
convertUint8ArrayToString
(
new
Uint8Array
(
data
,
0
,
4
)
);
if
(
magic
===
BINARY_EXTENSION_HEADER_
DEFAULTS
.
magic
)
{
if
(
magic
===
BINARY_EXTENSION_HEADER_
MAGIC
)
{
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
]
=
new
GLTFBinaryExtension
(
data
);
content
=
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
content
;
...
...
@@ -69,9 +79,32 @@ THREE.GLTFLoader = ( function () {
var
json
=
JSON
.
parse
(
content
);
if
(
json
.
extensionsUsed
&&
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_MATERIALS_COMMON
)
>=
0
)
{
if
(
json
.
asset
===
undefined
||
json
.
asset
.
version
[
0
]
<
2
)
{
onError
(
new
Error
(
'
THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.
'
)
);
return
;
}
if
(
json
.
extensionsUsed
)
{
if
(
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_LIGHTS
)
>=
0
)
{
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
=
new
GLTFLightsExtension
(
json
);
}
if
(
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_MATERIALS_COMMON
)
>=
0
)
{
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
=
new
GLTFMaterialsCommonExtension
(
json
);
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
=
new
GLTFMaterialsCommonExtension
(
json
);
}
if
(
json
.
extensionsUsed
.
indexOf
(
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
)
>=
0
)
{
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
]
=
new
GLTFMaterialsPbrSpecularGlossinessExtension
();
}
}
...
...
@@ -89,15 +122,15 @@ THREE.GLTFLoader = ( function () {
console
.
timeEnd
(
'
GLTFLoader
'
);
var
glTF
=
{
"
scene
"
:
scene
,
"
scenes
"
:
scenes
,
"
cameras
"
:
cameras
,
"
animations
"
:
animations
scene
:
scene
,
scenes
:
scenes
,
cameras
:
cameras
,
animations
:
animations
};
callback
(
glTF
);
onLoad
(
glTF
);
}
);
}
,
onError
);
}
...
...
@@ -155,254 +188,579 @@ THREE.GLTFLoader = ( function () {
}
/* GLTFSHADERS */
/*********************************/
/********** EXTENSIONS ***********/
/*********************************/
GLTFLoader
.
Shaders
=
{
var
EXTENSIONS
=
{
KHR_BINARY_GLTF
:
'
KHR_binary_glTF
'
,
KHR_LIGHTS
:
'
KHR_lights
'
,
KHR_MATERIALS_COMMON
:
'
KHR_materials_common
'
,
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
:
'
KHR_materials_pbrSpecularGlossiness
'
};
update
:
function
()
{
/**
* Lights Extension
*
* Specification: PENDING
*/
function
GLTFLightsExtension
(
json
)
{
console
.
warn
(
'
THREE.GLTFLoader.Shaders has been deprecated, and now updates automatically.
'
)
;
this
.
name
=
EXTENSIONS
.
KHR_LIGHTS
;
}
this
.
lights
=
{};
};
var
extension
=
(
json
.
extensions
&&
json
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
)
||
{};
var
lights
=
extension
.
lights
||
{};
/* GLTFSHADER */
for
(
var
lightId
in
lights
)
{
function
GLTFShader
(
targetNode
,
allNodes
)
{
var
light
=
lights
[
lightId
];
var
lightNode
;
var
boundUniforms
=
{}
;
var
color
=
new
THREE
.
Color
().
fromArray
(
light
.
color
)
;
// bind each uniform to its source node
switch
(
light
.
type
)
{
var
uniforms
=
targetNode
.
material
.
uniforms
;
case
'
directional
'
:
lightNode
=
new
THREE
.
DirectionalLight
(
color
);
lightNode
.
position
.
set
(
0
,
0
,
1
);
break
;
for
(
var
uniformId
in
uniforms
)
{
case
'
point
'
:
lightNode
=
new
THREE
.
PointLight
(
color
);
break
;
var
uniform
=
uniforms
[
uniformId
];
case
'
spot
'
:
lightNode
=
new
THREE
.
SpotLight
(
color
);
lightNode
.
position
.
set
(
0
,
0
,
1
);
break
;
if
(
uniform
.
semantic
)
{
case
'
ambient
'
:
lightNode
=
new
THREE
.
AmbientLight
(
color
);
break
;
var
sourceNodeRef
=
uniform
.
node
;
}
var
sourceNode
=
targetNode
;
if
(
lightNode
)
{
if
(
sourceNodeRef
)
{
if
(
light
.
constantAttenuation
!==
undefined
)
{
sourceNode
=
allNodes
[
sourceNodeRef
]
;
lightNode
.
intensity
=
light
.
constantAttenuation
;
}
boundUniforms
[
uniformId
]
=
{
semantic
:
uniform
.
semantic
,
sourceNode
:
sourceNode
,
targetNode
:
targetNode
,
uniform
:
uniform
};
if
(
light
.
linearAttenuation
!==
undefined
)
{
}
lightNode
.
distance
=
1
/
light
.
linearAttenuation
;
}
}
this
.
boundUniforms
=
boundUniforms
;
this
.
_m4
=
new
THREE
.
Matrix4
();
if
(
light
.
quadraticAttenuation
!==
undefined
)
{
}
lightNode
.
decay
=
light
.
quadraticAttenuation
;
// Update - update all the uniform values
GLTFShader
.
prototype
.
update
=
function
(
scene
,
camera
)
{
}
var
boundUniforms
=
this
.
boundUniforms
;
if
(
light
.
fallOffAngle
!==
undefined
)
{
for
(
var
name
in
boundUniforms
)
{
lightNode
.
angle
=
light
.
fallOffAngle
;
var
boundUniform
=
boundUniforms
[
name
];
}
switch
(
boundUniform
.
semantic
)
{
if
(
light
.
fallOffExponent
!==
undefined
)
{
case
"
MODELVIEW
"
:
console
.
warn
(
'
THREE.GLTFLoader:: light.fallOffExponent not currently supported.
'
);
var
m4
=
boundUniform
.
uniform
.
value
;
m4
.
multiplyMatrices
(
camera
.
matrixWorldInverse
,
boundUniform
.
sourceNode
.
matrixWorld
);
break
;
}
case
"
MODELVIEWINVERSETRANSPOSE
"
:
lightNode
.
name
=
light
.
name
||
(
'
light_
'
+
lightId
);
this
.
lights
[
lightId
]
=
lightNode
;
var
m3
=
boundUniform
.
uniform
.
value
;
this
.
_m4
.
multiplyMatrices
(
camera
.
matrixWorldInverse
,
boundUniform
.
sourceNode
.
matrixWorld
);
m3
.
getNormalMatrix
(
this
.
_m4
);
break
;
}
case
"
PROJECTION
"
:
}
var
m4
=
boundUniform
.
uniform
.
value
;
m4
.
copy
(
camera
.
projectionMatrix
);
break
;
}
case
"
JOINTMATRIX
"
:
/**
* Common Materials Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_common
*/
function
GLTFMaterialsCommonExtension
(
json
)
{
var
m4v
=
boundUniform
.
uniform
.
value
;
this
.
name
=
EXTENSIONS
.
KHR_MATERIALS_COMMON
;
for
(
var
mi
=
0
;
mi
<
m4v
.
length
;
mi
++
)
{
}
// So it goes like this:
// SkinnedMesh world matrix is already baked into MODELVIEW;
// transform joints to local space,
// then transform using joint's inverse
m4v
[
mi
]
.
getInverse
(
boundUniform
.
sourceNode
.
matrixWorld
)
.
multiply
(
boundUniform
.
targetNode
.
skeleton
.
bones
[
mi
].
matrixWorld
)
.
multiply
(
boundUniform
.
targetNode
.
skeleton
.
boneInverses
[
mi
]
)
.
multiply
(
boundUniform
.
targetNode
.
bindMatrix
);
GLTFMaterialsCommonExtension
.
prototype
.
getMaterialType
=
function
(
material
)
{
}
var
khrMaterial
=
material
.
extensions
[
this
.
name
];
break
;
switch
(
khrMaterial
.
type
)
{
default
:
case
'
commonBlinn
'
:
case
'
commonPhong
'
:
return
THREE
.
MeshPhongMaterial
;
console
.
warn
(
"
Unhandled shader semantic:
"
+
boundUniform
.
semantic
);
break
;
case
'
commonLambert
'
:
return
THREE
.
MeshLambertMaterial
;
}
case
'
commonConstant
'
:
default
:
return
THREE
.
MeshBasicMaterial
;
}
};
GLTFMaterialsCommonExtension
.
prototype
.
extendParams
=
function
(
materialParams
,
material
,
parser
)
{
/* ANIMATION */
var
khrMaterial
=
material
.
extensions
[
this
.
name
];
GLTFLoader
.
Animations
=
{
var
pending
=
[];
update
:
function
()
{
var
keys
=
[];
console
.
warn
(
'
THREE.GLTFLoader.Animation has been deprecated. Use THREE.AnimationMixer instead.
'
);
// TODO: Currently ignored: 'ambientFactor', 'ambientTexture'
switch
(
khrMaterial
.
type
)
{
}
case
'
commonBlinn
'
:
case
'
commonPhong
'
:
keys
.
push
(
'
diffuseFactor
'
,
'
diffuseTexture
'
,
'
specularFactor
'
,
'
specularTexture
'
,
'
shininessFactor
'
);
break
;
};
case
'
commonLambert
'
:
keys
.
push
(
'
diffuseFactor
'
,
'
diffuseTexture
'
);
break
;
/*********************************/
/********** EXTENSIONS ***********/
/*********************************/
case
'
commonConstant
'
:
default
:
break
;
var
EXTENSIONS
=
{
KHR_BINARY_GLTF
:
'
KHR_binary_glTF
'
,
KHR_MATERIALS_COMMON
:
'
KHR_materials_common
'
};
}
/* MATERIALS COMMON EXTENSION */
var
materialValues
=
{};
function
GLTFMaterialsCommonExtension
(
json
)
{
keys
.
forEach
(
function
(
v
)
{
this
.
name
=
EXTENSIONS
.
KHR_MATERIALS_COMMON
;
if
(
khrMaterial
[
v
]
!==
undefined
)
materialValues
[
v
]
=
khrMaterial
[
v
]
;
this
.
lights
=
{}
;
}
)
;
var
extension
=
(
json
.
extensions
&&
json
.
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
)
||
{};
var
lights
=
extension
.
lights
||
{};
if
(
materialValues
.
diffuseFactor
!==
undefined
)
{
for
(
var
lightId
in
lights
)
{
materialParams
.
color
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
diffuseFactor
);
materialParams
.
opacity
=
materialValues
.
diffuseFactor
[
3
];
var
light
=
lights
[
lightId
];
var
lightNode
;
}
var
lightParams
=
light
[
light
.
type
];
var
color
=
new
THREE
.
Color
().
fromArray
(
lightParams
.
color
);
if
(
materialValues
.
diffuseTexture
!==
undefined
)
{
switch
(
light
.
type
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
map
'
,
materialValues
.
diffuseTexture
.
index
)
);
case
"
directional
"
:
lightNode
=
new
THREE
.
DirectionalLight
(
color
);
lightNode
.
position
.
set
(
0
,
0
,
1
);
break
;
}
case
"
point
"
:
lightNode
=
new
THREE
.
PointLight
(
color
);
break
;
if
(
materialValues
.
specularFactor
!==
undefined
)
{
case
"
spot
"
:
lightNode
=
new
THREE
.
SpotLight
(
color
);
lightNode
.
position
.
set
(
0
,
0
,
1
);
break
;
materialParams
.
specular
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
specularFactor
);
case
"
ambient
"
:
lightNode
=
new
THREE
.
AmbientLight
(
color
);
break
;
}
}
if
(
materialValues
.
specularTexture
!==
undefined
)
{
if
(
lightNode
)
{
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
specularMap
'
,
materialValues
.
specularTexture
.
index
)
);
this
.
lights
[
lightId
]
=
lightNode
;
}
}
if
(
materialValues
.
shininessFactor
!==
undefined
)
{
materialParams
.
shininess
=
materialValues
.
shininessFactor
;
}
}
return
Promise
.
all
(
pending
);
};
/* BINARY EXTENSION */
var
BINARY_EXTENSION_BUFFER_NAME
=
'
binary_glTF
'
;
var
BINARY_EXTENSION_HEADER_DEFAULTS
=
{
magic
:
'
glTF
'
,
version
:
1
,
contentFormat
:
0
};
var
BINARY_EXTENSION_HEADER_LENGTH
=
20
;
var
BINARY_EXTENSION_HEADER_MAGIC
=
'
glTF
'
;
var
BINARY_EXTENSION_HEADER_LENGTH
=
12
;
var
BINARY_EXTENSION_CHUNK_TYPES
=
{
JSON
:
0x4E4F534A
,
BIN
:
0x004E4942
};
function
GLTFBinaryExtension
(
data
)
{
this
.
name
=
EXTENSIONS
.
KHR_BINARY_GLTF
;
this
.
content
=
null
;
this
.
body
=
null
;
var
headerView
=
new
DataView
(
data
,
0
,
BINARY_EXTENSION_HEADER_LENGTH
);
var
header
=
{
this
.
header
=
{
magic
:
convertUint8ArrayToString
(
new
Uint8Array
(
data
.
slice
(
0
,
4
)
)
),
version
:
headerView
.
getUint32
(
4
,
true
),
length
:
headerView
.
getUint32
(
8
,
true
),
contentLength
:
headerView
.
getUint32
(
12
,
true
),
contentFormat
:
headerView
.
getUint32
(
16
,
true
)
length
:
headerView
.
getUint32
(
8
,
true
)
};
for
(
var
key
in
BINARY_EXTENSION_HEADER_DEFAULTS
)
{
if
(
this
.
header
.
magic
!==
BINARY_EXTENSION_HEADER_MAGIC
)
{
var
value
=
BINARY_EXTENSION_HEADER_DEFAULTS
[
key
]
;
throw
new
Error
(
'
THREE.GLTFLoader: Unsupported glTF-Binary header.
'
)
;
if
(
header
[
key
]
!==
value
)
{
}
else
if
(
this
.
header
.
version
<
2.0
)
{
throw
new
Error
(
'
Unsupported glTF-Binary header: Expected "%s" to be "%s".
'
,
key
,
value
);
throw
new
Error
(
'
THREE.GLTFLoader: Legacy binary file detected. Use GLTFLoader instead.
'
);
}
var
chunkView
=
new
DataView
(
data
,
BINARY_EXTENSION_HEADER_LENGTH
);
var
chunkIndex
=
0
;
while
(
chunkIndex
<
chunkView
.
byteLength
)
{
var
chunkLength
=
chunkView
.
getUint32
(
chunkIndex
,
true
);
chunkIndex
+=
4
;
var
chunkType
=
chunkView
.
getUint32
(
chunkIndex
,
true
);
chunkIndex
+=
4
;
if
(
chunkType
===
BINARY_EXTENSION_CHUNK_TYPES
.
JSON
)
{
var
contentArray
=
new
Uint8Array
(
data
,
BINARY_EXTENSION_HEADER_LENGTH
+
chunkIndex
,
chunkLength
);
this
.
content
=
convertUint8ArrayToString
(
contentArray
);
}
else
if
(
chunkType
===
BINARY_EXTENSION_CHUNK_TYPES
.
BIN
)
{
var
byteOffset
=
BINARY_EXTENSION_HEADER_LENGTH
+
chunkIndex
;
this
.
body
=
data
.
slice
(
byteOffset
,
byteOffset
+
chunkLength
);
}
// Clients must ignore chunks with unknown types.
chunkIndex
+=
chunkLength
;
}
var
contentArray
=
new
Uint8Array
(
data
,
BINARY_EXTENSION_HEADER_LENGTH
,
header
.
contentLength
);
if
(
this
.
content
===
null
)
{
throw
new
Error
(
'
THREE.GLTFLoader: JSON content not found.
'
);
this
.
header
=
header
;
this
.
content
=
convertUint8ArrayToString
(
contentArray
);
this
.
body
=
data
.
slice
(
BINARY_EXTENSION_HEADER_LENGTH
+
header
.
contentLength
,
header
.
length
);
}
}
GLTFBinaryExtension
.
prototype
.
loadShader
=
function
(
shader
,
bufferViews
)
{
/**
* Specular-Glossiness Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_pbrSpecularGlossiness
*/
function
GLTFMaterialsPbrSpecularGlossinessExtension
()
{
var
bufferView
=
bufferViews
[
shader
.
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
bufferView
];
var
array
=
new
Uint8Array
(
bufferView
);
return
{
return
convertUint8ArrayToString
(
array
);
name
:
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
,
};
getMaterialType
:
function
()
{
GLTFBinaryExtension
.
prototype
.
loadTextureSourceUri
=
function
(
source
,
bufferViews
)
{
return
THREE
.
ShaderMaterial
;
var
metadata
=
source
.
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
];
var
bufferView
=
bufferViews
[
metadata
.
bufferView
];
var
stringData
=
convertUint8ArrayToString
(
new
Uint8Array
(
bufferView
)
);
},
return
'
data:
'
+
metadata
.
mimeType
+
'
;base64,
'
+
btoa
(
stringData
);
extendParams
:
function
(
params
,
material
,
parser
)
{
var
pbrSpecularGlossiness
=
material
.
extensions
[
this
.
name
];
var
shader
=
THREE
.
ShaderLib
[
'
standard
'
];
var
uniforms
=
THREE
.
UniformsUtils
.
clone
(
shader
.
uniforms
);
var
specularMapParsFragmentChunk
=
[
'
#ifdef USE_SPECULARMAP
'
,
'
uniform sampler2D specularMap;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
glossinessMapParsFragmentChunk
=
[
'
#ifdef USE_GLOSSINESSMAP
'
,
'
uniform sampler2D glossinessMap;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
specularMapFragmentChunk
=
[
'
vec3 specularFactor = specular;
'
,
'
#ifdef USE_SPECULARMAP
'
,
'
vec4 texelSpecular = texture2D( specularMap, vUv );
'
,
'
// reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture
'
,
'
specularFactor *= texelSpecular.rgb;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
glossinessMapFragmentChunk
=
[
'
float glossinessFactor = glossiness;
'
,
'
#ifdef USE_GLOSSINESSMAP
'
,
'
vec4 texelGlossiness = texture2D( glossinessMap, vUv );
'
,
'
// reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture
'
,
'
glossinessFactor *= texelGlossiness.a;
'
,
'
#endif
'
].
join
(
'
\n
'
);
var
lightPhysicalFragmentChunk
=
[
'
PhysicalMaterial material;
'
,
'
material.diffuseColor = diffuseColor.rgb;
'
,
'
material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );
'
,
'
material.specularColor = specularFactor.rgb;
'
,
].
join
(
'
\n
'
);
var
fragmentShader
=
shader
.
fragmentShader
.
replace
(
'
#include <specularmap_fragment>
'
,
''
)
.
replace
(
'
uniform float roughness;
'
,
'
uniform vec3 specular;
'
)
.
replace
(
'
uniform float metalness;
'
,
'
uniform float glossiness;
'
)
.
replace
(
'
#include <roughnessmap_pars_fragment>
'
,
specularMapParsFragmentChunk
)
.
replace
(
'
#include <metalnessmap_pars_fragment>
'
,
glossinessMapParsFragmentChunk
)
.
replace
(
'
#include <roughnessmap_fragment>
'
,
specularMapFragmentChunk
)
.
replace
(
'
#include <metalnessmap_fragment>
'
,
glossinessMapFragmentChunk
)
.
replace
(
'
#include <lights_physical_fragment>
'
,
lightPhysicalFragmentChunk
);
delete
uniforms
.
roughness
;
delete
uniforms
.
metalness
;
delete
uniforms
.
roughnessMap
;
delete
uniforms
.
metalnessMap
;
uniforms
.
specular
=
{
value
:
new
THREE
.
Color
().
setHex
(
0x111111
)
};
uniforms
.
glossiness
=
{
value
:
0.5
};
uniforms
.
specularMap
=
{
value
:
null
};
uniforms
.
glossinessMap
=
{
value
:
null
};
params
.
vertexShader
=
shader
.
vertexShader
;
params
.
fragmentShader
=
fragmentShader
;
params
.
uniforms
=
uniforms
;
params
.
defines
=
{
'
STANDARD
'
:
''
};
params
.
color
=
new
THREE
.
Color
(
1.0
,
1.0
,
1.0
);
params
.
opacity
=
1.0
;
var
pending
=
[];
if
(
Array
.
isArray
(
pbrSpecularGlossiness
.
diffuseFactor
)
)
{
var
array
=
pbrSpecularGlossiness
.
diffuseFactor
;
params
.
color
.
fromArray
(
array
);
params
.
opacity
=
array
[
3
];
};
}
if
(
pbrSpecularGlossiness
.
diffuseTexture
!==
undefined
)
{
pending
.
push
(
parser
.
assignTexture
(
params
,
'
map
'
,
pbrSpecularGlossiness
.
diffuseTexture
.
index
)
);
}
params
.
emissive
=
new
THREE
.
Color
(
0.0
,
0.0
,
0.0
);
params
.
glossiness
=
pbrSpecularGlossiness
.
glossinessFactor
!==
undefined
?
pbrSpecularGlossiness
.
glossinessFactor
:
1.0
;
params
.
specular
=
new
THREE
.
Color
(
1.0
,
1.0
,
1.0
);
if
(
Array
.
isArray
(
pbrSpecularGlossiness
.
specularFactor
)
)
{
params
.
specular
.
fromArray
(
pbrSpecularGlossiness
.
specularFactor
);
}
if
(
pbrSpecularGlossiness
.
specularGlossinessTexture
!==
undefined
)
{
var
specGlossIndex
=
pbrSpecularGlossiness
.
specularGlossinessTexture
.
index
;
pending
.
push
(
parser
.
assignTexture
(
params
,
'
glossinessMap
'
,
specGlossIndex
)
);
pending
.
push
(
parser
.
assignTexture
(
params
,
'
specularMap
'
,
specGlossIndex
)
);
}
return
Promise
.
all
(
pending
);
},
createMaterial
:
function
(
params
)
{
// setup material properties based on MeshStandardMaterial for Specular-Glossiness
var
material
=
new
THREE
.
ShaderMaterial
(
{
defines
:
params
.
defines
,
vertexShader
:
params
.
vertexShader
,
fragmentShader
:
params
.
fragmentShader
,
uniforms
:
params
.
uniforms
,
fog
:
true
,
lights
:
true
,
opacity
:
params
.
opacity
,
transparent
:
params
.
transparent
}
);
material
.
isGLTFSpecularGlossinessMaterial
=
true
;
material
.
color
=
params
.
color
;
material
.
map
=
params
.
map
===
undefined
?
null
:
params
.
map
;
material
.
lightMap
=
null
;
material
.
lightMapIntensity
=
1.0
;
material
.
aoMap
=
params
.
aoMap
===
undefined
?
null
:
params
.
aoMap
;
material
.
aoMapIntensity
=
1.0
;
material
.
emissive
=
params
.
emissive
;
material
.
emissiveIntensity
=
1.0
;
material
.
emissiveMap
=
params
.
emissiveMap
===
undefined
?
null
:
params
.
emissiveMap
;
material
.
bumpMap
=
params
.
bumpMap
===
undefined
?
null
:
params
.
bumpMap
;
material
.
bumpScale
=
1
;
material
.
normalMap
=
params
.
normalMap
===
undefined
?
null
:
params
.
normalMap
;
material
.
normalScale
=
new
THREE
.
Vector2
(
1
,
1
);
material
.
displacementMap
=
null
;
material
.
displacementScale
=
1
;
material
.
displacementBias
=
0
;
material
.
specularMap
=
params
.
specularMap
===
undefined
?
null
:
params
.
specularMap
;
material
.
specular
=
params
.
specular
;
material
.
glossinessMap
=
params
.
glossinessMap
===
undefined
?
null
:
params
.
glossinessMap
;
material
.
glossiness
=
params
.
glossiness
;
material
.
alphaMap
=
null
;
material
.
envMap
=
params
.
envMap
===
undefined
?
null
:
params
.
envMap
;
material
.
envMapIntensity
=
1.0
;
material
.
refractionRatio
=
0.98
;
material
.
extensions
.
derivatives
=
true
;
return
material
;
},
// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.
refreshUniforms
:
function
(
renderer
,
scene
,
camera
,
geometry
,
material
,
group
)
{
var
uniforms
=
material
.
uniforms
;
var
defines
=
material
.
defines
;
uniforms
.
opacity
.
value
=
material
.
opacity
;
uniforms
.
diffuse
.
value
.
copy
(
material
.
color
);
uniforms
.
emissive
.
value
.
copy
(
material
.
emissive
).
multiplyScalar
(
material
.
emissiveIntensity
);
uniforms
.
map
.
value
=
material
.
map
;
uniforms
.
specularMap
.
value
=
material
.
specularMap
;
uniforms
.
alphaMap
.
value
=
material
.
alphaMap
;
uniforms
.
lightMap
.
value
=
material
.
lightMap
;
uniforms
.
lightMapIntensity
.
value
=
material
.
lightMapIntensity
;
uniforms
.
aoMap
.
value
=
material
.
aoMap
;
uniforms
.
aoMapIntensity
.
value
=
material
.
aoMapIntensity
;
// uv repeat and offset setting priorities
// 1. color map
// 2. specular map
// 3. normal map
// 4. bump map
// 5. alpha map
// 6. emissive map
var
uvScaleMap
;
if
(
material
.
map
)
{
uvScaleMap
=
material
.
map
;
}
else
if
(
material
.
specularMap
)
{
uvScaleMap
=
material
.
specularMap
;
}
else
if
(
material
.
displacementMap
)
{
uvScaleMap
=
material
.
displacementMap
;
}
else
if
(
material
.
normalMap
)
{
uvScaleMap
=
material
.
normalMap
;
}
else
if
(
material
.
bumpMap
)
{
uvScaleMap
=
material
.
bumpMap
;
}
else
if
(
material
.
glossinessMap
)
{
uvScaleMap
=
material
.
glossinessMap
;
}
else
if
(
material
.
alphaMap
)
{
uvScaleMap
=
material
.
alphaMap
;
}
else
if
(
material
.
emissiveMap
)
{
uvScaleMap
=
material
.
emissiveMap
;
}
if
(
uvScaleMap
!==
undefined
)
{
// backwards compatibility
if
(
uvScaleMap
.
isWebGLRenderTarget
)
{
uvScaleMap
=
uvScaleMap
.
texture
;
}
var
offset
=
uvScaleMap
.
offset
;
var
repeat
=
uvScaleMap
.
repeat
;
uniforms
.
offsetRepeat
.
value
.
set
(
offset
.
x
,
offset
.
y
,
repeat
.
x
,
repeat
.
y
);
}
uniforms
.
envMap
.
value
=
material
.
envMap
;
uniforms
.
envMapIntensity
.
value
=
material
.
envMapIntensity
;
uniforms
.
flipEnvMap
.
value
=
(
material
.
envMap
&&
material
.
envMap
.
isCubeTexture
)
?
-
1
:
1
;
uniforms
.
refractionRatio
.
value
=
material
.
refractionRatio
;
uniforms
.
specular
.
value
.
copy
(
material
.
specular
);
uniforms
.
glossiness
.
value
=
material
.
glossiness
;
uniforms
.
glossinessMap
.
value
=
material
.
glossinessMap
;
uniforms
.
emissiveMap
.
value
=
material
.
emissiveMap
;
uniforms
.
bumpMap
.
value
=
material
.
bumpMap
;
uniforms
.
normalMap
.
value
=
material
.
normalMap
;
uniforms
.
displacementMap
.
value
=
material
.
displacementMap
;
uniforms
.
displacementScale
.
value
=
material
.
displacementScale
;
uniforms
.
displacementBias
.
value
=
material
.
displacementBias
;
if
(
uniforms
.
glossinessMap
.
value
!==
null
&&
defines
.
USE_GLOSSINESSMAP
===
undefined
)
{
defines
.
USE_GLOSSINESSMAP
=
''
;
// set USE_ROUGHNESSMAP to enable vUv
defines
.
USE_ROUGHNESSMAP
=
''
;
}
if
(
uniforms
.
glossinessMap
.
value
===
null
&&
defines
.
USE_GLOSSINESSMAP
!==
undefined
)
{
delete
defines
.
USE_GLOSSINESSMAP
;
delete
defines
.
USE_ROUGHNESSMAP
;
}
}
};
}
/*********************************/
/********** INTERNALS ************/
...
...
@@ -421,13 +779,15 @@ THREE.GLTFLoader = ( function () {
LINEAR
:
9729
,
REPEAT
:
10497
,
SAMPLER_2D
:
35678
,
TRIANGLES
:
4
,
POINTS
:
0
,
LINES
:
1
,
LINE_LOOP
:
2
,
LINE_STRIP
:
3
,
TRIANGLES
:
4
,
TRIANGLE_STRIP
:
5
,
TRIANGLE_FAN
:
6
,
UNSIGNED_BYTE
:
5121
,
UNSIGNED_SHORT
:
5123
,
VERTEX_SHADER
:
35633
,
FRAGMENT_SHADER
:
35632
UNSIGNED_SHORT
:
5123
};
var
WEBGL_TYPE
=
{
...
...
@@ -535,10 +895,13 @@ THREE.GLTFLoader = ( function () {
var
PATH_PROPERTIES
=
{
scale
:
'
scale
'
,
translation
:
'
position
'
,
rotation
:
'
quaternion
'
rotation
:
'
quaternion
'
,
weights
:
'
morphTargetInfluences
'
};
var
INTERPOLATION
=
{
CATMULLROMSPLINE
:
THREE
.
InterpolateSmooth
,
CUBICSPLINE
:
THREE
.
InterpolateSmooth
,
LINEAR
:
THREE
.
InterpolateLinear
,
STEP
:
THREE
.
InterpolateDiscrete
};
...
...
@@ -552,6 +915,12 @@ THREE.GLTFLoader = ( function () {
32926
:
'
SAMPLE_ALPHA_TO_COVERAGE
'
};
var
ALPHA_MODES
=
{
OPAQUE
:
'
OPAQUE
'
,
MASK
:
'
MASK
'
,
BLEND
:
'
BLEND
'
};
/* UTILITY FUNCTIONS */
function
_each
(
object
,
callback
,
thisObj
)
{
...
...
@@ -659,6 +1028,13 @@ THREE.GLTFLoader = ( function () {
}
// Blob URL
if
(
/^blob:.*$/i
.
test
(
url
)
)
{
return
url
;
}
// Relative URL
return
(
path
||
''
)
+
url
;
...
...
@@ -687,151 +1063,141 @@ THREE.GLTFLoader = ( function () {
}
// Three.js seems too dependent on attribute names so globally
// replace those in the shader code
function
replaceTHREEShaderAttributes
(
shaderText
,
technique
)
{
// Expected technique attributes
var
attributes
=
{};
for
(
var
attributeId
in
technique
.
attributes
)
{
var
pname
=
technique
.
attributes
[
attributeId
];
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
*/
function
createDefaultMaterial
()
{
var
param
=
technique
.
parameters
[
pname
];
var
atype
=
param
.
type
;
var
semantic
=
param
.
semantic
;
return
new
THREE
.
MeshStandardMaterial
(
{
color
:
0xFFFFFF
,
emissive
:
0x000000
,
metalness
:
1
,
roughness
:
1
,
transparent
:
false
,
depthTest
:
true
,
side
:
THREE
.
FrontSide
}
);
attributes
[
attributeId
]
=
{
type
:
atype
,
semantic
:
semantic
};
}
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
* @param {THREE.Mesh} mesh
* @param {GLTF.Mesh} meshDef
* @param {GLTF.Primitive} primitiveDef
* @param {Object} dependencies
*/
function
addMorphTargets
(
mesh
,
meshDef
,
primitiveDef
,
dependencies
)
{
// Figure out which attributes to change in technique
var
geometry
=
mesh
.
geometry
;
var
material
=
mesh
.
material
;
var
shaderParams
=
technique
.
parameters
;
var
shaderAttributes
=
technique
.
attributes
;
var
params
=
{};
var
targets
=
primitiveDef
.
targets
;
var
morphAttributes
=
geometry
.
morphAttributes
;
for
(
var
attributeId
in
attributes
)
{
morphAttributes
.
position
=
[];
morphAttributes
.
normal
=
[];
var
pname
=
shaderAttributes
[
attributeId
];
var
shaderParam
=
shaderParams
[
pname
];
var
semantic
=
shaderParam
.
semantic
;
if
(
semantic
)
{
material
.
morphTargets
=
true
;
params
[
attributeId
]
=
shaderParam
;
for
(
var
i
=
0
,
il
=
targets
.
length
;
i
<
il
;
i
++
)
{
}
var
target
=
targets
[
i
];
var
attributeName
=
'
morphTarget
'
+
i
;
}
var
positionAttribute
,
normalAttribute
;
for
(
var
pname
in
params
)
{
if
(
target
.
POSITION
!==
undefined
)
{
var
param
=
params
[
pname
];
var
semantic
=
param
.
semantic
;
// Three.js morph formula is
// position
// + weight0 * ( morphTarget0 - position )
// + weight1 * ( morphTarget1 - position )
// ...
// while the glTF one is
// position
// + weight0 * morphTarget0
// + weight1 * morphTarget1
// ...
// then adding position to morphTarget.
// So morphTarget value will depend on mesh's position, then cloning attribute
// for the case if attribute is shared among two or more meshes.
var
regEx
=
new
RegExp
(
"
\\
b
"
+
pname
+
"
\\
b
"
,
"
g
"
);
positionAttribute
=
dependencies
.
accessors
[
target
.
POSITION
].
clone
();
var
position
=
geometry
.
attributes
.
position
;
switch
(
semantic
)
{
for
(
var
j
=
0
,
jl
=
positionAttribute
.
count
;
j
<
jl
;
j
++
)
{
case
"
POSITION
"
:
positionAttribute
.
setXYZ
(
j
,
positionAttribute
.
getX
(
j
)
+
position
.
getX
(
j
),
positionAttribute
.
getY
(
j
)
+
position
.
getY
(
j
),
positionAttribute
.
getZ
(
j
)
+
position
.
getZ
(
j
)
);
shaderText
=
shaderText
.
replace
(
regEx
,
'
position
'
);
break
;
}
case
"
NORMAL
"
:
}
else
{
shaderText
=
shaderText
.
replace
(
regEx
,
'
normal
'
);
break
;
// Copying the original position not to affect the final position.
// See the formula above.
positionAttribute
=
geometry
.
attributes
.
position
.
clone
();
case
'
TEXCOORD_0
'
:
case
'
TEXCOORD0
'
:
case
'
TEXCOORD
'
:
}
shaderText
=
shaderText
.
replace
(
regEx
,
'
uv
'
);
break
;
if
(
target
.
NORMAL
!==
undefined
)
{
case
'
TEXCOORD_1
'
:
material
.
morphNormals
=
true
;
shaderText
=
shaderText
.
replace
(
regEx
,
'
uv2
'
);
break
;
// see target.POSITION's comment
case
'
COLOR_0
'
:
case
'
COLOR0
'
:
case
'
COLOR
'
:
normalAttribute
=
dependencies
.
accessors
[
target
.
NORMAL
].
clone
();
var
normal
=
geometry
.
attributes
.
normal
;
shaderText
=
shaderText
.
replace
(
regEx
,
'
color
'
);
break
;
for
(
var
j
=
0
,
jl
=
normalAttribute
.
count
;
j
<
jl
;
j
++
)
{
case
"
WEIGHT
"
:
normalAttribute
.
setXYZ
(
j
,
normalAttribute
.
getX
(
j
)
+
normal
.
getX
(
j
),
normalAttribute
.
getY
(
j
)
+
normal
.
getY
(
j
),
normalAttribute
.
getZ
(
j
)
+
normal
.
getZ
(
j
)
);
shaderText
=
shaderText
.
replace
(
regEx
,
'
skinWeight
'
);
break
;
}
case
"
JOINT
"
:
}
else
{
shaderText
=
shaderText
.
replace
(
regEx
,
'
skinIndex
'
);
break
;
normalAttribute
=
geometry
.
attributes
.
normal
.
clone
();
}
}
return
shaderText
;
}
function
createDefaultMaterial
()
{
return
new
THREE
.
MeshPhongMaterial
(
{
color
:
0x00000
,
emissive
:
0x888888
,
specular
:
0x000000
,
shininess
:
0
,
transparent
:
false
,
depthTest
:
true
,
side
:
THREE
.
FrontSide
}
);
}
// Deferred constructor for RawShaderMaterial types
function
DeferredShaderMaterial
(
params
)
{
if
(
target
.
TANGENT
!==
undefined
)
{
this
.
isDeferredShaderMaterial
=
true
;
// TODO: implement
this
.
params
=
params
;
}
}
positionAttribute
.
name
=
attributeName
;
normalAttribute
.
name
=
attributeName
;
DeferredShaderMaterial
.
prototype
.
create
=
function
()
{
morphAttributes
.
position
.
push
(
positionAttribute
);
morphAttributes
.
normal
.
push
(
normalAttribute
);
var
uniforms
=
THREE
.
UniformsUtils
.
clone
(
this
.
params
.
uniforms
);
}
for
(
var
uniformId
in
this
.
params
.
uniforms
)
{
mesh
.
updateMorphTargets
();
var
originalUniform
=
this
.
params
.
uniforms
[
uniformId
];
if
(
meshDef
.
weights
!==
undefined
)
{
if
(
originalUniform
.
value
instanceof
THREE
.
Texture
)
{
for
(
var
i
=
0
,
il
=
meshDef
.
weights
.
length
;
i
<
il
;
i
++
)
{
uniforms
[
uniformId
].
value
=
originalUniform
.
value
;
uniforms
[
uniformId
].
value
.
needsUpdate
=
true
;
mesh
.
morphTargetInfluences
[
i
]
=
meshDef
.
weights
[
i
];
}
uniforms
[
uniformId
].
semantic
=
originalUniform
.
semantic
;
uniforms
[
uniformId
].
node
=
originalUniform
.
node
;
}
this
.
params
.
uniforms
=
uniforms
;
return
new
THREE
.
RawShaderMaterial
(
this
.
params
);
};
}
/* GLTF PARSER */
...
...
@@ -853,7 +1219,7 @@ THREE.GLTFLoader = ( function () {
for
(
var
i
=
0
;
i
<
dependencies
.
length
;
i
++
)
{
var
dependency
=
dependencies
[
i
];
var
fnName
=
"
load
"
+
dependency
.
charAt
(
0
).
toUpperCase
()
+
dependency
.
slice
(
1
);
var
fnName
=
'
load
'
+
dependency
.
charAt
(
0
).
toUpperCase
()
+
dependency
.
slice
(
1
);
var
cached
=
this
.
cache
.
get
(
dependency
);
...
...
@@ -880,7 +1246,7 @@ THREE.GLTFLoader = ( function () {
};
GLTFParser
.
prototype
.
parse
=
function
(
callback
)
{
GLTFParser
.
prototype
.
parse
=
function
(
onLoad
,
onError
)
{
var
json
=
this
.
json
;
...
...
@@ -890,9 +1256,9 @@ THREE.GLTFLoader = ( function () {
// Fire the callback on complete
this
.
_withDependencies
(
[
"
scenes
"
,
"
cameras
"
,
"
animations
"
'
scenes
'
,
'
cameras
'
,
'
animations
'
]
).
then
(
function
(
dependencies
)
{
...
...
@@ -923,661 +1289,472 @@ THREE.GLTFLoader = ( function () {
}
callback
(
scene
,
scenes
,
cameras
,
animations
);
onLoad
(
scene
,
scenes
,
cameras
,
animations
);
}
);
}
)
.
catch
(
onError
)
;
};
GLTFParser
.
prototype
.
loadShaders
=
function
()
{
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
var
options
=
this
.
options
;
return
this
.
_withDependencies
(
[
"
bufferViews
"
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
shaders
,
function
(
shader
)
{
if
(
shader
.
extensions
&&
shader
.
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
]
)
{
return
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
loadShader
(
shader
,
dependencies
.
bufferViews
);
}
return
new
Promise
(
function
(
resolve
)
{
var
loader
=
new
THREE
.
FileLoader
();
loader
.
setResponseType
(
'
text
'
);
loader
.
load
(
resolveURL
(
shader
.
uri
,
options
.
path
),
function
(
shaderText
)
{
resolve
(
shaderText
);
}
);
}
);
}
);
}
);
};
/**
* Requests the specified dependency asynchronously, with caching.
* @param {string} type
* @param {number} index
* @return {Promise<Object>}
*/
GLTFParser
.
prototype
.
getDependency
=
function
(
type
,
index
)
{
GLTFParser
.
prototype
.
loadBuffers
=
function
()
{
var
cacheKey
=
type
+
'
:
'
+
index
;
var
dependency
=
this
.
cache
.
get
(
cacheKey
);
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
var
options
=
this
.
options
;
return
_each
(
json
.
buffers
,
function
(
buffer
,
name
)
{
if
(
name
===
BINARY_EXTENSION_BUFFER_NAME
)
{
return
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
body
;
}
if
(
buffer
.
type
===
'
arraybuffer
'
||
buffer
.
type
===
undefined
)
{
return
new
Promise
(
function
(
resolve
)
{
var
loader
=
new
THREE
.
FileLoader
();
loader
.
setResponseType
(
'
arraybuffer
'
);
loader
.
load
(
resolveURL
(
buffer
.
uri
,
options
.
path
),
function
(
buffer
)
{
resolve
(
buffer
);
}
);
}
);
}
else
{
console
.
warn
(
'
THREE.GLTFLoader:
'
+
buffer
.
type
+
'
buffer type is not supported
'
);
}
}
);
};
GLTFParser
.
prototype
.
loadBufferViews
=
function
()
{
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
"
buffers
"
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
bufferViews
,
function
(
bufferView
)
{
var
arraybuffer
=
dependencies
.
buffers
[
bufferView
.
buffer
];
var
byteLength
=
bufferView
.
byteLength
!==
undefined
?
bufferView
.
byteLength
:
0
;
return
arraybuffer
.
slice
(
bufferView
.
byteOffset
,
bufferView
.
byteOffset
+
byteLength
);
}
);
}
);
};
GLTFParser
.
prototype
.
loadAccessors
=
function
()
{
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
"
bufferViews
"
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
accessors
,
function
(
accessor
)
{
var
arraybuffer
=
dependencies
.
bufferViews
[
accessor
.
bufferView
];
var
itemSize
=
WEBGL_TYPE_SIZES
[
accessor
.
type
];
var
TypedArray
=
WEBGL_COMPONENT_TYPES
[
accessor
.
componentType
];
// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
var
elementBytes
=
TypedArray
.
BYTES_PER_ELEMENT
;
var
itemBytes
=
elementBytes
*
itemSize
;
// The buffer is not interleaved if the stride is the item size in bytes.
if
(
accessor
.
byteStride
&&
accessor
.
byteStride
!==
itemBytes
)
{
// Use the full buffer if it's interleaved.
var
array
=
new
TypedArray
(
arraybuffer
);
// Integer parameters to IB/IBA are in array elements, not bytes.
var
ib
=
new
THREE
.
InterleavedBuffer
(
array
,
accessor
.
byteStride
/
elementBytes
);
return
new
THREE
.
InterleavedBufferAttribute
(
ib
,
itemSize
,
accessor
.
byteOffset
/
elementBytes
);
}
else
{
array
=
new
TypedArray
(
arraybuffer
,
accessor
.
byteOffset
,
accessor
.
count
*
itemSize
);
return
new
THREE
.
BufferAttribute
(
array
,
itemSize
);
}
}
);
}
);
};
GLTFParser
.
prototype
.
loadTextures
=
function
()
{
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
var
options
=
this
.
options
;
return
this
.
_withDependencies
(
[
"
bufferViews
"
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
textures
,
function
(
texture
)
{
if
(
texture
.
source
)
{
return
new
Promise
(
function
(
resolve
)
{
var
source
=
json
.
images
[
texture
.
source
];
var
sourceUri
=
source
.
uri
;
if
(
source
.
extensions
&&
source
.
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
]
)
{
sourceUri
=
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
loadTextureSourceUri
(
source
,
dependencies
.
bufferViews
);
}
var
textureLoader
=
THREE
.
Loader
.
Handlers
.
get
(
sourceUri
);
if
(
textureLoader
===
null
)
{
textureLoader
=
new
THREE
.
TextureLoader
();
}
textureLoader
.
setCrossOrigin
(
options
.
crossOrigin
);
textureLoader
.
load
(
resolveURL
(
sourceUri
,
options
.
path
),
function
(
_texture
)
{
_texture
.
flipY
=
false
;
if
(
texture
.
name
!==
undefined
)
_texture
.
name
=
texture
.
name
;
_texture
.
format
=
texture
.
format
!==
undefined
?
WEBGL_TEXTURE_FORMATS
[
texture
.
format
]
:
THREE
.
RGBAFormat
;
if
(
texture
.
internalFormat
!==
undefined
&&
_texture
.
format
!==
WEBGL_TEXTURE_FORMATS
[
texture
.
internalFormat
]
)
{
console
.
warn
(
'
THREE.GLTFLoader: Three.js doesn
\'
t support texture internalFormat which is different from texture format.
'
+
'
internalFormat will be forced to be the same value as format.
'
);
}
_texture
.
type
=
texture
.
type
!==
undefined
?
WEBGL_TEXTURE_DATATYPES
[
texture
.
type
]
:
THREE
.
UnsignedByteType
;
if
(
texture
.
sampler
)
{
var
sampler
=
json
.
samplers
[
texture
.
sampler
];
_texture
.
magFilter
=
WEBGL_FILTERS
[
sampler
.
magFilter
]
||
THREE
.
LinearFilter
;
_texture
.
minFilter
=
WEBGL_FILTERS
[
sampler
.
minFilter
]
||
THREE
.
NearestMipMapLinearFilter
;
_texture
.
wrapS
=
WEBGL_WRAPPINGS
[
sampler
.
wrapS
]
||
THREE
.
RepeatWrapping
;
_texture
.
wrapT
=
WEBGL_WRAPPINGS
[
sampler
.
wrapT
]
||
THREE
.
RepeatWrapping
;
}
resolve
(
_texture
);
},
undefined
,
function
()
{
resolve
();
}
);
}
);
}
}
);
}
);
};
GLTFParser
.
prototype
.
loadMaterials
=
function
()
{
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
if
(
!
dependency
)
{
"
shaders
"
,
"
textures
"
var
fnName
=
'
load
'
+
type
.
charAt
(
0
).
toUpperCase
()
+
type
.
slice
(
1
);
dependency
=
this
[
fnName
](
index
);
this
.
cache
.
add
(
cacheKey
,
dependency
);
]
).
then
(
function
(
dependencies
)
{
}
return
_each
(
json
.
materials
,
function
(
material
)
{
return
dependency
;
var
materialType
;
var
materialValues
=
{};
var
materialParams
=
{};
};
var
khr_material
;
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
* @param {number} bufferIndex
* @return {Promise<ArrayBuffer>}
*/
GLTFParser
.
prototype
.
loadBuffer
=
function
(
bufferIndex
)
{
if
(
material
.
extensions
&&
material
.
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
)
{
var
bufferDef
=
this
.
json
.
buffers
[
bufferIndex
];
khr_material
=
material
.
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
];
if
(
bufferDef
.
type
&&
bufferDef
.
type
!==
'
arraybuffer
'
)
{
}
throw
new
Error
(
'
THREE.GLTFLoader: %s buffer type is not supported.
'
,
bufferDef
.
type
);
if
(
khr_material
)
{
}
// don't copy over unused values to avoid material warning spam
var
keys
=
[
'
ambient
'
,
'
emission
'
,
'
transparent
'
,
'
transparency
'
,
'
doubleSided
'
];
// If present, GLB container is required to be the first buffer.
if
(
bufferDef
.
uri
===
undefined
&&
bufferIndex
===
0
)
{
switch
(
khr_material
.
technique
)
{
return
Promise
.
resolve
(
this
.
extensions
[
EXTENSIONS
.
KHR_BINARY_GLTF
].
body
);
case
'
BLINN
'
:
case
'
PHONG
'
:
materialType
=
THREE
.
MeshPhongMaterial
;
keys
.
push
(
'
diffuse
'
,
'
specular
'
,
'
shininess
'
);
break
;
}
case
'
LAMBERT
'
:
materialType
=
THREE
.
MeshLambertMaterial
;
keys
.
push
(
'
diffuse
'
);
break
;
var
options
=
this
.
options
;
case
'
CONSTANT
'
:
default
:
materialType
=
THREE
.
MeshBasicMaterial
;
break
;
return
new
Promise
(
function
(
resolve
)
{
}
var
loader
=
new
THREE
.
FileLoader
();
loader
.
setResponseType
(
'
arraybuffer
'
);
loader
.
load
(
resolveURL
(
bufferDef
.
uri
,
options
.
path
),
resolve
);
keys
.
forEach
(
function
(
v
)
{
}
);
if
(
khr_material
.
values
[
v
]
!==
undefined
)
materialValues
[
v
]
=
khr_material
.
values
[
v
]
;
}
;
}
);
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
* @param {number} bufferViewIndex
* @return {Promise<ArrayBuffer>}
*/
GLTFParser
.
prototype
.
loadBufferView
=
function
(
bufferViewIndex
)
{
if
(
khr_material
.
doubleSided
||
materialValues
.
doubleSided
)
{
var
bufferViewDef
=
this
.
json
.
bufferViews
[
bufferViewIndex
];
materialParams
.
side
=
THREE
.
DoubleSide
;
return
this
.
getDependency
(
'
buffer
'
,
bufferViewDef
.
buffer
).
then
(
function
(
buffer
)
{
}
var
byteLength
=
bufferViewDef
.
byteLength
||
0
;
var
byteOffset
=
bufferViewDef
.
byteOffset
||
0
;
return
buffer
.
slice
(
byteOffset
,
byteOffset
+
byteLength
);
if
(
khr_material
.
transparent
||
materialValues
.
transparent
)
{
}
);
materialParams
.
transparent
=
true
;
materialParams
.
opacity
=
(
materialValues
.
transparency
!==
undefined
)
?
materialValues
.
transparency
:
1
;
};
}
GLTFParser
.
prototype
.
loadAccessors
=
function
()
{
}
else
if
(
material
.
technique
===
undefined
)
{
var
parser
=
this
;
var
json
=
this
.
json
;
materialType
=
THREE
.
MeshPhongMaterial
;
return
_each
(
json
.
accessors
,
function
(
accessor
)
{
Object
.
assign
(
materialValues
,
material
.
values
);
return
parser
.
getDependency
(
'
bufferView
'
,
accessor
.
bufferView
).
then
(
function
(
bufferView
)
{
}
else
{
var
itemSize
=
WEBGL_TYPE_SIZES
[
accessor
.
type
];
var
TypedArray
=
WEBGL_COMPONENT_TYPES
[
accessor
.
componentType
];
materialType
=
DeferredShaderMaterial
;
// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
var
elementBytes
=
TypedArray
.
BYTES_PER_ELEMENT
;
var
itemBytes
=
elementBytes
*
itemSize
;
var
byteStride
=
json
.
bufferViews
[
accessor
.
bufferView
].
byteStride
;
var
array
;
var
technique
=
json
.
techniques
[
material
.
technique
];
// The buffer is not interleaved if the stride is the item size in bytes.
if
(
byteStride
&&
byteStride
!==
itemBytes
)
{
materialParams
.
uniforms
=
{};
// Use the full buffer if it's interleaved.
array
=
new
TypedArray
(
bufferView
);
var
program
=
json
.
programs
[
technique
.
program
];
// Integer parameters to IB/IBA are in array elements, not bytes.
var
ib
=
new
THREE
.
InterleavedBuffer
(
array
,
byteStride
/
elementBytes
);
if
(
program
)
{
return
new
THREE
.
InterleavedBufferAttribute
(
ib
,
itemSize
,
accessor
.
byteOffset
/
elementBytes
);
materialParams
.
fragmentShader
=
dependencies
.
shaders
[
program
.
fragmentShader
];
}
else
{
if
(
!
materialParams
.
fragmentShader
)
{
array
=
new
TypedArray
(
bufferView
,
accessor
.
byteOffset
,
accessor
.
count
*
itemSize
);
console
.
warn
(
"
ERROR: Missing fragment shader definition:
"
,
program
.
fragmentShader
);
materialType
=
THREE
.
MeshPhongMaterial
;
return
new
THREE
.
BufferAttribute
(
array
,
itemSize
);
}
}
var
vertexShader
=
dependencies
.
shaders
[
program
.
vertexShader
]
;
}
)
;
if
(
!
vertexShader
)
{
}
);
console
.
warn
(
"
ERROR: Missing vertex shader definition:
"
,
program
.
vertexShader
);
materialType
=
THREE
.
MeshPhongMaterial
;
};
}
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
* @param {number} textureIndex
* @return {Promise<THREE.Texture>}
*/
GLTFParser
.
prototype
.
loadTexture
=
function
(
textureIndex
)
{
// IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS
materialParams
.
vertexShader
=
replaceTHREEShaderAttributes
(
vertexShader
,
technique
);
var
parser
=
this
;
var
json
=
this
.
json
;
var
options
=
this
.
options
;
var
uniforms
=
technique
.
uniforms
;
var
URL
=
window
.
URL
||
window
.
webkitURL
;
for
(
var
uniformId
in
uniforms
)
{
var
textureDef
=
json
.
textures
[
textureIndex
];
var
source
=
json
.
images
[
textureDef
.
source
];
var
sourceURI
=
source
.
uri
;
var
isObjectURL
=
false
;
var
pname
=
uniforms
[
uniformId
];
var
shaderParam
=
technique
.
parameters
[
pname
];
if
(
source
.
bufferView
!==
undefined
)
{
var
ptype
=
shaderParam
.
type
;
// Load binary image data from bufferView, if provided.
if
(
WEBGL_TYPE
[
ptype
]
)
{
sourceURI
=
parser
.
getDependency
(
'
bufferView
'
,
source
.
bufferView
)
.
then
(
function
(
bufferView
)
{
var
pcount
=
shaderParam
.
count
;
var
value
;
isObjectURL
=
true
;
var
blob
=
new
Blob
(
[
bufferView
],
{
type
:
source
.
mimeType
}
);
sourceURI
=
URL
.
createObjectURL
(
blob
);
return
sourceURI
;
if
(
material
.
values
!==
undefined
)
value
=
material
.
values
[
pname
]
;
}
)
;
var
uvalue
=
new
WEBGL_TYPE
[
ptype
]();
var
usemantic
=
shaderParam
.
semantic
;
var
unode
=
shaderParam
.
node
;
}
switch
(
ptype
)
{
return
Promise
.
resolve
(
sourceURI
).
then
(
function
(
sourceURI
)
{
case
WEBGL_CONSTANTS
.
FLOAT
:
// Load Texture resource.
uvalue
=
shaderParam
.
value
;
var
textureLoader
=
THREE
.
Loader
.
Handlers
.
get
(
sourceURI
)
||
new
THREE
.
TextureLoader
();
textureLoader
.
setCrossOrigin
(
options
.
crossOrigin
);
if
(
pname
==
"
transparency
"
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
materialParams
.
transparent
=
true
;
textureLoader
.
load
(
resolveURL
(
sourceURI
,
options
.
path
),
resolve
,
undefined
,
reject
)
;
}
}
);
if
(
value
!==
undefined
)
{
}
).
then
(
function
(
texture
)
{
uvalue
=
value
;
// Clean up resources and configure Texture.
}
if
(
isObjectURL
!==
undefined
)
{
break
;
URL
.
revokeObjectURL
(
sourceURI
)
;
case
WEBGL_CONSTANTS
.
FLOAT_VEC2
:
case
WEBGL_CONSTANTS
.
FLOAT_VEC3
:
case
WEBGL_CONSTANTS
.
FLOAT_VEC4
:
case
WEBGL_CONSTANTS
.
FLOAT_MAT3
:
}
if
(
shaderParam
&&
shaderParam
.
value
)
{
texture
.
flipY
=
false
;
uvalue
.
fromArray
(
shaderParam
.
value
)
;
if
(
textureDef
.
name
!==
undefined
)
texture
.
name
=
textureDef
.
name
;
}
texture
.
format
=
textureDef
.
format
!==
undefined
?
WEBGL_TEXTURE_FORMATS
[
textureDef
.
format
]
:
THREE
.
RGBAFormat
;
if
(
value
)
{
if
(
textureDef
.
internalFormat
!==
undefined
&&
texture
.
format
!==
WEBGL_TEXTURE_FORMATS
[
textureDef
.
internalFormat
]
)
{
uvalue
.
fromArray
(
value
);
console
.
warn
(
'
THREE.GLTFLoader: Three.js does not support texture internalFormat which is different from texture format.
'
+
'
internalFormat will be forced to be the same value as format.
'
);
}
}
break
;
texture
.
type
=
textureDef
.
type
!==
undefined
?
WEBGL_TEXTURE_DATATYPES
[
textureDef
.
type
]
:
THREE
.
UnsignedByteType
;
case
WEBGL_CONSTANTS
.
FLOAT_MAT2
:
var
samplers
=
json
.
samplers
||
{};
var
sampler
=
samplers
[
textureDef
.
sampler
]
||
{};
// what to do?
console
.
warn
(
"
FLOAT_MAT2 is not a supported uniform type
"
);
break
;
texture
.
magFilter
=
WEBGL_FILTERS
[
sampler
.
magFilter
]
||
THREE
.
LinearFilter
;
texture
.
minFilter
=
WEBGL_FILTERS
[
sampler
.
minFilter
]
||
THREE
.
LinearMipMapLinearFilter
;
texture
.
wrapS
=
WEBGL_WRAPPINGS
[
sampler
.
wrapS
]
||
THREE
.
RepeatWrapping
;
texture
.
wrapT
=
WEBGL_WRAPPINGS
[
sampler
.
wrapT
]
||
THREE
.
RepeatWrapping
;
case
WEBGL_CONSTANTS
.
FLOAT_MAT4
:
return
texture
;
if
(
pcount
)
{
}
);
uvalue
=
new
Array
(
pcount
)
;
}
;
for
(
var
mi
=
0
;
mi
<
pcount
;
mi
++
)
{
/**
* Asynchronously assigns a texture to the given material parameters.
* @param {Object} materialParams
* @param {string} textureName
* @param {number} textureIndex
* @return {Promise}
*/
GLTFParser
.
prototype
.
assignTexture
=
function
(
materialParams
,
textureName
,
textureIndex
)
{
uvalue
[
mi
]
=
new
WEBGL_TYPE
[
ptype
]();
return
this
.
getDependency
(
'
texture
'
,
textureIndex
).
then
(
function
(
texture
)
{
}
materialParams
[
textureName
]
=
texture
;
if
(
shaderParam
&&
shaderParam
.
value
)
{
}
);
var
m4v
=
shaderParam
.
value
;
uvalue
.
fromArray
(
m4v
);
};
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
* @return {Promise<Array<THREE.Material>>}
*/
GLTFParser
.
prototype
.
loadMaterials
=
function
()
{
if
(
value
)
{
var
parser
=
this
;
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
uvalue
.
fromArray
(
value
);
return
_each
(
json
.
materials
,
function
(
material
)
{
}
var
materialType
;
var
materialParams
=
{};
var
materialExtensions
=
material
.
extensions
||
{};
}
else
{
var
pending
=
[];
if
(
shaderParam
&&
shaderParam
.
value
)
{
if
(
materialExtensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
]
)
{
var
m4
=
shaderParam
.
value
;
uvalue
.
fromArray
(
m4
);
var
khcExtension
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
];
materialType
=
khcExtension
.
getMaterialType
(
material
);
pending
.
push
(
khcExtension
.
extendParams
(
materialParams
,
material
,
parser
)
);
}
}
else
if
(
materialExtensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
]
)
{
if
(
value
)
{
var
sgExtension
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
];
materialType
=
sgExtension
.
getMaterialType
(
material
);
pending
.
push
(
sgExtension
.
extendParams
(
materialParams
,
material
,
parser
)
);
uvalue
.
fromArray
(
value
);
}
else
if
(
material
.
pbrMetallicRoughness
!==
undefined
)
{
}
// Specification:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
}
materialType
=
THREE
.
MeshStandardMaterial
;
break
;
var
metallicRoughness
=
material
.
pbrMetallicRoughness
;
case
WEBGL_CONSTANTS
.
SAMPLER_2D
:
materialParams
.
color
=
new
THREE
.
Color
(
1.0
,
1.0
,
1.0
);
materialParams
.
opacity
=
1.0
;
if
(
value
!==
undefined
)
{
if
(
Array
.
isArray
(
metallicRoughness
.
baseColorFactor
)
)
{
uvalue
=
dependencies
.
textures
[
value
]
;
var
array
=
metallicRoughness
.
baseColorFactor
;
}
else
if
(
shaderParam
.
value
!==
undefined
)
{
materialParams
.
color
.
fromArray
(
array
);
materialParams
.
opacity
=
array
[
3
];
uvalue
=
dependencies
.
textures
[
shaderParam
.
value
];
}
}
else
{
if
(
metallicRoughness
.
baseColorTexture
!==
undefined
)
{
uvalue
=
null
;
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
map
'
,
metallicRoughness
.
baseColorTexture
.
index
)
)
;
}
}
break
;
materialParams
.
metalness
=
metallicRoughness
.
metallicFactor
!==
undefined
?
metallicRoughness
.
metallicFactor
:
1.0
;
materialParams
.
roughness
=
metallicRoughness
.
roughnessFactor
!==
undefined
?
metallicRoughness
.
roughnessFactor
:
1.0
;
}
if
(
metallicRoughness
.
metallicRoughnessTexture
!==
undefined
)
{
materialParams
.
uniforms
[
uniformId
]
=
{
value
:
uvalue
,
semantic
:
usemantic
,
node
:
unode
};
var
textureIndex
=
metallicRoughness
.
metallicRoughnessTexture
.
index
;
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
metalnessMap
'
,
textureIndex
)
);
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
roughnessMap
'
,
textureIndex
)
);
}
else
{
}
throw
new
Error
(
"
Unknown shader uniform param type:
"
+
ptype
);
}
else
{
}
materialType
=
THREE
.
MeshPhongMaterial
;
}
}
var
states
=
technique
.
states
||
{};
var
enables
=
states
.
enable
||
[];
var
functions
=
states
.
functions
||
{};
if
(
material
.
doubleSided
===
true
)
{
var
enableCullFace
=
false
;
var
enableDepthTest
=
false
;
var
enableBlend
=
false
;
materialParams
.
side
=
THREE
.
DoubleSide
;
for
(
var
i
=
0
,
il
=
enables
.
length
;
i
<
il
;
i
++
)
{
}
var
enable
=
enables
[
i
]
;
var
alphaMode
=
material
.
alphaMode
||
ALPHA_MODES
.
OPAQUE
;
switch
(
STATES_ENABLES
[
enable
]
)
{
if
(
alphaMode
!==
ALPHA_MODES
.
OPAQUE
)
{
case
'
CULL_FACE
'
:
materialParams
.
transparent
=
true
;
enableCullFace
=
true
;
}
else
{
break
;
materialParams
.
transparent
=
false
;
case
'
DEPTH_TEST
'
:
}
enableDepthTest
=
true
;
if
(
material
.
normalTexture
!==
undefined
)
{
break
;
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
normalMap
'
,
material
.
normalTexture
.
index
)
)
;
case
'
BLEND
'
:
}
enableBlend
=
true
;
if
(
material
.
occlusionTexture
!==
undefined
)
{
break
;
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
aoMap
'
,
material
.
occlusionTexture
.
index
)
)
;
// TODO: implement
case
'
SCISSOR_TEST
'
:
case
'
POLYGON_OFFSET_FILL
'
:
case
'
SAMPLE_ALPHA_TO_COVERAGE
'
:
}
break
;
if
(
material
.
emissiveFactor
!==
undefined
)
{
default
:
if
(
materialType
===
THREE
.
MeshBasicMaterial
)
{
throw
new
Error
(
"
Unknown technique.states.enable:
"
+
enable
);
materialParams
.
color
=
new
THREE
.
Color
().
fromArray
(
material
.
emissiveFactor
);
}
}
else
{
}
materialParams
.
emissive
=
new
THREE
.
Color
().
fromArray
(
material
.
emissiveFactor
);
if
(
enableCullFace
)
{
}
materialParams
.
side
=
functions
.
cullFace
!==
undefined
?
WEBGL_SIDES
[
functions
.
cullFace
]
:
THREE
.
FrontSide
;
}
}
else
{
if
(
material
.
emissiveTexture
!==
undefined
)
{
materialParams
.
side
=
THREE
.
DoubleSide
;
if
(
materialType
===
THREE
.
MeshBasicMaterial
)
{
}
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
map
'
,
material
.
emissiveTexture
.
index
)
);
materialParams
.
depthTest
=
enableDepthTest
;
materialParams
.
depthFunc
=
functions
.
depthFunc
!==
undefined
?
WEBGL_DEPTH_FUNCS
[
functions
.
depthFunc
]
:
THREE
.
LessDepth
;
materialParams
.
depthWrite
=
functions
.
depthMask
!==
undefined
?
functions
.
depthMask
[
0
]
:
true
;
}
else
{
materialParams
.
blending
=
enableBlend
?
THREE
.
CustomBlending
:
THREE
.
NoBlending
;
materialParams
.
transparent
=
enableBlend
;
pending
.
push
(
parser
.
assignTexture
(
materialParams
,
'
emissiveMap
'
,
material
.
emissiveTexture
.
index
)
);
var
blendEquationSeparate
=
functions
.
blendEquationSeparate
;
}
if
(
blendEquationSeparate
!==
undefined
)
{
}
materialParams
.
blendEquation
=
WEBGL_BLEND_EQUATIONS
[
blendEquationSeparate
[
0
]
];
materialParams
.
blendEquationAlpha
=
WEBGL_BLEND_EQUATIONS
[
blendEquationSeparate
[
1
]
];
return
Promise
.
all
(
pending
).
then
(
function
()
{
}
else
{
var
_material
;
materialParams
.
blendEquation
=
THREE
.
AddEquation
;
materialParams
.
blendEquationAlpha
=
THREE
.
AddEquation
;
if
(
materialType
===
THREE
.
ShaderMaterial
)
{
}
_material
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
].
createMaterial
(
materialParams
);
var
blendFuncSeparate
=
functions
.
blendFuncSeparate
;
}
else
{
if
(
blendFuncSeparate
!==
undefined
)
{
_material
=
new
materialType
(
materialParams
);
materialParams
.
blendSrc
=
WEBGL_BLEND_FUNCS
[
blendFuncSeparate
[
0
]
];
materialParams
.
blendDst
=
WEBGL_BLEND_FUNCS
[
blendFuncSeparate
[
1
]
];
materialParams
.
blendSrcAlpha
=
WEBGL_BLEND_FUNCS
[
blendFuncSeparate
[
2
]
];
materialParams
.
blendDstAlpha
=
WEBGL_BLEND_FUNCS
[
blendFuncSeparate
[
3
]
];
}
}
else
{
if
(
material
.
name
!==
undefined
)
_material
.
name
=
material
.
name
;
materialParams
.
blendSrc
=
THREE
.
OneFactor
;
materialParams
.
blendDst
=
THREE
.
ZeroFactor
;
materialParams
.
blendSrcAlpha
=
THREE
.
OneFactor
;
materialParams
.
blendDstAlpha
=
THREE
.
ZeroFactor
;
// Normal map textures use OpenGL conventions:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture
_material
.
normalScale
.
x
=
-
1
;
}
_material
.
userData
=
material
.
extras
;
}
return
_material
;
}
}
);
if
(
Array
.
isArray
(
materialValues
.
diffuse
)
)
{
}
);
materialParams
.
color
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
diffuse
)
;
}
;
}
else
if
(
typeof
(
materialValues
.
diffuse
)
===
'
string
'
)
{
GLTFParser
.
prototype
.
loadGeometries
=
function
(
primitives
)
{
materialParams
.
map
=
dependencies
.
textures
[
materialValues
.
diffuse
];
return
this
.
_withDependencies
(
[
}
'
accessors
'
,
delete
materialParams
.
diffuse
;
]
).
then
(
function
(
dependencies
)
{
if
(
typeof
(
materialValues
.
reflective
)
===
'
string
'
)
{
return
_each
(
primitives
,
function
(
primitive
)
{
materialParams
.
envMap
=
dependencies
.
textures
[
materialValues
.
reflective
]
;
var
geometry
=
new
THREE
.
BufferGeometry
()
;
}
var
attributes
=
primitive
.
attributes
;
if
(
typeof
(
materialValues
.
bump
)
===
'
string
'
)
{
for
(
var
attributeId
in
attributes
)
{
materialParams
.
bumpMap
=
dependencies
.
textures
[
materialValues
.
bump
];
var
attributeEntry
=
attributes
[
attributeId
];
}
if
(
attributeEntry
===
undefined
)
return
;
if
(
Array
.
isArray
(
materialValues
.
emission
)
)
{
var
bufferAttribute
=
dependencies
.
accessors
[
attributeEntry
];
if
(
materialType
===
THREE
.
MeshBasicMaterial
)
{
switch
(
attributeId
)
{
materialParams
.
color
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
emission
);
case
'
POSITION
'
:
}
else
{
geometry
.
addAttribute
(
'
position
'
,
bufferAttribute
);
break
;
materialParams
.
emissive
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
emission
);
case
'
NORMAL
'
:
}
geometry
.
addAttribute
(
'
normal
'
,
bufferAttribute
);
break
;
}
else
if
(
typeof
(
materialValues
.
emission
)
===
'
string
'
)
{
case
'
TEXCOORD_0
'
:
case
'
TEXCOORD0
'
:
case
'
TEXCOORD
'
:
if
(
materialType
===
THREE
.
MeshBasicMaterial
)
{
geometry
.
addAttribute
(
'
uv
'
,
bufferAttribute
);
break
;
materialParams
.
map
=
dependencies
.
textures
[
materialValues
.
emission
];
case
'
TEXCOORD_1
'
:
}
else
{
geometry
.
addAttribute
(
'
uv2
'
,
bufferAttribute
);
break
;
materialParams
.
emissiveMap
=
dependencies
.
textures
[
materialValues
.
emission
];
case
'
COLOR_0
'
:
case
'
COLOR0
'
:
case
'
COLOR
'
:
}
geometry
.
addAttribute
(
'
color
'
,
bufferAttribute
);
break
;
}
case
'
WEIGHTS_0
'
:
case
'
WEIGHT
'
:
// WEIGHT semantic deprecated.
if
(
Array
.
isArray
(
materialValues
.
specular
)
)
{
geometry
.
addAttribute
(
'
skinWeight
'
,
bufferAttribute
);
break
;
materialParams
.
specular
=
new
THREE
.
Color
().
fromArray
(
materialValues
.
specular
);
case
'
JOINTS_0
'
:
case
'
JOINT
'
:
// JOINT semantic deprecated.
}
else
if
(
typeof
(
materialValues
.
specular
)
===
'
string
'
)
{
geometry
.
addAttribute
(
'
skinIndex
'
,
bufferAttribute
);
break
;
materialParams
.
specularMap
=
dependencies
.
textures
[
materialValues
.
specular
];
}
}
if
(
materialValues
.
shinines
s
!==
undefined
)
{
if
(
primitive
.
indice
s
!==
undefined
)
{
materialParams
.
shininess
=
materialValues
.
shininess
;
geometry
.
setIndex
(
dependencies
.
accessors
[
primitive
.
indices
]
)
;
}
var
_material
=
new
materialType
(
materialParams
);
if
(
material
.
name
!==
undefined
)
_material
.
name
=
material
.
name
;
return
_material
;
return
geometry
;
}
);
...
...
@@ -1585,159 +1762,127 @@ THREE.GLTFLoader = ( function () {
};
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
*/
GLTFParser
.
prototype
.
loadMeshes
=
function
()
{
var
scope
=
this
;
var
json
=
this
.
json
;
return
this
.
_withDependencies
(
[
"
accessors
"
,
"
materials
"
'
accessors
'
,
'
materials
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
meshes
,
function
(
mesh
)
{
return
_each
(
json
.
meshes
,
function
(
mesh
Def
)
{
var
group
=
new
THREE
.
Group
();
if
(
mesh
.
name
!==
undefined
)
group
.
name
=
mesh
.
name
;
if
(
mesh
.
extras
)
group
.
userData
=
mesh
.
extras
;
var
primitives
=
mesh
.
primitives
||
[];
if
(
meshDef
.
name
!==
undefined
)
group
.
name
=
meshDef
.
name
;
if
(
meshDef
.
extras
)
group
.
userData
=
meshDef
.
extras
;
for
(
var
name
in
primitives
)
{
var
primitives
=
meshDef
.
primitives
||
[];
var
primitive
=
primitives
[
name
];
return
scope
.
loadGeometries
(
primitives
).
then
(
function
(
geometries
)
{
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLES
||
primitive
.
mode
===
undefined
)
{
for
(
var
name
in
primitives
)
{
var
geometry
=
new
THREE
.
BufferGeometry
();
var
primitive
=
primitives
[
name
];
var
geometry
=
geometries
[
name
];
var
attributes
=
primitive
.
attributes
;
var
material
=
primitive
.
material
===
undefined
?
createDefaultMaterial
()
:
dependencies
.
materials
[
primitive
.
material
];
for
(
var
attributeId
in
attributes
)
{
if
(
material
.
aoMap
&&
geometry
.
attributes
.
uv2
===
undefined
&&
geometry
.
attributes
.
uv
!==
undefined
)
{
var
attributeEntry
=
attributes
[
attributeId
];
console
.
log
(
'
THREE.GLTFLoader: Duplicating UVs to support aoMap.
'
);
geometry
.
addAttribute
(
'
uv2
'
,
new
THREE
.
BufferAttribute
(
geometry
.
attributes
.
uv
.
array
,
2
)
);
if
(
!
attributeEntry
)
return
;
var
bufferAttribute
=
dependencies
.
accessors
[
attributeEntry
];
}
switch
(
attributeI
d
)
{
if
(
geometry
.
attributes
.
color
!==
undefine
d
)
{
case
'
POSITION
'
:
geometry
.
addAttribute
(
'
position
'
,
bufferAttribute
);
break
;
material
.
vertexColors
=
THREE
.
VertexColors
;
material
.
needsUpdate
=
true
;
case
'
NORMAL
'
:
geometry
.
addAttribute
(
'
normal
'
,
bufferAttribute
);
break
;
}
case
'
TEXCOORD_0
'
:
case
'
TEXCOORD0
'
:
case
'
TEXCOORD
'
:
geometry
.
addAttribute
(
'
uv
'
,
bufferAttribute
);
break
;
if
(
geometry
.
attributes
.
normal
===
undefined
)
{
case
'
TEXCOORD_1
'
:
geometry
.
addAttribute
(
'
uv2
'
,
bufferAttribute
);
break
;
if
(
material
.
flatShading
!==
undefined
)
{
case
'
COLOR_0
'
:
case
'
COLOR0
'
:
case
'
COLOR
'
:
geometry
.
addAttribute
(
'
color
'
,
bufferAttribute
);
break
;
material
.
flatShading
=
true
;
case
'
WEIGHT
'
:
geometry
.
addAttribute
(
'
skinWeight
'
,
bufferAttribute
);
break
;
}
else
{
case
'
JOINT
'
:
geometry
.
addAttribute
(
'
skinIndex
'
,
bufferAttribute
);
break
;
// TODO: Remove this backwards-compatibility fix after r87 release.
material
.
shading
=
THREE
.
FlatShading
;
}
}
if
(
primitive
.
indices
)
{
geometry
.
setIndex
(
dependencies
.
accessors
[
primitive
.
indices
]
);
var
mesh
;
}
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLES
||
primitive
.
mode
===
undefined
)
{
var
material
=
dependencies
.
materials
!==
undefined
?
dependencies
.
materials
[
primitive
.
material
]
:
createDefaultMaterial
(
);
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
var
meshNode
=
new
THREE
.
Mesh
(
geometry
,
material
);
meshNode
.
castShadow
=
true
;
meshNode
.
name
=
(
name
===
"
0
"
?
group
.
name
:
group
.
name
+
name
);
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLE_STRIP
)
{
if
(
primitive
.
extras
)
meshNode
.
userData
=
primitive
.
extras
;
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
mesh
.
drawMode
=
THREE
.
TriangleStripDrawMode
;
group
.
add
(
meshNode
);
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
TRIANGLE_FAN
)
{
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINES
)
{
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
mesh
.
drawMode
=
THREE
.
TriangleFanDrawMode
;
var
geometry
=
new
THREE
.
BufferGeometry
();
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINES
)
{
var
attributes
=
primitive
.
attributes
;
mesh
=
new
THREE
.
LineSegments
(
geometry
,
material
)
;
for
(
var
attributeId
in
attributes
)
{
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINE_STRIP
)
{
var
attributeEntry
=
attributes
[
attributeId
]
;
mesh
=
new
THREE
.
Line
(
geometry
,
material
)
;
if
(
!
attributeEntry
)
return
;
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
LINE_LOOP
)
{
var
bufferAttribute
=
dependencies
.
accessors
[
attributeEntry
]
;
mesh
=
new
THREE
.
LineLoop
(
geometry
,
material
)
;
switch
(
attributeId
)
{
}
else
if
(
primitive
.
mode
===
WEBGL_CONSTANTS
.
POINTS
)
{
case
'
POSITION
'
:
geometry
.
addAttribute
(
'
position
'
,
bufferAttribute
);
break
;
mesh
=
new
THREE
.
Points
(
geometry
,
material
);
case
'
COLOR_0
'
:
case
'
COLOR0
'
:
case
'
COLOR
'
:
geometry
.
addAttribute
(
'
color
'
,
bufferAttribute
);
break
;
}
else
{
}
throw
new
Error
(
'
THREE.GLTFLoader: Primitive mode unsupported:
'
,
primitive
.
mode
);
}
var
material
=
dependencies
.
materials
[
primitive
.
material
];
var
meshNode
;
mesh
.
name
=
group
.
name
+
'
_
'
+
name
;
if
(
primitive
.
indices
)
{
geometry
.
setIndex
(
dependencies
.
accessors
[
primitive
.
indices
]
);
meshNode
=
new
THREE
.
LineSegments
(
geometry
,
material
);
}
else
{
if
(
primitive
.
targets
!==
undefined
)
{
meshNode
=
new
THREE
.
Line
(
geometry
,
material
);
addMorphTargets
(
mesh
,
meshDef
,
primitive
,
dependencies
);
}
meshNode
.
name
=
(
name
===
"
0
"
?
group
.
name
:
group
.
name
+
name
)
;
if
(
primitive
.
extras
)
mesh
.
userData
=
primitive
.
extras
;
if
(
primitive
.
extras
)
meshNode
.
userData
=
primitive
.
extras
;
group
.
add
(
meshNode
);
}
else
{
console
.
warn
(
"
Only triangular and line primitives are supported
"
);
group
.
add
(
mesh
);
}
}
return
group
;
return
group
;
}
)
;
}
);
...
...
@@ -1745,39 +1890,44 @@ THREE.GLTFLoader = ( function () {
};
/**
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
*/
GLTFParser
.
prototype
.
loadCameras
=
function
()
{
var
json
=
this
.
json
;
return
_each
(
json
.
cameras
,
function
(
camera
)
{
if
(
camera
.
type
==
"
perspective
"
&&
camera
.
perspective
)
{
var
_camera
;
var
yfov
=
camera
.
perspective
.
yfov
;
var
aspectRatio
=
camera
.
perspective
.
aspectRatio
!==
undefined
?
camera
.
perspective
.
aspectRatio
:
1
;
var
params
=
camera
[
camera
.
type
];
// According to COLLADA spec...
// aspectRatio = xfov / yfov
var
xfov
=
yfov
*
aspectRatio
;
if
(
!
params
)
{
var
_camera
=
new
THREE
.
PerspectiveCamera
(
THREE
.
Math
.
radToDeg
(
xfov
),
aspectRatio
,
camera
.
perspective
.
znear
||
1
,
camera
.
perspective
.
zfar
||
2
e6
);
if
(
camera
.
name
!==
undefined
)
_camera
.
name
=
camera
.
name
;
console
.
warn
(
'
THREE.GLTFLoader: Missing camera parameters.
'
);
return
;
if
(
camera
.
extras
)
_camera
.
userData
=
camera
.
extras
;
}
return
_camera
;
if
(
camera
.
type
===
'
perspective
'
)
{
}
else
if
(
camera
.
type
==
"
orthographic
"
&&
camera
.
orthographic
)
{
var
aspectRatio
=
params
.
aspectRatio
||
1
;
var
xfov
=
params
.
yfov
*
aspectRatio
;
var
_camera
=
new
THREE
.
OrthographicCamera
(
window
.
innerWidth
/
-
2
,
window
.
innerWidth
/
2
,
window
.
innerHeight
/
2
,
window
.
innerHeight
/
-
2
,
camera
.
orthographic
.
znear
,
camera
.
orthographic
.
zfar
);
if
(
camera
.
name
!==
undefined
)
_camera
.
name
=
camera
.
name
;
_camera
=
new
THREE
.
PerspectiveCamera
(
THREE
.
Math
.
radToDeg
(
xfov
),
aspectRatio
,
params
.
znear
||
1
,
params
.
zfar
||
2
e6
);
if
(
camera
.
extras
)
_camera
.
userData
=
camera
.
extras
;
}
else
if
(
camera
.
type
===
'
orthographic
'
)
{
return
_camera
;
_camera
=
new
THREE
.
OrthographicCamera
(
params
.
xmag
/
-
2
,
params
.
xmag
/
2
,
params
.
ymag
/
2
,
params
.
ymag
/
-
2
,
params
.
znear
,
params
.
zfar
)
;
}
if
(
camera
.
name
!==
undefined
)
_camera
.
name
=
camera
.
name
;
if
(
camera
.
extras
)
_camera
.
userData
=
camera
.
extras
;
return
_camera
;
}
);
};
...
...
@@ -1788,19 +1938,14 @@ THREE.GLTFLoader = ( function () {
return
this
.
_withDependencies
(
[
"
accessors
"
'
accessors
'
]
).
then
(
function
(
dependencies
)
{
return
_each
(
json
.
skins
,
function
(
skin
)
{
var
bindShapeMatrix
=
new
THREE
.
Matrix4
();
if
(
skin
.
bindShapeMatrix
!==
undefined
)
bindShapeMatrix
.
fromArray
(
skin
.
bindShapeMatrix
);
var
_skin
=
{
bindShapeMatrix
:
bindShapeMatrix
,
jointNames
:
skin
.
jointNames
,
joints
:
skin
.
joints
,
inverseBindMatrices
:
dependencies
.
accessors
[
skin
.
inverseBindMatrices
]
};
...
...
@@ -1818,8 +1963,8 @@ THREE.GLTFLoader = ( function () {
return
this
.
_withDependencies
(
[
"
accessors
"
,
"
nodes
"
'
accessors
'
,
'
nodes
'
]
).
then
(
function
(
dependencies
)
{
...
...
@@ -1835,7 +1980,7 @@ THREE.GLTFLoader = ( function () {
if
(
sampler
)
{
var
target
=
channel
.
target
;
var
name
=
target
.
id
;
var
name
=
target
.
node
!==
undefined
?
target
.
node
:
target
.
id
;
// NOTE: target.id is deprecated.
var
input
=
animation
.
parameters
!==
undefined
?
animation
.
parameters
[
sampler
.
input
]
:
sampler
.
input
;
var
output
=
animation
.
parameters
!==
undefined
?
animation
.
parameters
[
sampler
.
output
]
:
sampler
.
output
;
...
...
@@ -1849,22 +1994,77 @@ THREE.GLTFLoader = ( function () {
node
.
updateMatrix
();
node
.
matrixAutoUpdate
=
true
;
var
TypedKeyframeTrack
=
PATH_PROPERTIES
[
target
.
path
]
===
PATH_PROPERTIES
.
rotation
?
THREE
.
QuaternionKeyframeTrack
:
THREE
.
VectorKeyframeTrack
;
var
TypedKeyframeTrack
;
switch
(
PATH_PROPERTIES
[
target
.
path
]
)
{
case
PATH_PROPERTIES
.
weights
:
TypedKeyframeTrack
=
THREE
.
NumberKeyframeTrack
;
break
;
case
PATH_PROPERTIES
.
rotation
:
TypedKeyframeTrack
=
THREE
.
QuaternionKeyframeTrack
;
break
;
case
PATH_PROPERTIES
.
position
:
case
PATH_PROPERTIES
.
scale
:
default
:
TypedKeyframeTrack
=
THREE
.
VectorKeyframeTrack
;
break
;
}
var
targetName
=
node
.
name
?
node
.
name
:
node
.
uuid
;
if
(
sampler
.
interpolation
===
'
CATMULLROMSPLINE
'
)
{
console
.
warn
(
'
THREE.GLTFLoader: CATMULLROMSPLINE interpolation is not supported. Using CUBICSPLINE instead.
'
);
}
var
interpolation
=
sampler
.
interpolation
!==
undefined
?
INTERPOLATION
[
sampler
.
interpolation
]
:
THREE
.
InterpolateLinear
;
var
targetNames
=
[];
if
(
PATH_PROPERTIES
[
target
.
path
]
===
PATH_PROPERTIES
.
weights
)
{
// node should be THREE.Group here but
// PATH_PROPERTIES.weights(morphTargetInfluences) should be
// the property of a mesh object under node.
// So finding targets here.
node
.
traverse
(
function
(
object
)
{
if
(
object
.
isMesh
===
true
&&
object
.
material
.
morphTargets
===
true
)
{
targetNames
.
push
(
object
.
name
?
object
.
name
:
object
.
uuid
);
}
}
);
}
else
{
targetNames
.
push
(
targetName
);
}
// KeyframeTrack.optimize() will modify given 'times' and 'values'
// buffers before creating a truncated copy to keep. Because buffers may
// be reused by other tracks, make copies here.
tracks
.
push
(
new
TypedKeyframeTrack
(
targetName
+
'
.
'
+
PATH_PROPERTIES
[
target
.
path
],
THREE
.
AnimationUtils
.
arraySlice
(
inputAccessor
.
array
,
0
),
THREE
.
AnimationUtils
.
arraySlice
(
outputAccessor
.
array
,
0
),
interpolation
)
);
for
(
var
i
=
0
,
il
=
targetNames
.
length
;
i
<
il
;
i
++
)
{
tracks
.
push
(
new
TypedKeyframeTrack
(
targetNames
[
i
]
+
'
.
'
+
PATH_PROPERTIES
[
target
.
path
],
THREE
.
AnimationUtils
.
arraySlice
(
inputAccessor
.
array
,
0
),
THREE
.
AnimationUtils
.
arraySlice
(
outputAccessor
.
array
,
0
),
interpolation
)
);
}
}
...
...
@@ -1872,7 +2072,7 @@ THREE.GLTFLoader = ( function () {
}
var
name
=
animation
.
name
!==
undefined
?
animation
.
name
:
"
animation_
"
+
animationId
;
var
name
=
animation
.
name
!==
undefined
?
animation
.
name
:
'
animation_
'
+
animationId
;
return
new
THREE
.
AnimationClip
(
name
,
undefined
,
tracks
);
...
...
@@ -1888,22 +2088,30 @@ THREE.GLTFLoader = ( function () {
var
extensions
=
this
.
extensions
;
var
scope
=
this
;
return
_each
(
json
.
nodes
,
function
(
node
)
{
var
nodes
=
json
.
nodes
||
[];
var
skins
=
json
.
skins
||
[];
var
matrix
=
new
THREE
.
Matrix4
();
// Nothing in the node definition indicates whether it is a Bone or an
// Object3D. Use the skins' joint references to mark bones.
skins
.
forEach
(
function
(
skin
)
{
var
_node
;
skin
.
joints
.
forEach
(
function
(
id
)
{
if
(
node
.
jointName
)
{
nodes
[
id
].
isBone
=
true
;
_node
=
new
THREE
.
Bone
();
_node
.
name
=
node
.
name
!==
undefined
?
node
.
name
:
node
.
jointName
;
_node
.
jointName
=
node
.
jointName
;
}
);
}
else
{
}
);
return
_each
(
json
.
nodes
,
function
(
node
)
{
var
matrix
=
new
THREE
.
Matrix4
();
var
_node
=
node
.
isBone
===
true
?
new
THREE
.
Bone
()
:
new
THREE
.
Object3D
();
_node
=
new
THREE
.
Object3D
();
if
(
node
.
name
!==
undefined
)
_node
.
name
=
node
.
name
;
if
(
node
.
name
!==
undefined
)
{
_node
.
name
=
THREE
.
PropertyBinding
.
sanitizeNodeName
(
node
.
name
);
}
...
...
@@ -1942,9 +2150,9 @@ THREE.GLTFLoader = ( function () {
return
scope
.
_withDependencies
(
[
"
meshes
"
,
"
skins
"
,
"
cameras
"
'
meshes
'
,
'
skins
'
,
'
cameras
'
]
).
then
(
function
(
dependencies
)
{
...
...
@@ -1952,42 +2160,51 @@ THREE.GLTFLoader = ( function () {
var
node
=
json
.
nodes
[
nodeId
];
if
(
node
.
meshes
!==
undefined
)
{
var
meshes
;
if
(
node
.
mesh
!==
undefined
)
{
meshes
=
[
node
.
mesh
];
}
else
if
(
node
.
meshes
!==
undefined
)
{
console
.
warn
(
'
THREE.GLTFLoader: Legacy glTF file detected. Nodes may have no more than one mesh.
'
);
meshes
=
node
.
meshes
;
}
if
(
meshes
!==
undefined
)
{
for
(
var
meshId
in
node
.
meshes
)
{
for
(
var
meshId
in
meshes
)
{
var
mesh
=
node
.
meshes
[
meshId
];
var
mesh
=
meshes
[
meshId
];
var
group
=
dependencies
.
meshes
[
mesh
];
if
(
group
===
undefined
)
{
console
.
warn
(
'
GLTFLoader: Couldn
\'
t find node "
'
+
mesh
+
'
".
'
);
console
.
warn
(
'
THREE.GLTFLoader: Could no
t find node "
'
+
mesh
+
'
".
'
);
continue
;
}
// do not clone children as they will be replaced anyway
var
clonedgroup
=
group
.
clone
(
false
);
for
(
var
childrenId
in
group
.
children
)
{
var
child
=
group
.
children
[
childrenId
];
var
originalChild
=
child
;
// clone Mesh to add to _node
var
originalMaterial
=
child
.
material
;
var
originalGeometry
=
child
.
geometry
;
var
originalInfluences
=
child
.
morphTargetInfluences
;
var
originalUserData
=
child
.
userData
;
var
originalName
=
child
.
name
;
var
material
;
if
(
originalMaterial
.
isDeferredShaderMaterial
)
{
originalMaterial
=
material
=
originalMaterial
.
create
();
}
else
{
material
=
originalMaterial
;
}
var
material
=
originalMaterial
;
switch
(
child
.
type
)
{
...
...
@@ -2003,18 +2220,24 @@ THREE.GLTFLoader = ( function () {
child
=
new
THREE
.
Line
(
originalGeometry
,
material
);
break
;
case
'
Points
'
:
child
=
new
THREE
.
Points
(
originalGeometry
,
material
);
break
;
default
:
child
=
new
THREE
.
Mesh
(
originalGeometry
,
material
);
child
.
drawMode
=
originalChild
.
drawMode
;
}
child
.
castShadow
=
true
;
child
.
morphTargetInfluences
=
originalInfluences
;
child
.
userData
=
originalUserData
;
child
.
name
=
originalName
;
var
skinEntry
;
if
(
node
.
skin
)
{
if
(
node
.
skin
!==
undefined
)
{
skinEntry
=
dependencies
.
skins
[
node
.
skin
];
...
...
@@ -2023,24 +2246,8 @@ THREE.GLTFLoader = ( function () {
// Replace Mesh with SkinnedMesh in library
if
(
skinEntry
)
{
var
getJointNode
=
function
(
jointId
)
{
var
keys
=
Object
.
keys
(
__nodes
);
for
(
var
i
=
0
,
il
=
keys
.
length
;
i
<
il
;
i
++
)
{
var
n
=
__nodes
[
keys
[
i
]
];
if
(
n
.
jointName
===
jointId
)
return
n
;
}
return
null
;
};
var
geometry
=
originalGeometry
;
var
material
=
originalMaterial
;
material
=
originalMaterial
;
material
.
skinning
=
true
;
child
=
new
THREE
.
SkinnedMesh
(
geometry
,
material
);
...
...
@@ -2051,10 +2258,10 @@ THREE.GLTFLoader = ( function () {
var
bones
=
[];
var
boneInverses
=
[];
for
(
var
i
=
0
,
l
=
skinEntry
.
joint
Name
s
.
length
;
i
<
l
;
i
++
)
{
for
(
var
i
=
0
,
l
=
skinEntry
.
joints
.
length
;
i
<
l
;
i
++
)
{
var
jointId
=
skinEntry
.
joint
Name
s
[
i
];
var
jointNode
=
getJointNode
(
jointId
)
;
var
jointId
=
skinEntry
.
joints
[
i
];
var
jointNode
=
__nodes
[
jointId
]
;
if
(
jointNode
)
{
...
...
@@ -2066,45 +2273,22 @@ THREE.GLTFLoader = ( function () {
}
else
{
console
.
warn
(
"
WARNING: joint: '
"
+
jointId
+
"
' could not be found
"
);
console
.
warn
(
'
THREE.GLTFLoader: Joint "%s" could not be found.
'
,
jointId
);
}
}
child
.
bind
(
new
THREE
.
Skeleton
(
bones
,
boneInverses
),
skinEntry
.
bindShapeMatrix
);
var
buildBoneGraph
=
function
(
parentJson
,
parentObject
,
property
)
{
var
children
=
parentJson
[
property
];
if
(
children
===
undefined
)
return
;
for
(
var
i
=
0
,
il
=
children
.
length
;
i
<
il
;
i
++
)
{
var
nodeId
=
children
[
i
];
var
bone
=
__nodes
[
nodeId
];
var
boneJson
=
json
.
nodes
[
nodeId
];
if
(
bone
!==
undefined
&&
bone
.
isBone
===
true
&&
boneJson
!==
undefined
)
{
parentObject
.
add
(
bone
);
buildBoneGraph
(
boneJson
,
bone
,
'
children
'
);
}
}
};
buildBoneGraph
(
node
,
child
,
'
skeletons
'
);
child
.
bind
(
new
THREE
.
Skeleton
(
bones
,
boneInverses
),
child
.
matrixWorld
);
}
_node
.
add
(
child
);
clonedgroup
.
add
(
child
);
}
_node
.
add
(
clonedgroup
);
}
}
...
...
@@ -2118,13 +2302,11 @@ THREE.GLTFLoader = ( function () {
}
if
(
node
.
extensions
&&
node
.
extensions
[
EXTENSIONS
.
KHR_
MATERIALS_COMMON
]
&&
node
.
extensions
[
EXTENSIONS
.
KHR_
MATERIALS_COMMON
].
light
)
{
&&
node
.
extensions
[
EXTENSIONS
.
KHR_
LIGHTS
]
&&
node
.
extensions
[
EXTENSIONS
.
KHR_
LIGHTS
].
light
!==
undefined
)
{
var
extensionLights
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
].
lights
;
var
light
=
extensionLights
[
node
.
extensions
[
EXTENSIONS
.
KHR_MATERIALS_COMMON
].
light
];
_node
.
add
(
light
);
var
lights
=
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
lights
;
_node
.
add
(
lights
[
node
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
]
);
}
...
...
@@ -2141,6 +2323,7 @@ THREE.GLTFLoader = ( function () {
GLTFParser
.
prototype
.
loadScenes
=
function
()
{
var
json
=
this
.
json
;
var
extensions
=
this
.
extensions
;
// scene node hierachy builder
...
...
@@ -2168,7 +2351,7 @@ THREE.GLTFLoader = ( function () {
return
this
.
_withDependencies
(
[
"
nodes
"
'
nodes
'
]
).
then
(
function
(
dependencies
)
{
...
...
@@ -2190,18 +2373,25 @@ THREE.GLTFLoader = ( function () {
_scene
.
traverse
(
function
(
child
)
{
//
Register raw material meshes with GLTFLoader.Shaders
if
(
child
.
material
&&
child
.
material
.
is
RawShader
Material
)
{
//
for Specular-Glossiness.
if
(
child
.
material
&&
child
.
material
.
is
GLTFSpecularGlossiness
Material
)
{
child
.
gltfShader
=
new
GLTFShader
(
child
,
dependencies
.
nodes
);
child
.
onBeforeRender
=
function
(
renderer
,
scene
,
camera
){
this
.
gltfShader
.
update
(
scene
,
camera
);
};
child
.
onBeforeRender
=
extensions
[
EXTENSIONS
.
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS
].
refreshUniforms
;
}
}
);
// Ambient lighting, if present, is always attached to the scene root.
if
(
scene
.
extensions
&&
scene
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
]
&&
scene
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
!==
undefined
)
{
var
lights
=
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
lights
;
_scene
.
add
(
lights
[
scene
.
extensions
[
EXTENSIONS
.
KHR_LIGHTS
].
light
]
);
}
return
_scene
;
}
);
...
...
examples/webgl_exporter_gltf
2
.html
→
examples/webgl_exporter_gltf.html
浏览文件 @
a1e574b5
...
...
@@ -22,7 +22,7 @@
</head>
<body>
<div
id=
"info"
>
GLTF
2
Exporter
<br/>
GLTF Exporter
<br/>
<button
id=
"export_scene"
>
Export Scene1
</button>
<button
id=
"export_scenes"
>
Export Scene1 and Scene 2
</button>
<button
id=
"export_object"
>
Export Sphere
</button>
...
...
examples/webgl_loader_gltf
2
.html
→
examples/webgl_loader_gltf.html
浏览文件 @
a1e574b5
...
...
@@ -96,7 +96,7 @@
</div>
<script
src=
"../build/three.js"
></script>
<script
src=
"js/controls/OrbitControls.js"
></script>
<script
src=
"js/loaders/GLTF
2
Loader.js"
></script>
<script
src=
"js/loaders/GLTFLoader.js"
></script>
<script>
var
orbitControls
=
null
;
...
...
@@ -202,7 +202,7 @@
scene
.
add
(
ground
);
}
loader
=
new
THREE
.
GLTF
2
Loader
();
loader
=
new
THREE
.
GLTFLoader
();
for
(
var
i
=
0
;
i
<
extensionSelect
.
children
.
length
;
i
++
)
{
var
child
=
extensionSelect
.
children
[
i
];
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录