提交 25ae71ca 编写于 作者: M Mr.doob

Merge branch 'dev' of https://github.com/tparisi/three.js into dev

......@@ -168,6 +168,7 @@
"webgl_loader_collada_skinning",
"webgl_loader_ctm",
"webgl_loader_ctm_materials",
"webgl_loader_gltf",
"webgl_loader_json_blender",
"webgl_loader_json_objconverter",
"webgl_loader_obj",
......
// Copyright (c) 2013 Fabrice Robinet
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
The Abstract Loader has two modes:
#1: [static] load all the JSON at once [as of now]
#2: [stream] stream and parse JSON progressively [not yet supported]
Whatever is the mechanism used to parse the JSON (#1 or #2),
The loader starts by resolving the paths to binaries and referenced json files (by replace the value of the path property with an absolute path if it was relative).
In case #1: it is guaranteed to call the concrete loader implementation methods in a order that solves the dependencies between the entries.
only the nodes requires an extra pass to set up the hirerarchy.
In case #2: the concrete implementation will have to solve the dependencies. no order is guaranteed.
When case #1 is used the followed dependency order is:
scenes -> nodes -> meshes -> materials -> techniques -> shaders
-> buffers
-> cameras
-> lights
The readers starts with the leafs, i.e:
shaders, techniques, materials, meshes, buffers, cameras, lights, nodes, scenes
For each called handle method called the client should return true if the next handle can be call right after returning,
or false if a callback on client side will notify the loader that the next handle method can be called.
*/
var global = window;
(function (root, factory) {
if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like enviroments that support module.exports,
// like Node.
factory(module.exports);
} else if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function () {
return factory(root);
});
} else {
// Browser globals
factory(root);
}
}(this, function (root) {
"use strict";
var categoriesDepsOrder = ["buffers", "bufferViews", "images", "videos", "samplers", "textures", "shaders", "programs", "techniques", "materials", "accessors", "meshes", "cameras", "lights", "skins", "nodes", "scenes", "animations"];
var glTFParser = Object.create(Object.prototype, {
_rootDescription: { value: null, writable: true },
rootDescription: {
set: function(value) {
this._rootDescription = value;
},
get: function() {
return this._rootDescription;
}
},
baseURL: { value: null, writable: true },
//detect absolute path following the same protocol than window.location
_isAbsolutePath: {
value: function(path) {
var isAbsolutePathRegExp = new RegExp("^"+window.location.protocol, "i");
return path.match(isAbsolutePathRegExp) ? true : false;
}
},
resolvePathIfNeeded: {
value: function(path) {
if (this._isAbsolutePath(path)) {
return path;
}
return this.baseURL + path;
}
},
_resolvePathsForCategories: {
value: function(categories) {
categories.forEach( function(category) {
var descriptions = this.json[category];
if (descriptions) {
var descriptionKeys = Object.keys(descriptions);
descriptionKeys.forEach( function(descriptionKey) {
var description = descriptions[descriptionKey];
description.path = this.resolvePathIfNeeded(description.path);
}, this);
}
}, this);
}
},
_json: {
value: null,
writable: true
},
json: {
enumerable: true,
get: function() {
return this._json;
},
set: function(value) {
if (this._json !== value) {
this._json = value;
this._resolvePathsForCategories(["buffers", "shaders", "images", "videos"]);
}
}
},
_path: {
value: null,
writable: true
},
getEntryDescription: {
value: function (entryID, entryType) {
var entries = null;
var category = entryType;
entries = this.rootDescription[category];
if (!entries) {
console.log("ERROR:CANNOT find expected category named:"+category);
return null;
}
return entries ? entries[entryID] : null;
}
},
_stepToNextCategory: {
value: function() {
this._state.categoryIndex = this.getNextCategoryIndex(this._state.categoryIndex + 1);
if (this._state.categoryIndex !== -1) {
this._state.categoryState.index = 0;
return true;
}
return false;
}
},
_stepToNextDescription: {
enumerable: false,
value: function() {
var categoryState = this._state.categoryState;
var keys = categoryState.keys;
if (!keys) {
console.log("INCONSISTENCY ERROR");
return false;
}
categoryState.index++;
categoryState.keys = null;
if (categoryState.index >= keys.length) {
return this._stepToNextCategory();
}
return false;
}
},
hasCategory: {
value: function(category) {
return this.rootDescription[category] ? true : false;
}
},
_handleState: {
value: function() {
var methodForType = {
"buffers" : this.handleBuffer,
"bufferViews" : this.handleBufferView,
"shaders" : this.handleShader,
"programs" : this.handleProgram,
"techniques" : this.handleTechnique,
"materials" : this.handleMaterial,
"meshes" : this.handleMesh,
"cameras" : this.handleCamera,
"lights" : this.handleLight,
"nodes" : this.handleNode,
"scenes" : this.handleScene,
"images" : this.handleImage,
"animations" : this.handleAnimation,
"accessors" : this.handleAccessor,
"skins" : this.handleSkin,
"samplers" : this.handleSampler,
"textures" : this.handleTexture,
"videos" : this.handleVideo
};
var success = true;
while (this._state.categoryIndex !== -1) {
var category = categoriesDepsOrder[this._state.categoryIndex];
var categoryState = this._state.categoryState;
var keys = categoryState.keys;
if (!keys) {
categoryState.keys = keys = Object.keys(this.rootDescription[category]);
if (keys) {
if (keys.length == 0) {
this._stepToNextDescription();
continue;
}
}
}
var type = category;
var entryID = keys[categoryState.index];
var description = this.getEntryDescription(entryID, type);
if (!description) {
if (this.handleError) {
this.handleError("INCONSISTENCY ERROR: no description found for entry "+entryID);
success = false;
break;
}
} else {
if (methodForType[type]) {
if (methodForType[type].call(this, entryID, description, this._state.userInfo) === false) {
success = false;
break;
}
}
this._stepToNextDescription();
}
}
if (this.handleLoadCompleted) {
this.handleLoadCompleted(success);
}
}
},
_loadJSONIfNeeded: {
enumerable: true,
value: function(callback) {
var self = this;
//FIXME: handle error
if (!this._json) {
var jsonPath = this._path;
var i = jsonPath.lastIndexOf("/");
this.baseURL = (i !== 0) ? jsonPath.substring(0, i + 1) : '';
var jsonfile = new XMLHttpRequest();
jsonfile.open("GET", jsonPath, true);
jsonfile.onreadystatechange = function() {
if (jsonfile.readyState == 4) {
if (jsonfile.status == 200) {
self.json = JSON.parse(jsonfile.responseText);
if (callback) {
callback(self.json);
}
}
}
};
jsonfile.send(null);
} else {
if (callback) {
callback(this.json);
}
}
}
},
/* load JSON and assign it as description to the reader */
_buildLoader: {
value: function(callback) {
var self = this;
function JSONReady(json) {
self.rootDescription = json;
if (callback)
callback(this);
}
this._loadJSONIfNeeded(JSONReady);
}
},
_state: { value: null, writable: true },
_getEntryType: {
value: function(entryID) {
var rootKeys = categoriesDepsOrder;
for (var i = 0 ; i < rootKeys.length ; i++) {
var rootValues = this.rootDescription[rootKeys[i]];
if (rootValues) {
return rootKeys[i];
}
}
return null;
}
},
getNextCategoryIndex: {
value: function(currentIndex) {
for (var i = currentIndex ; i < categoriesDepsOrder.length ; i++) {
if (this.hasCategory(categoriesDepsOrder[i])) {
return i;
}
}
return -1;
}
},
load: {
enumerable: true,
value: function(userInfo, options) {
var self = this;
this._buildLoader(function loaderReady(reader) {
var startCategory = self.getNextCategoryIndex.call(self,0);
if (startCategory !== -1) {
self._state = { "userInfo" : userInfo,
"options" : options,
"categoryIndex" : startCategory,
"categoryState" : { "index" : "0" } };
self._handleState();
}
});
}
},
initWithPath: {
value: function(path) {
this._path = path;
this._json = null;
return this;
}
},
//this is meant to be global and common for all instances
_knownURLs: { writable: true, value: {} },
//to be invoked by subclass, so that ids can be ensured to not overlap
loaderContext: {
value: function() {
if (typeof this._knownURLs[this._path] === "undefined") {
this._knownURLs[this._path] = Object.keys(this._knownURLs).length;
}
return "__" + this._knownURLs[this._path];
}
},
initWithJSON: {
value: function(json, baseURL) {
this.json = json;
this.baseURL = baseURL;
if (!baseURL) {
console.log("WARNING: no base URL passed to Reader:initWithJSON");
}
return this;
}
}
});
if(root) {
root.glTFParser = glTFParser;
}
return glTFParser;
}));
/**
* @author Tony Parisi / http://www.tonyparisi.com/
*/
THREE.glTFAnimator = ( function () {
var animators = [];
return {
add : function(animator)
{
animators.push(animator);
},
remove: function(animator)
{
var i = animators.indexOf(animator);
if ( i !== -1 ) {
animators.splice( i, 1 );
}
},
update : function()
{
for (i = 0; i < animators.length; i++)
{
animators[i].update();
}
},
};
})();
// Construction/initialization
THREE.glTFAnimation = function(interps)
{
this.running = false;
this.loop = false;
this.duration = 0;
this.startTime = 0;
this.interps = [];
if (interps)
{
this.createInterpolators(interps);
}
}
THREE.glTFAnimation.prototype.createInterpolators = function(interps)
{
var i, len = interps.length;
for (i = 0; i < len; i++)
{
var interp = new THREE.glTFInterpolator(interps[i]);
this.interps.push(interp);
this.duration = Math.max(this.duration, interp.duration);
}
}
// Start/stop
THREE.glTFAnimation.prototype.play = function()
{
if (this.running)
return;
this.startTime = Date.now();
this.running = true;
THREE.glTFAnimator.add(this);
}
THREE.glTFAnimation.prototype.stop = function()
{
this.running = false;
THREE.glTFAnimator.remove(this);
}
// Update - drive key frame evaluation
THREE.glTFAnimation.prototype.update = function()
{
if (!this.running)
return;
var now = Date.now();
var deltat = (now - this.startTime) / 1000;
var t = deltat % this.duration;
var nCycles = Math.floor(deltat / this.duration);
if (nCycles >= 1 && !this.loop)
{
this.running = false;
var i, len = this.interps.length;
for (i = 0; i < len; i++)
{
this.interps[i].interp(this.duration);
}
this.stop();
return;
}
else
{
var i, len = this.interps.length;
for (i = 0; i < len; i++)
{
this.interps[i].interp(t);
}
}
}
//Interpolator class
//Construction/initialization
THREE.glTFInterpolator = function(param)
{
this.keys = param.keys;
this.values = param.values;
this.count = param.count;
this.type = param.type;
this.path = param.path;
this.isRot = false;
var node = param.target;
node.updateMatrix();
node.matrixAutoUpdate = true;
this.targetNode = node;
switch (param.path) {
case "translation" :
this.target = node.position;
this.originalValue = node.position.clone();
break;
case "rotation" :
this.target = node.quaternion;
this.originalValue = node.quaternion.clone();
this.isRot = true;
break;
case "scale" :
this.target = node.scale;
this.originalValue = node.scale.clone();
break;
}
this.duration = this.keys[this.count - 1];
this.vec1 = new THREE.Vector3;
this.vec2 = new THREE.Vector3;
this.vec3 = new THREE.Vector3;
this.quat1 = new THREE.Quaternion;
this.quat2 = new THREE.Quaternion;
this.quat3 = new THREE.Quaternion;
}
//Interpolation and tweening methods
THREE.glTFInterpolator.prototype.interp = function(t)
{
var i, j;
if (t == this.keys[0])
{
if (this.isRot) {
this.quat3.set(this.values[0], this.values[1], this.values[2], this.values[3]);
}
else {
this.vec3.set(this.values[0], this.values[1], this.values[2]);
}
}
else if (t < this.keys[0])
{
if (this.isRot) {
this.quat1.set(this.originalValue.x,
this.originalValue.y,
this.originalValue.z,
this.originalValue.w);
this.quat2.set(this.values[0],
this.values[1],
this.values[2],
this.values[3]);
THREE.Quaternion.slerp(this.quat1, this.quat2, this.quat3, t / this.keys[0]);
}
else {
this.vec3.set(this.originalValue.x,
this.originalValue.y,
this.originalValue.z);
this.vec2.set(this.values[0],
this.values[1],
this.values[2]);
this.vec3.lerp(this.vec2, t / this.keys[0]);
}
}
else if (t >= this.keys[this.count - 1])
{
if (this.isRot) {
this.quat3.set(this.values[(this.count - 1) * 4],
this.values[(this.count - 1) * 4 + 1],
this.values[(this.count - 1) * 4 + 2],
this.values[(this.count - 1) * 4 + 3]);
}
else {
this.vec3.set(this.values[(this.count - 1) * 3],
this.values[(this.count - 1) * 3 + 1],
this.values[(this.count - 1) * 3 + 2]);
}
}
else
{
for (i = 0; i < this.count - 1; i++)
{
var key1 = this.keys[i];
var key2 = this.keys[i + 1];
if (t >= key1 && t <= key2)
{
if (this.isRot) {
this.quat1.set(this.values[i * 4],
this.values[i * 4 + 1],
this.values[i * 4 + 2],
this.values[i * 4 + 3]);
this.quat2.set(this.values[(i + 1) * 4],
this.values[(i + 1) * 4 + 1],
this.values[(i + 1) * 4 + 2],
this.values[(i + 1) * 4 + 3]);
THREE.Quaternion.slerp(this.quat1, this.quat2, this.quat3, (t - key1) / (key2 - key1));
}
else {
this.vec3.set(this.values[i * 3],
this.values[i * 3 + 1],
this.values[i * 3 + 2]);
this.vec2.set(this.values[(i + 1) * 3],
this.values[(i + 1) * 3 + 1],
this.values[(i + 1) * 3 + 2]);
this.vec3.lerp(this.vec2, (t - key1) / (key2 - key1));
}
}
}
}
if (this.target)
{
this.copyValue(this.target);
}
}
THREE.glTFInterpolator.prototype.copyValue = function(target) {
if (this.isRot) {
target.copy(this.quat3);
}
else {
target.copy(this.vec3);
}
}
此差异已折叠。
/**
* @author Tony Parisi / http://www.tonyparisi.com/
*/
THREE.GLTFLoaderUtils = Object.create(Object, {
// errors
MISSING_DESCRIPTION: { value: "MISSING_DESCRIPTION" },
INVALID_PATH: { value: "INVALID_PATH" },
INVALID_TYPE: { value: "INVALID_TYPE" },
XMLHTTPREQUEST_STATUS_ERROR: { value: "XMLHTTPREQUEST_STATUS_ERROR" },
NOT_FOUND: { value: "NOT_FOUND" },
// misc constants
ARRAY_BUFFER: { value: "ArrayBuffer" },
_streams : { value:{}, writable: true },
_streamsStatus: { value: {}, writable: true },
_resources: { value: {}, writable: true },
_resourcesStatus: { value: {}, writable: true },
// initialization
init: {
value: function() {
this._streams = {};
this._streamsStatus = {};
this._resources = {};
this._resourcesStatus = {};
}
},
//manage entries
_containsResource: {
enumerable: false,
value: function(resourceID) {
return this._resources[resourceID] ? true : false;
}
},
_storeResource: {
enumerable: false,
value: function(resourceID, resource) {
if (!resourceID) {
console.log("ERROR: entry does not contain id, cannot store");
return;
}
if (this._containsResource[resourceID]) {
console.log("WARNING: resource:"+resourceID+" is already stored, overriding");
}
this._resources[resourceID] = resource;
}
},
_getResource: {
enumerable: false,
value: function(resourceID) {
return this._resources[resourceID];
}
},
_loadStream: {
value: function(path, type, delegate) {
var self = this;
if (!type) {
delegate.handleError(THREE.GLTFLoaderUtils.INVALID_TYPE, null);
return;
}
if (!path) {
delegate.handleError(THREE.GLTFLoaderUtils.INVALID_PATH);
return;
}
var xhr = new XMLHttpRequest();
xhr.open('GET', path, true);
xhr.responseType = (type === this.ARRAY_BUFFER) ? "arraybuffer" : "text";
//if this is not specified, 1 "big blob" scenes fails to load.
xhr.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
xhr.onload = function(e) {
if ((xhr.status == 200) || (xhr.status == 206)) {
delegate.streamAvailable(path, xhr.response);
} else {
delegate.handleError(THREE.GLTFLoaderUtils.XMLHTTPREQUEST_STATUS_ERROR, this.status);
}
};
xhr.send(null);
}
},
send: { value: 0, writable: true },
requested: { value: 0, writable: true },
_handleRequest: {
value: function(request) {
var resourceStatus = this._resourcesStatus[request.id];
if (resourceStatus)
{
this._resourcesStatus[request.id]++;
}
else
{
this._resourcesStatus[request.id] = 1;
}
var streamStatus = this._streamsStatus[request.path];
if (streamStatus && streamStatus.status === "loading" )
{
streamStatus.requests.push(request);
return;
}
this._streamsStatus[request.path] = { status : "loading", requests : [request] };
var self = this;
var processResourceDelegate = {};
processResourceDelegate.streamAvailable = function(path, res_) {
var streamStatus = self._streamsStatus[path];
var requests = streamStatus.requests;
requests.forEach( function(req_) {
var subArray = res_.slice(req_.range[0], req_.range[1]);
var convertedResource = req_.delegate.convert(subArray, req_.ctx);
self._storeResource(req_.id, convertedResource);
req_.delegate.resourceAvailable(convertedResource, req_.ctx);
--self._resourcesStatus[req_.id];
}, this);
delete self._streamsStatus[path];
};
processResourceDelegate.handleError = function(errorCode, info) {
request.delegate.handleError(errorCode, info);
}
this._loadStream(request.path, request.type, processResourceDelegate);
}
},
_elementSizeForGLType: {
value: function(glType) {
switch (glType) {
case WebGLRenderingContext.FLOAT :
return Float32Array.BYTES_PER_ELEMENT;
case WebGLRenderingContext.UNSIGNED_BYTE :
return Uint8Array.BYTES_PER_ELEMENT;
case WebGLRenderingContext.UNSIGNED_SHORT :
return Uint16Array.BYTES_PER_ELEMENT;
case WebGLRenderingContext.FLOAT_VEC2 :
return Float32Array.BYTES_PER_ELEMENT * 2;
case WebGLRenderingContext.FLOAT_VEC3 :
return Float32Array.BYTES_PER_ELEMENT * 3;
case WebGLRenderingContext.FLOAT_VEC4 :
return Float32Array.BYTES_PER_ELEMENT * 4;
case WebGLRenderingContext.FLOAT_MAT3 :
return Float32Array.BYTES_PER_ELEMENT * 9;
case WebGLRenderingContext.FLOAT_MAT4 :
return Float32Array.BYTES_PER_ELEMENT * 16;
default:
return null;
}
}
},
_handleWrappedBufferViewResourceLoading: {
value: function(wrappedBufferView, delegate, ctx) {
var bufferView = wrappedBufferView.bufferView;
var buffer = bufferView.buffer;
var byteOffset = wrappedBufferView.byteOffset + bufferView.description.byteOffset;
var range = [byteOffset , (this._elementSizeForGLType(wrappedBufferView.type) * wrappedBufferView.count) + byteOffset];
this._handleRequest({ "id" : wrappedBufferView.id,
"range" : range,
"type" : buffer.description.type,
"path" : buffer.description.path,
"delegate" : delegate,
"ctx" : ctx }, null);
}
},
getBuffer: {
value: function(wrappedBufferView, delegate, ctx) {
var savedBuffer = this._getResource(wrappedBufferView.id);
if (savedBuffer) {
return savedBuffer;
} else {
this._handleWrappedBufferViewResourceLoading(wrappedBufferView, delegate, ctx);
}
return null;
}
},
getFile: {
value: function(request, delegate, ctx) {
request.delegate = delegate;
request.ctx = ctx;
this._handleRequest({ "id" : request.id,
"path" : request.path,
"range" : [0],
"type" : "text",
"delegate" : delegate,
"ctx" : ctx }, null);
return null;
}
},
});
---UPDATED 2/21/2007
Scaled down the duck to a more reasonable size, removed physics scene, removed extra "dummy" transforms and pivot points, added camera and light.
---
This model is a typical bathtub rubber duck. It uses a single texture.
One version uses a polylist the other is triangles only.
The model has been stripped of all <extra> tags and should be COLLADA 1.4.1 compliant.
For additional information post messages on www.collada.org or mail collada@collada.org
These models are Copyright 2006 Sony Computer Entertainment Inc. and are distributed under the terms of the SCEA Shared Source License, available at http://research.scea.com/scea_shared_source_license.html
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{
"accessors": {
"attribute_23": {
"bufferView": "bufferView_29",
"byteOffset": 0,
"byteStride": 12,
"count": 2399,
"max": [
96.1799,
163.97,
53.9252
],
"min": [
-69.2985,
9.92937,
-61.3282
],
"type": 35665
},
"attribute_25": {
"bufferView": "bufferView_29",
"byteOffset": 28788,
"byteStride": 12,
"count": 2399,
"max": [
0.999599,
0.999581,
0.998436
],
"min": [
-0.999084,
-1,
-0.999832
],
"type": 35665
},
"attribute_27": {
"bufferView": "bufferView_29",
"byteOffset": 57576,
"byteStride": 8,
"count": 2399,
"max": [
0.983346,
0.980037
],
"min": [
0.026409,
0.019963
],
"type": 35664
},
"indices_21": {
"bufferView": "bufferView_30",
"byteOffset": 0,
"count": 12636,
"type": 5123
}
},
"animations": {},
"asset": {
"generator": "collada2gltf@75061f683116dc0ffdad48f33c226e933132e98c"
},
"bufferViews": {
"bufferView_29": {
"buffer": "duck",
"byteLength": 76768,
"byteOffset": 0,
"target": 34962
},
"bufferView_30": {
"buffer": "duck",
"byteLength": 25272,
"byteOffset": 76768,
"target": 34963
},
"bufferView_31": {
"buffer": "duck",
"byteLength": 0,
"byteOffset": 102040
}
},
"buffers": {
"duck": {
"byteLength": 102040,
"path": "duck.bin",
"type": "arraybuffer"
}
},
"cameras": {
"camera_0": {
"perspective": {
"aspect_ratio": 1.5,
"yfov": 37.8492,
"zfar": 10000,
"znear": 1
},
"type": "perspective"
}
},
"images": {
"image_0": {
"path": "duckCM.png"
}
},
"lights": {
"directionalLightShape1-lib": {
"directional": {
"color": [
1,
1,
1
]
},
"type": "directional"
}
},
"materials": {
"blinn3-fx": {
"instanceTechnique": {
"technique": "technique1",
"values": {
"ambient": [
0,
0,
0,
1
],
"diffuse": "texture_image_0",
"emission": [
0,
0,
0,
1
],
"shininess": 38.4,
"specular": [
0,
0,
0,
1
]
}
},
"name": "blinn3"
}
},
"meshes": {
"LOD3spShape-lib": {
"name": "LOD3spShape",
"primitives": [
{
"attributes": {
"NORMAL": "attribute_25",
"POSITION": "attribute_23",
"TEXCOORD_0": "attribute_27"
},
"indices": "indices_21",
"material": "blinn3-fx",
"primitive": 4
}
]
}
},
"nodes": {
"LOD3sp": {
"children": [],
"matrix": [
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1
],
"meshes": [
"LOD3spShape-lib"
],
"name": "LOD3sp"
},
"camera1": {
"camera": "camera_0",
"children": [],
"matrix": [
-0.728969,
0,
-0.684547,
0,
-0.425205,
0.783693,
0.452797,
0,
0.536475,
0.621148,
-0.571288,
0,
400.113,
463.264,
-431.078,
1
],
"name": "camera1"
},
"directionalLight1": {
"children": [],
"light": "directionalLightShape1-lib",
"matrix": [
-0.954692,
0.218143,
-0.202428,
0,
0.0146721,
0.713885,
0.700109,
0,
0.297235,
0.665418,
-0.684741,
0,
148.654,
183.672,
-292.179,
1
],
"name": "directionalLight1"
}
},
"profile": "WebGL 1.0.2",
"programs": {
"program_0": {
"attributes": [
"a_normal",
"a_position",
"a_texcoord0"
],
"fragmentShader": "duck0FS",
"vertexShader": "duck0VS"
}
},
"samplers": {
"sampler_0": {
"magFilter": 9729,
"minFilter": 9987,
"wrapS": 10497,
"wrapT": 10497
}
},
"scene": "defaultScene",
"scenes": {
"defaultScene": {
"nodes": [
"LOD3sp",
"camera1",
"directionalLight1"
]
}
},
"shaders": {
"duck0FS": {
"path": "duck0FS.glsl"
},
"duck0VS": {
"path": "duck0VS.glsl"
}
},
"skins": {},
"techniques": {
"technique1": {
"parameters": {
"ambient": {
"type": 35666
},
"diffuse": {
"type": 35678
},
"emission": {
"type": 35666
},
"light0Color": {
"type": 35665,
"value": [
1,
1,
1
]
},
"light0Transform": {
"source": "directionalLight1",
"type": 35676
},
"modelViewMatrix": {
"semantic": "MODELVIEW",
"type": 35676
},
"normal": {
"semantic": "NORMAL",
"type": 35665
},
"normalMatrix": {
"semantic": "MODELVIEWINVERSETRANSPOSE",
"type": 35675
},
"position": {
"semantic": "POSITION",
"type": 35665
},
"projectionMatrix": {
"semantic": "PROJECTION",
"type": 35676
},
"shininess": {
"type": 5126
},
"specular": {
"type": 35666
},
"texcoord0": {
"semantic": "TEXCOORD_0",
"type": 35664
}
},
"pass": "defaultPass",
"passes": {
"defaultPass": {
"details": {
"commonProfile": {
"extras": {
"doubleSided": false
},
"lightingModel": "Blinn",
"parameters": [
"ambient",
"diffuse",
"emission",
"light0Color",
"light0Transform",
"modelViewMatrix",
"normalMatrix",
"projectionMatrix",
"shininess",
"specular"
],
"texcoordBindings": {
"diffuse": "TEXCOORD_0"
}
},
"type": "COLLADA-1.4.1/commonProfile"
},
"instanceProgram": {
"attributes": {
"a_normal": "normal",
"a_position": "position",
"a_texcoord0": "texcoord0"
},
"program": "program_0",
"uniforms": {
"u_ambient": "ambient",
"u_diffuse": "diffuse",
"u_emission": "emission",
"u_light0Color": "light0Color",
"u_light0Transform": "light0Transform",
"u_modelViewMatrix": "modelViewMatrix",
"u_normalMatrix": "normalMatrix",
"u_projectionMatrix": "projectionMatrix",
"u_shininess": "shininess",
"u_specular": "specular"
}
},
"states": {
"blendEnable": 0,
"cullFaceEnable": 1,
"depthMask": 1,
"depthTestEnable": 1
}
}
}
}
},
"textures": {
"texture_image_0": {
"format": 6408,
"internalFormat": 6408,
"sampler": "sampler_0",
"source": "image_0",
"target": 3553
}
}
}
\ No newline at end of file
precision highp float;
varying vec3 v_normal;
uniform vec3 u_light0Color;
varying vec3 v_light0Direction;
uniform float u_shininess;
uniform vec4 u_ambient;
varying vec2 v_texcoord0;
uniform sampler2D u_diffuse;
uniform vec4 u_emission;
uniform vec4 u_specular;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec3 diffuseLight = vec3(0., 0., 0.);
vec4 emission;
vec4 ambient;
vec4 specular;
vec3 specularLight = vec3(0., 0., 0.);
{
float diffuseIntensity;
float specularIntensity;
vec3 l = normalize(v_light0Direction);
vec3 h = normalize(l+vec3(0.,0.,1.));
diffuseIntensity = max(dot(normal,l), 0.);
specularIntensity = pow(max(0.0,dot(normal,h)),u_shininess);
specularLight += u_light0Color * specularIntensity;
diffuseLight += u_light0Color * diffuseIntensity;
}
ambient = u_ambient;
diffuse = texture2D(u_diffuse, v_texcoord0);
emission = u_emission;
specular = u_specular;
specular.xyz *= specularLight;
color.xyz += specular.xyz;
diffuse.xyz *= diffuseLight;
color.xyz += diffuse.xyz;
color.xyz += emission.xyz;
color = vec4(color.rgb * diffuse.a, diffuse.a);
gl_FragColor = color;
}
precision highp float;
attribute vec3 a_position;
attribute vec3 a_normal;
varying vec3 v_normal;
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
uniform mat4 u_light0Transform;
varying vec3 v_light0Direction;
attribute vec2 a_texcoord0;
varying vec2 v_texcoord0;
void main(void) {
vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);
v_normal = normalize(u_normalMatrix * a_normal);
v_light0Direction = normalize(mat3(u_light0Transform) * vec3(0.,0.,1.));
v_texcoord0 = a_texcoord0;
gl_Position = u_projectionMatrix * pos;
}
此差异已折叠。
此差异已折叠。
precision highp float;
varying vec3 v_normal;
varying vec4 v_joint;
varying vec4 v_weight;
uniform float u_shininess;
uniform vec4 u_ambient;
varying vec2 v_texcoord0;
uniform sampler2D u_diffuse;
uniform vec4 u_specular;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = texture2D(u_diffuse, v_texcoord0);
specular = u_specular;
diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.);
color.xyz += diffuse.xyz;
color = vec4(color.rgb * diffuse.a, diffuse.a);
gl_FragColor = color;
}
precision highp float;
attribute vec3 a_position;
attribute vec3 a_normal;
varying vec3 v_normal;
attribute vec4 a_joint;
varying vec4 v_joint;
attribute vec4 a_weight;
varying vec4 v_weight;
uniform mat4 u_jointMat[60];
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
attribute vec2 a_texcoord0;
varying vec2 v_texcoord0;
void main(void) {
mat4 skinMat = a_weight.x * u_jointMat[int(a_joint.x)];
skinMat += a_weight.y * u_jointMat[int(a_joint.y)];
skinMat += a_weight.z * u_jointMat[int(a_joint.z)];
skinMat += a_weight.w * u_jointMat[int(a_joint.w)];
vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);
v_normal = normalize(u_normalMatrix * mat3(skinMat)* a_normal);
v_texcoord0 = a_texcoord0;
gl_Position = u_projectionMatrix * pos;
}
Model from http://www.3drt.com/downloads.htm
<!doctype html>
<html lang="en">
<head>
<title>three.js webgl - glTF</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: #EEF;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
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:250px;
bottom:0%;
right:0%;
height:134px;
background-color:White;
opacity:.9;
font: 13px/1.231 "Lucida Grande", Lucida, Verdana, sans-serif;
}
#status {
position:absolute;
width:25%;
left:2%;
top:95%;
height:5%;
opacity:.9;
font: 13px/1.231 "Lucida Grande", Lucida, Verdana, sans-serif;
}
.control {
position:absolute;
margin-left:12px;
width:100%;
font-weight:bold;
}
.controlValue {
position:absolute;
left:36%;
top:0%;
}
#scenes_control {
position:absolute;
top:8px;
}
#cameras_control {
position:absolute;
top:40px;
}
#animations_control {
position:absolute;
top:72px;
}
#buffer_geometry_control {
position:absolute;
top:104px;
}
#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="http://gltf.gl/" target="_blank">glTF</a> loader -
<br></br>
monster by <a href="http://www.3drt.com/downloads.htm" target="_blank">3drt</a> -
COLLADA duck by Sony
</div>
<div id="container">
</div>
<div id="status">
</div>
<div id="controls">
<div class="control" id="scenes_control">
Model
<select class="controlValue" id="scenes_list" size="1" onchange="selectScene();" ondblclick="selectScene();">
</select>
</div>
<div class="control" id="cameras_control">
Camera
<select class="controlValue" id="cameras_list" size="1" onchange="selectCamera();" ondblclick="selectCamera();">
</select>
</div>
<div class="control" id="animations_control">
Animations
<div class="controlValue"><input type="checkbox" checked onclick="toggleAnimations();">Play</input></div>
</div>
<div class="control" id="buffer_geometry_control">
Geometry
<div class="controlValue">
<input type="checkbox" id="buffer_geometry_checkbox" checked onclick="toggleBufferGeometry();">BufferGeometry</input>
</div>
</div>
</div>
<script src="../build/three.js"></script>
<script src="./js/controls/OrbitControls.js"></script>
<script src="./js/loaders/gltf/glTF-parser.js"></script>
<script src="./js/loaders/gltf/glTFLoader.js"></script>
<script src="./js/loaders/gltf/glTFLoaderUtils.js"></script>
<script src="./js/loaders/gltf/glTFAnimation.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;
function onload() {
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'keypress',
function(e) { onKeyPress(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( 0x888888 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xdddddd );
directionalLight.position.set( 0, -1, 1 ).normalize();
scene.add( directionalLight );
spot1 = new THREE.SpotLight( 0xffffff, 1 );
spot1.position.set( -100, 200, 100 );
spot1.target.position.set( 0, 0, 0 );
if (sceneInfo.shadows) {
spot1.shadowCameraNear = 1;
spot1.shadowCameraFar = 1024;
spot1.castShadow = true;
spot1.shadowDarkness = 0.3;
spot1.shadowBias = 0.0001;
spot1.shadowMapWidth = 2048;
spot1.shadowMapHeight = 2048;
}
scene.add( spot1 );
}
// RENDERER
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( container.offsetWidth, container.offsetHeight );
if (sceneInfo.shadows) {
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
}
container.appendChild( renderer.domElement );
var ground = null;
if (sceneInfo.addGround) {
var groundMaterial = new THREE.MeshPhongMaterial({
color: 0xFFFFFF,
ambient: 0x888888,
shading: THREE.SmoothShading,
});
ground = new THREE.Mesh( new THREE.PlaneGeometry(1024, 1024), 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.glTFLoader;
loader.useBufferGeometry = useBufferGeometry;
var loadStartTime = Date.now();
var status = document.getElementById("status");
status.innerHTML = "Loading...";
loader.load( sceneInfo.url, function(data) {
gltf = data;
var object = gltf.scene;
var loadEndTime = Date.now();
var loadTime = (loadEndTime - loadStartTime) / 1000;
status.innerHTML = "Load time: " + loadTime.toFixed(2) + " seconds.";
if (sceneInfo.cameraPos)
defaultCamera.position.copy(sceneInfo.cameraPos);
if (sceneInfo.center) {
orbitControls.center.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);
}
if (gltf.animations && gltf.animations.length) {
var i, len = gltf.animations.length;
for (i = 0; i < len; i++) {
var animation = gltf.animations[i];
animation.loop = true;
// 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;
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( container.offsetWidth, container.offsetHeight );
}
function animate() {
requestAnimationFrame( animate );
THREE.glTFAnimator.update();
if (cameraIndex == 0)
orbitControls.update();
render();
}
function render() {
renderer.render( scene, camera );
}
function onKeyPress(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 : "Monster", url : "./models/gltf/monster/monster.json",
cameraPos: new THREE.Vector3(30, 10, 70),
objectScale: new THREE.Vector3(0.01, 0.01, 0.01),
objectPosition: new THREE.Vector3(0, 1, 0),
objectRotation: new THREE.Euler(-Math.PI / 2, 0, -Math.PI / 2),
animationTime: 3,
addLights:true,
shadows:true,
addGround:true },
{ name : "Duck", url : "./models/gltf/duck/duck.json",
cameraPos: new THREE.Vector3(0, 30, -50),
objectScale: new THREE.Vector3(0.1, 0.1, 0.1),
addLights:true,
addGround:true,
shadows:true },
];
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 animation = gltf.animations[i];
if (animation.running) {
animation.stop();
}
else {
animation.play();
}
}
}
var usebuf = document.getElementById("buffer_geometry_checkbox");
var useBufferGeometry = usebuf.hasAttribute("checked");
function toggleBufferGeometry()
{
useBufferGeometry = !useBufferGeometry;
selectScene();
}
function cleanup() {
if (container && renderer)
{
container.removeChild(renderer.domElement);
}
cameraIndex = 0;
cameras = [];
cameraNames = [];
defaultCamera = null;
if (!loader || !gltf.animations)
return;
var i, len = gltf.animations.length;
for (i = 0; i < len; i++) {
var animation = gltf.animations[i];
if (animation.running) {
animation.stop();
}
}
}
onload();
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册