提交 63c049e0 编写于 作者: M Mr.doob 提交者: GitHub

Merge pull request #10972 from donmccurdy/feat-gltf2-docs-and-examples

[glTF] Branch glTF/glTF2.0 examples, and update docs to GLTF2Loader.
...@@ -12,22 +12,41 @@ ...@@ -12,22 +12,41 @@
<h1>[name]</h1> <h1>[name]</h1>
<div class="desc"> <div class="desc">
A loader for loading a *gltf* resource in JSON format. A loader for *glTF* 2.0 resources.
<br /><br /> <br /><br />
The <a href="https://www.khronos.org/gltf">glTF file format</a> is a JSON file format to enable rapid delivery and loading of 3D content. <a href="https://www.khronos.org/gltf">glTF</a> (GL Transmission Format) is an open format
specification for efficient delivery and loading of 3D content. Assets may be provided either
in JSON (.gltf) or binary (.glb) format. External files store textures (.jpg, .png, ...) and
additional binary data (.bin). A glTF asset may deliver one or more scenes, including meshes,
materials, textures, shaders, skins, skeletons, animations, lights, and/or cameras. Morph target
animations are not yet finalized in the
<a href="https://github.com/KhronosGroup/glTF/tree/master/specification">glTF specification</a>.
</div> </div>
<h2>Notes</h2> <h2>Extensions</h2>
<div> <div>
When using custom shaders provided within a glTF file [page:THREE.GLTFLoader.Shaders] should be updated on each render loop. See [example:webgl_loader_gltf] demo source code for example usage. GLTF2Loader supports the following glTF extensions:
</div> </div>
<ul>
<li>
<a target="_blank" href="https://github.com/KhronosGroup/glTF/blob/master/extensions/Khronos/KHR_binary_glTF">
KHR_binary_glTF
</a>
</li>
<li>
<a target="_blank" href="https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_common">
KHR_materials_common
</a>
</li>
</ul>
<h2>Example</h2> <h2>Example</h2>
<code> <code>
// Instantiate a loader // Instantiate a loader
var loader = new THREE.GLTFLoader(); var loader = new THREE.GLTF2Loader();
// Load a glTF resource // Load a glTF resource
loader.load( 'models/gltf/duck/duck.gltf', function ( gltf ) { loader.load( 'models/gltf/duck/duck.gltf', function ( gltf ) {
...@@ -40,7 +59,7 @@ ...@@ -40,7 +59,7 @@
} ); } );
</code> </code>
[example:webgl_loader_gltf] [example:webgl_loader_gltf2]
<h2>Constructor</h2> <h2>Constructor</h2>
...@@ -88,11 +107,11 @@ ...@@ -88,11 +107,11 @@
[page:String path] — The base path from which to find subsequent glTF resources such as textures, GLSL shaders and .bin data files.<br /> [page:String path] — The base path from which to find subsequent glTF resources such as textures, GLSL shaders and .bin data files.<br />
</div> </div>
<div> <div>
Parse a glTF-based <em>JSON</em> structure and fire [page:Function callback] when complete. The argument to [page:Function callback] will be an [page:object] that contains loaded parts: .[page:Scene scene], .[page:Array cameras], .[page:Array animations] and .[page:Array shaders] Parse a glTF-based <em>JSON</em> structure and fire [page:Function callback] when complete. The argument to [page:Function callback] will be an [page:object] that contains loaded parts: .[page:Scene scene], .[page:Array scenes], .[page:Array cameras], and .[page:Array animations].
</div> </div>
<h2>Source</h2> <h2>Source</h2>
[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/GLTFLoader.js examples/js/loaders/GLTFLoader.js] [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/GLTF2Loader.js examples/js/loaders/GLTF2Loader.js]
</body> </body>
</html> </html>
...@@ -340,7 +340,7 @@ var list = { ...@@ -340,7 +340,7 @@ var list = {
"Loaders": [ "Loaders": [
[ "BabylonLoader", "examples/loaders/BabylonLoader" ], [ "BabylonLoader", "examples/loaders/BabylonLoader" ],
[ "ColladaLoader", "examples/loaders/ColladaLoader" ], [ "ColladaLoader", "examples/loaders/ColladaLoader" ],
[ "GLTFLoader", "examples/loaders/GLTFLoader" ], [ "GLTF2Loader", "examples/loaders/GLTF2Loader" ],
[ "MTLLoader", "examples/loaders/MTLLoader" ], [ "MTLLoader", "examples/loaders/MTLLoader" ],
[ "OBJLoader", "examples/loaders/OBJLoader" ], [ "OBJLoader", "examples/loaders/OBJLoader" ],
[ "PCDLoader", "examples/loaders/PCDLoader" ], [ "PCDLoader", "examples/loaders/PCDLoader" ],
......
...@@ -89,6 +89,7 @@ var files = { ...@@ -89,6 +89,7 @@ var files = {
"webgl_loader_ctm_materials", "webgl_loader_ctm_materials",
"webgl_loader_fbx", "webgl_loader_fbx",
"webgl_loader_gltf", "webgl_loader_gltf",
"webgl_loader_gltf2",
"webgl_loader_json_blender", "webgl_loader_json_blender",
"webgl_loader_json_claraio", "webgl_loader_json_claraio",
"webgl_loader_json_objconverter", "webgl_loader_json_objconverter",
......
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>three.js webgl - glTF</title> <title>three.js webgl - glTF 1.0</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style> <style>
...@@ -63,11 +63,10 @@ ...@@ -63,11 +63,10 @@
<body> <body>
<div id="info"> <div id="info">
<a href="http://threejs.org" target="_blank">three.js</a> - <a href="http://threejs.org" target="_blank">three.js</a> -
<a href="https://github.com/KhronosGroup/glTF" target="_blank">glTF</a> loader <a href="https://github.com/KhronosGroup/glTF" target="_blank">glTF</a> 1.0 loader
<br> <br>
monster by <a href="http://www.3drt.com/downloads.htm" target="_blank">3drt</a> - COLLADA duck by Sony - monster by <a href="http://www.3drt.com/downloads.htm" target="_blank">3drt</a> - COLLADA duck by Sony -
Cesium models by <a href="http://cesiumjs.org/" target="_blank">Cesium</a> - Cesium models by <a href="http://cesiumjs.org/" target="_blank">Cesium</a>
BoomBox by <a href="https://www.microsoft.com/" target="_blank">Microsoft</a>
</div> </div>
<div id="container"></div> <div id="container"></div>
<div id="controls"> <div id="controls">
...@@ -96,7 +95,7 @@ ...@@ -96,7 +95,7 @@
</div> </div>
<script src="../build/three.js"></script> <script src="../build/three.js"></script>
<script src="js/controls/OrbitControls.js"></script> <script src="js/controls/OrbitControls.js"></script>
<script src="js/loaders/GLTF2Loader.js"></script> <script src="js/loaders/GLTFLoader.js"></script>
<script> <script>
var orbitControls = null; var orbitControls = null;
...@@ -203,7 +202,7 @@ ...@@ -203,7 +202,7 @@
scene.add(ground); scene.add(ground);
} }
loader = new THREE.GLTF2Loader(); loader = new THREE.GLTFLoader();
for (var i = 0; i < extensionSelect.children.length; i++) { for (var i = 0; i < extensionSelect.children.length; i++) {
var child = extensionSelect.children[i]; var child = extensionSelect.children[i];
...@@ -382,14 +381,6 @@ ...@@ -382,14 +381,6 @@
addGround:true, addGround:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"] extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
}, },
{
name : "BoomBox (PBR)", url : "./models/gltf/BoomBox/%s/BoomBox.gltf",
cameraPos: new THREE.Vector3(2, 1, 3),
objectRotation: new THREE.Euler(0, Math.PI, 0),
addLights:true,
extensions: ["glTF"]
},
{ {
name : "Duck", url : "./models/gltf/duck/%s/duck.gltf", name : "Duck", url : "./models/gltf/duck/%s/duck.gltf",
cameraPos: new THREE.Vector3(0, 3, 5), cameraPos: new THREE.Vector3(0, 3, 5),
......
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - glTF 2.0</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #222222;
margin: 0px;
overflow: hidden;
}
#info {
color: #808080;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
#container {
position: absolute;
top: 0px;
width:100%;
height:100%;
z-index: -1;
}
#controls {
position: absolute;
width: 200px;
bottom: 0px;
left: 0px;
padding: 10px;
background-color: White;
font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
}
#controls > div {
margin-bottom: 8px;
}
#controls hr {
border: 0px;
height: 1px;
margin-bottom: 10px;
background-color: #bbb;
}
#info a, .button {
color: #f00;
font-weight: bold;
text-decoration: underline;
cursor: pointer
}
</style>
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank">three.js</a> -
<a href="https://github.com/KhronosGroup/glTF" target="_blank">glTF</a> 2.0 loader
<br>
BoomBox by <a href="https://www.microsoft.com/" target="_blank">Microsoft</a>
</div>
<div id="container"></div>
<div id="controls">
<div id="status">Loading...</div>
<hr />
<div>
Model
<select id="scenes_list" size="1" onchange="selectScene();" ondblclick="selectScene();"></select>
</div>
<div>
Camera
<select id="cameras_list" size="1" onchange="selectCamera();" ondblclick="selectCamera();"></select>
</div>
<div>
Animations
<input type="checkbox" checked onclick="toggleAnimations();">Play</input>
</div>
<div>
Extension
<select id="extensions_list" onchange="selectExtension();">
<option value="glTF">None</option>
<option value="glTF-MaterialsCommon">Built-in shaders</option>
<option value="glTF-Binary">Binary</option>
</select>
</div>
</div>
<script src="../build/three.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/loaders/GLTF2Loader.js"></script>
<script>
var orbitControls = null;
var container, camera, scene, renderer, loader;
var cameraIndex = 0;
var cameras = [];
var cameraNames = [];
var defaultCamera = null;
var gltf = null;
var mixer = null;
var clock = new THREE.Clock();
function onload() {
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'keydown', function(e) { onKeyDown(e); }, false );
buildSceneList();
switchScene(0);
animate();
}
function initScene(index) {
container = document.getElementById( 'container' );
scene = new THREE.Scene();
defaultCamera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 20000 );
//defaultCamera.up = new THREE.Vector3( 0, 1, 0 );
scene.add( defaultCamera );
camera = defaultCamera;
var sceneInfo = sceneList[index];
var spot1 = null;
if (sceneInfo.addLights) {
var ambient = new THREE.AmbientLight( 0x222222 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xdddddd );
directionalLight.position.set( 0, 0, 1 ).normalize();
scene.add( directionalLight );
spot1 = new THREE.SpotLight( 0xffffff, 1 );
spot1.position.set( 10, 20, 10 );
spot1.angle = 0.25;
spot1.distance = 1024;
spot1.penumbra = 0.75;
if ( sceneInfo.shadows ) {
spot1.castShadow = true;
spot1.shadow.bias = 0.0001;
spot1.shadow.mapSize.width = 2048;
spot1.shadow.mapSize.height = 2048;
}
scene.add( spot1 );
}
// RENDERER
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setClearColor( 0x222222 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
if (sceneInfo.shadows) {
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
}
container.appendChild( renderer.domElement );
var ground = null;
if (sceneInfo.addGround) {
var groundMaterial = new THREE.MeshPhongMaterial({
color: 0xFFFFFF,
shading: THREE.SmoothShading
});
ground = new THREE.Mesh( new THREE.PlaneBufferGeometry(512, 512), groundMaterial);
if (sceneInfo.shadows) {
ground.receiveShadow = true;
}
if (sceneInfo.groundPos) {
ground.position.copy(sceneInfo.groundPos);
} else {
ground.position.z = -70;
}
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
}
loader = new THREE.GLTF2Loader();
for (var i = 0; i < extensionSelect.children.length; i++) {
var child = extensionSelect.children[i];
child.disabled = sceneInfo.extensions.indexOf(child.value) === -1;
if (child.disabled && child.selected) {
extensionSelect.value = extension = 'glTF';
}
}
var url = sceneInfo.url;
var r = eval("/" + '\%s' + "/g");
url = url.replace(r, extension);
if (extension === 'glTF-Binary') {
url = url.replace('.gltf', '.glb');
}
var loadStartTime = performance.now();
var status = document.getElementById("status");
status.innerHTML = "Loading...";
loader.load( url, function(data) {
gltf = data;
var object = gltf.scene;
status.innerHTML = "Load time: " + ( performance.now() - loadStartTime ).toFixed( 2 ) + " ms.";
if (sceneInfo.cameraPos)
defaultCamera.position.copy(sceneInfo.cameraPos);
if (sceneInfo.center) {
orbitControls.target.copy(sceneInfo.center);
}
if (sceneInfo.objectPosition) {
object.position.copy(sceneInfo.objectPosition);
if (spot1) {
spot1.position.set(sceneInfo.objectPosition.x - 100, sceneInfo.objectPosition.y + 200, sceneInfo.objectPosition.z - 100 );
spot1.target.position.copy(sceneInfo.objectPosition);
}
}
if (sceneInfo.objectRotation)
object.rotation.copy(sceneInfo.objectRotation);
if (sceneInfo.objectScale)
object.scale.copy(sceneInfo.objectScale);
cameraIndex = 0;
cameras = [];
cameraNames = [];
if (gltf.cameras && gltf.cameras.length) {
var i, len = gltf.cameras.length;
for (i = 0; i < len; i++) {
var addCamera = true;
var cameraName = gltf.cameras[i].parent.name;
if (sceneInfo.cameras && !(cameraName in sceneInfo.cameras)) {
addCamera = false;
}
if (addCamera) {
cameraNames.push(cameraName);
cameras.push(gltf.cameras[i]);
}
}
updateCamerasList();
switchCamera(1);
} else {
updateCamerasList();
switchCamera(0);
}
var animations = gltf.animations;
if ( animations && animations.length ) {
mixer = new THREE.AnimationMixer( object );
for ( var i = 0; i < animations.length; i ++ ) {
var animation = animations[ i ];
// There's .3333 seconds junk at the tail of the Monster animation that
// keeps it from looping cleanly. Clip it at 3 seconds
if ( sceneInfo.animationTime )
animation.duration = sceneInfo.animationTime;
mixer.clipAction( animation ).play();
}
}
scene.add( object );
onWindowResize();
});
orbitControls = new THREE.OrbitControls(defaultCamera, renderer.domElement);
}
function onWindowResize() {
defaultCamera.aspect = container.offsetWidth / container.offsetHeight;
defaultCamera.updateProjectionMatrix();
var i, len = cameras.length;
for (i = 0; i < len; i++) { // just do it for default
cameras[i].aspect = container.offsetWidth / container.offsetHeight;
cameras[i].updateProjectionMatrix();
}
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
if (mixer) mixer.update(clock.getDelta());
if (cameraIndex == 0)
orbitControls.update();
render();
}
function render() {
renderer.render( scene, camera );
}
function onKeyDown(event) {
var chr = String.fromCharCode(event.keyCode);
if (chr == ' ') {
index = cameraIndex + 1;
if (index > cameras.length)
index = 0;
switchCamera(index);
} else {
var index = parseInt(chr);
if (!isNaN(index) && (index <= cameras.length)) {
switchCamera(index);
}
}
}
var sceneList = [
{
name : "BoomBox (PBR)", url : "./models/gltf/BoomBox/%s/BoomBox.gltf",
cameraPos: new THREE.Vector3(2, 1, 3),
objectRotation: new THREE.Euler(0, Math.PI, 0),
addLights:true,
extensions: ["glTF"]
}
];
function buildSceneList() {
var elt = document.getElementById('scenes_list');
while( elt.hasChildNodes() ){
elt.removeChild(elt.lastChild);
}
var i, len = sceneList.length;
for (i = 0; i < len; i++) {
option = document.createElement("option");
option.text=sceneList[i].name;
elt.add(option);
}
}
function switchScene(index) {
cleanup();
initScene(index);
var elt = document.getElementById('scenes_list');
elt.selectedIndex = index;
}
function selectScene() {
var select = document.getElementById("scenes_list");
var index = select.selectedIndex;
if (index >= 0) {
switchScene(index);
}
}
function switchCamera(index) {
cameraIndex = index;
if (cameraIndex == 0) {
camera = defaultCamera;
}
if (cameraIndex >= 1 && cameraIndex <= cameras.length) {
camera = cameras[cameraIndex - 1];
}
var elt = document.getElementById('cameras_list');
elt.selectedIndex = cameraIndex;
}
function updateCamerasList() {
var elt = document.getElementById('cameras_list');
while( elt.hasChildNodes() ){
elt.removeChild(elt.lastChild);
}
option = document.createElement("option");
option.text="[default]";
elt.add(option);
var i, len = cameraNames.length;
for (i = 0; i < len; i++) {
option = document.createElement("option");
option.text=cameraNames[i];
elt.add(option);
}
}
function selectCamera() {
var select = document.getElementById("cameras_list");
var index = select.selectedIndex;
if (index >= 0) {
switchCamera(index);
}
}
function toggleAnimations() {
var i, len = gltf.animations.length;
for (i = 0; i < len; i++) {
var clip = gltf.animations[i];
var action = mixer.existingAction( clip );
if (action.isRunning()) {
action.stop();
} else {
action.play();
}
}
}
var extensionSelect = document.getElementById("extensions_list");
var extension = extensionSelect.value;
function selectExtension()
{
extension = extensionSelect.value;
selectScene();
}
function cleanup() {
if (container && renderer) {
container.removeChild(renderer.domElement);
}
cameraIndex = 0;
cameras = [];
cameraNames = [];
defaultCamera = null;
if (!loader || !mixer)
return;
mixer.stopAllAction();
}
onload();
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册