提交 5bfe4037 编写于 作者: T Tony Parisi

Upgrade glTF Loader to v1.0

上级 fb9a8d49
......@@ -22,364 +22,374 @@
// 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]
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).
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.
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:
When case #1 is used the followed dependency order is:
scenes -> nodes -> meshes -> materials -> techniques -> shaders
-> buffers
-> cameras
-> lights
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
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.
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.
// 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.
// AMD. Register as an anonymous module.
define([], function () {
return factory(root);
});
} else {
// Browser globals
// 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 categoriesDepsOrder = ["extensions", "buffers", "bufferViews", "images", "videos", "samplers", "textures", "shaders", "programs", "techniques", "materials", "accessors", "meshes", "cameras", "lights", "skins", "nodes", "animations", "scenes"];
var glTFParser = Object.create(Object.prototype, {
_rootDescription: { value: null, writable: true },
_rootDescription: { value: null, writable: true },
rootDescription: {
set: function(value) {
this._rootDescription = value;
},
get: function() {
return this._rootDescription;
}
},
baseURL: { value: null, writable: true },
rootDescription: {
set: function(value) {
this._rootDescription = value;
},
get: function() {
return this._rootDescription;
}
},
//detect absolute path following the same protocol than window.location
_isAbsolutePath: {
value: function(path) {
var isAbsolutePathRegExp = new RegExp("^" + window.location.protocol, "i");
baseURL: { value: null, writable: true },
return path.match(isAbsolutePathRegExp) ? true : false;
}
},
//detect absolute path following the same protocol than window.location
_isAbsolutePath: {
value: function(path) {
var isAbsolutePathRegExp = new RegExp("^"+window.location.protocol, "i");
resolvePathIfNeeded: {
value: function(path) {
if (this._isAbsolutePath(path)) {
return path;
}
return path.match(isAbsolutePathRegExp) ? true : false;
}
},
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;
}
resolvePathIfNeeded: {
value: function(path) {
if (this._isAbsolutePath(path)) {
return path;
}
return entries ? entries[entryID] : null;
}
},
var isDataUriRegex = /^data:/;
if (isDataUriRegex.test(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.uri = this.resolvePathIfNeeded(description.uri);
}, 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;
}
_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 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;
}
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;
categoryState.index++;
categoryState.keys = null;
if (categoryState.index >= keys.length) {
return this._stepToNextCategory();
}
return false;
}
}
},
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;
hasCategory: {
value: function(category) {
return this.rootDescription[category] ? true : false;
}
} else {
},
_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,
"extensions" : this.handleExtension,
};
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 (methodForType[type]) {
if (methodForType[type].call(this, entryID, description, this._state.userInfo) === false) {
success = false;
break;
if (this.handleLoadCompleted) {
this.handleLoadCompleted(success);
}
}
this._stepToNextDescription();
}
}
}
},
_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);
}
if (this.handleLoadCompleted) {
this.handleLoadCompleted(success);
}
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;
}
}
}
},
_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.addEventListener( 'load', function ( event ) {
self.json = JSON.parse(jsonfile.responseText);
if (callback) {
callback(self.json);
return -1;
}
}, false );
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);
}
},
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();
}
});
}
},
this._loadJSONIfNeeded(JSONReady);
}
},
initWithPath: {
value: function(path) {
this._path = path;
this._json = null;
return this;
}
},
_state: { value: null, writable: true },
//this is meant to be global and common for all instances
_knownURLs: { writable: true, value: {} },
_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;
//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;
}
}
}
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) {
if(root) {
root.glTFParser = glTFParser;
}
......
......@@ -24,7 +24,7 @@ THREE.glTFAnimator = ( function () {
update : function()
{
for (i = 0; i < animators.length; i ++)
for (i = 0; i < animators.length; i++)
{
animators[i].update();
}
......@@ -45,18 +45,18 @@ THREE.glTFAnimation = function(interps)
{
this.createInterpolators(interps);
}
};
}
THREE.glTFAnimation.prototype.createInterpolators = function(interps)
{
var i, len = interps.length;
for (i = 0; i < len; i ++)
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()
......@@ -67,13 +67,13 @@ THREE.glTFAnimation.prototype.play = function()
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()
......@@ -90,7 +90,7 @@ THREE.glTFAnimation.prototype.update = function()
{
this.running = false;
var i, len = this.interps.length;
for (i = 0; i < len; i ++)
for (i = 0; i < len; i++)
{
this.interps[i].interp(this.duration);
}
......@@ -100,12 +100,12 @@ THREE.glTFAnimation.prototype.update = function()
else
{
var i, len = this.interps.length;
for (i = 0; i < len; i ++)
for (i = 0; i < len; i++)
{
this.interps[i].interp(t);
}
}
};
}
//Interpolator class
//Construction/initialization
......@@ -147,7 +147,7 @@ THREE.glTFInterpolator = function(param)
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)
......@@ -202,7 +202,7 @@ THREE.glTFInterpolator.prototype.interp = function(t)
}
else
{
for (i = 0; i < this.count - 1; i ++)
for (i = 0; i < this.count - 1; i++)
{
var key1 = this.keys[i];
var key2 = this.keys[i + 1];
......@@ -238,7 +238,7 @@ THREE.glTFInterpolator.prototype.interp = function(t)
{
this.copyValue(this.target);
}
};
}
THREE.glTFInterpolator.prototype.copyValue = function(target) {
......@@ -248,4 +248,4 @@ THREE.glTFInterpolator.prototype.copyValue = function(target) {
else {
target.copy(this.vec3);
}
};
}
......@@ -26,8 +26,8 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
value: function() {
this._streams = {};
this._streamsStatus = {};
this._resources = {};
this._resourcesStatus = {};
this._resources = {};
this._resourcesStatus = {};
}
},
......@@ -35,60 +35,119 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
_containsResource: {
enumerable: false,
value: function(resourceID) {
return this._resources[resourceID] ? true : false;
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 (!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");
}
if (this._containsResource[resourceID]) {
console.log("WARNING: resource:"+resourceID+" is already stored, overriding");
}
this._resources[resourceID] = resource;
this._resources[resourceID] = resource;
}
},
_getResource: {
enumerable: false,
value: function(resourceID) {
return this._resources[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";
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
function decodeDataUriText(isBase64, data) {
var result = decodeURIComponent(data);
if (isBase64) {
return atob(result);
}
return result;
}
function decodeDataUriArrayBuffer(isBase64, data) {
var byteString = decodeDataUriText(isBase64, data);
var buffer = new ArrayBuffer(byteString.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < byteString.length; i++) {
view[i] = byteString.charCodeAt(i);
}
return buffer;
}
function decodeDataUri(dataUriRegexResult, responseType) {
responseType = typeof responseType !== 'undefined' ? responseType : '';
var mimeType = dataUriRegexResult[1];
var isBase64 = !!dataUriRegexResult[2];
var data = dataUriRegexResult[3];
switch (responseType) {
case '':
case 'text':
return decodeDataUriText(isBase64, data);
case 'ArrayBuffer':
return decodeDataUriArrayBuffer(isBase64, data);
case 'blob':
var buffer = decodeDataUriArrayBuffer(isBase64, data);
return new Blob([buffer], {
type : mimeType
});
case 'document':
var parser = new DOMParser();
return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
case 'json':
return JSON.parse(decodeDataUriText(isBase64, data));
default:
throw 'Unhandled responseType: ' + responseType;
}
}
var dataUriRegexResult = dataUriRegex.exec(path);
if (dataUriRegexResult !== null) {
delegate.streamAvailable(path, decodeDataUri(dataUriRegexResult, type));
return;
}
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.addEventListener( 'load', function ( event ) {
delegate.streamAvailable(path, xhr.response);
}, false );
xhr.addEventListener( 'error', function ( event ) {
delegate.handleError(THREE.GLTFLoaderUtils.XMLHTTPREQUEST_STATUS_ERROR, xhr.status);
}, false );
xhr.send(null);
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);
}
},
......@@ -97,89 +156,109 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
_handleRequest: {
value: function(request) {
var resourceStatus = this._resourcesStatus[request.id];
if (resourceStatus)
var resourceStatus = this._resourcesStatus[request.id];
if (resourceStatus)
{
this._resourcesStatus[request.id] ++;
}
this._resourcesStatus[request.id]++;
}
else
{
this._resourcesStatus[request.id] = 1;
}
{
this._resourcesStatus[request.id] = 1;
}
var streamStatus = this._streamsStatus[request.path];
if (streamStatus && streamStatus.status === "loading" )
var streamStatus = this._streamsStatus[request.uri];
if (streamStatus && streamStatus.status === "loading" )
{
streamStatus.requests.push(request);
return;
}
streamStatus.requests.push(request);
return;
}
this._streamsStatus[request.path] = { status : "loading", requests : [ request ] };
this._streamsStatus[request.uri] = { 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);
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];
delete self._streamsStatus[path];
};
};
processResourceDelegate.handleError = function(errorCode, info) {
request.delegate.handleError(errorCode, info);
};
processResourceDelegate.handleError = function(errorCode, info) {
request.delegate.handleError(errorCode, info);
}
this._loadStream(request.path, request.type, processResourceDelegate);
this._loadStream(request.uri, 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;
}
value: function(componentType, type) {
var nElements = 0;
switch(type) {
case "SCALAR" :
nElements = 1;
break;
case "VEC2" :
nElements = 2;
break;
case "VEC3" :
nElements = 3;
break;
case "VEC4" :
nElements = 4;
break;
case "MAT2" :
nElements = 4;
break;
case "MAT3" :
nElements = 9;
break;
case "MAT4" :
nElements = 16;
break;
default :
debugger;
break;
}
switch (componentType) {
case WebGLRenderingContext.FLOAT :
return Float32Array.BYTES_PER_ELEMENT * nElements;
case WebGLRenderingContext.UNSIGNED_BYTE :
return Uint8Array.BYTES_PER_ELEMENT * nElements;
case WebGLRenderingContext.UNSIGNED_SHORT :
return Uint16Array.BYTES_PER_ELEMENT * nElements;
default :
debugger;
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 ];
var bufferView = wrappedBufferView.bufferView;
var buffer = bufferView.buffer;
var byteOffset = wrappedBufferView.byteOffset + bufferView.description.byteOffset;
var range = [byteOffset , (this._elementSizeForGLType(wrappedBufferView.componentType, wrappedBufferView.type) * wrappedBufferView.count) + byteOffset];
this._handleRequest({ "id" : wrappedBufferView.id,
this._handleRequest({ "id" : wrappedBufferView.id,
"range" : range,
"type" : buffer.description.type,
"path" : buffer.description.path,
"uri" : buffer.description.uri,
"delegate" : delegate,
"ctx" : ctx }, null);
}
......@@ -189,14 +268,14 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
value: function(wrappedBufferView, delegate, ctx) {
var savedBuffer = this._getResource(wrappedBufferView.id);
if (savedBuffer) {
return savedBuffer;
} else {
this._handleWrappedBufferViewResourceLoading(wrappedBufferView, delegate, ctx);
}
var savedBuffer = this._getResource(wrappedBufferView.id);
if (false) { // savedBuffer) {
return savedBuffer;
} else {
this._handleWrappedBufferViewResourceLoading(wrappedBufferView, delegate, ctx);
}
return null;
return null;
}
},
......@@ -204,17 +283,17 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
value: function(request, delegate, ctx) {
request.delegate = delegate;
request.ctx = ctx;
request.delegate = delegate;
request.ctx = ctx;
this._handleRequest({ "id" : request.id,
"path" : request.path,
"range" : [ 0 ],
this._handleRequest({ "id" : request.id,
"uri" : request.uri,
"range" : [0],
"type" : "text",
"delegate" : delegate,
"ctx" : ctx }, null);
return null;
}
return null;
}
},
});
/**
* @author Tony Parisi / http://www.tonyparisi.com/
*/
THREE.glTFShaders = ( function () {
var shaders = [];
return {
add : function(shader) {
shaders.push(shader);
},
remove: function(shader) {
var i = shaders.indexOf(shader);
if ( i !== -1 ) {
shaders.splice( i, 1 );
}
},
removeAll: function(shader) {
// probably want to clean up the shaders, too, but not for now
shaders = [];
},
bindShaderParameters: function(scene) {
for (i = 0; i < shaders.length; i++)
{
shaders[i].bindParameters(scene);
}
},
update : function(scene, camera) {
for (i = 0; i < shaders.length; i++)
{
shaders[i].update(scene, camera);
}
},
};
})();
// Construction/initialization
THREE.glTFShader = function(material, params, object, scene) {
this.material = material;
this.parameters = params.technique.parameters;
this.uniforms = params.technique.uniforms;
this.joints = params.joints;
this.object = object;
this.semantics = {};
this.m4 = new THREE.Matrix4;
}
// bindParameters - connect the uniform values to their source parameters
THREE.glTFShader.prototype.bindParameters = function(scene) {
function findObject(o, p) {
if (o.glTFID == param.node) {
p.sourceObject = o;
}
}
for (var uniform in this.uniforms) {
var pname = this.uniforms[uniform];
var param = this.parameters[pname];
if (param.semantic) {
var p = {
semantic : param.semantic,
uniform: this.material.uniforms[uniform]
};
if (param.node) {
scene.traverse(function(o) { findObject(o, p)});
}
else {
p.sourceObject = this.object;
}
this.semantics[pname] = p;
}
}
}
// Update - update all the uniform values
THREE.glTFShader.prototype.update = function(scene, camera) {
// update scene graph
scene.updateMatrixWorld();
// update camera matrices and frustum
camera.updateMatrixWorld();
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
for (var sname in this.semantics) {
var semantic = this.semantics[sname];
if (semantic) {
switch (semantic.semantic) {
case "MODELVIEW" :
var m4 = semantic.uniform.value;
m4.multiplyMatrices(camera.matrixWorldInverse,
semantic.sourceObject.matrixWorld);
break;
case "MODELVIEWINVERSETRANSPOSE" :
var m3 = semantic.uniform.value;
this.m4.multiplyMatrices(camera.matrixWorldInverse,
semantic.sourceObject.matrixWorld);
m3.getNormalMatrix(this.m4);
break;
case "PROJECTION" :
var m4 = semantic.uniform.value;
m4.copy(camera.projectionMatrix);
break;
case "JOINTMATRIX" :
var m4v = semantic.uniform.value;
for (var mi = 0; mi < m4v.length; mi++) {
// So it goes like this:
// SkinnedMesh world matrix is already baked into MODELVIEW;
// ransform joints to local space,
// then transform using joint's inverse
m4v[mi].getInverse(semantic.sourceObject.matrixWorld).
multiply(this.joints[mi].matrixWorld).
multiply(this.object.skeleton.boneInverses[mi]);
}
//console.log("Joint:", semantic)
break;
default :
throw new Error("Unhandled shader semantic" + semantic);
break;
}
}
}
}
/**
gltfUtilities
@license
The MIT License (MIT)
Copyright (c) 2014 Analytical Graphics, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
(function(root, factory) {
"use strict";
/*global define*/
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else {
// Browser globals
root.gltfUtilities = factory();
}
}(this, function() {
"use strict";
/**
* Given a URL, determine whether that URL is considered cross-origin to the current page.
*/
var isCrossOriginUrl = function(url) {
var location = window.location;
var a = document.createElement('a');
a.href = url;
// host includes both hostname and port if the port is not standard
return location.protocol !== a.protocol || location.host !== a.host;
};
var isDataUriRegex = /^data:/;
/**
* Asynchronously loads the given image URL. Attempts to load cross-origin images using CORS.
*
* @param {String} url The source of the image.
* @param {Function} success A function that will be called with an Image object
* once the image has loaded successfully.
* @param {Function} [error] A function that will be called if the request fails.
*
* @see <a href='http://www.w3.org/TR/cors/'>Cross-Origin Resource Sharing</a>
*/
var loadImage = function(url, success, error) {
var image = new Image();
image.onload = function() {
success(image);
};
if (typeof error !== 'undefined') {
image.onerror = error;
}
var crossOrigin;
if (isDataUriRegex.test(url)) {
crossOrigin = false;
} else {
crossOrigin = isCrossOriginUrl(url);
}
if (crossOrigin) {
image.crossOrigin = '';
}
image.src = url;
};
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
function decodeDataUriText(isBase64, data) {
var result = decodeURIComponent(data);
if (isBase64) {
return atob(result);
}
return result;
}
function decodeDataUriArrayBuffer(isBase64, data) {
var byteString = decodeDataUriText(isBase64, data);
var buffer = new ArrayBuffer(byteString.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < byteString.length; i++) {
view[i] = byteString.charCodeAt(i);
}
return buffer;
}
function decodeDataUri(dataUriRegexResult, responseType) {
responseType = typeof responseType !== 'undefined' ? responseType : '';
var mimeType = dataUriRegexResult[1];
var isBase64 = !!dataUriRegexResult[2];
var data = dataUriRegexResult[3];
switch (responseType) {
case '':
case 'text':
return decodeDataUriText(isBase64, data);
case 'arraybuffer':
return decodeDataUriArrayBuffer(isBase64, data);
case 'blob':
var buffer = decodeDataUriArrayBuffer(isBase64, data);
return new Blob([buffer], {
type : mimeType
});
case 'document':
var parser = new DOMParser();
return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
case 'json':
return JSON.parse(decodeDataUriText(isBase64, data));
default:
throw 'Unhandled responseType: ' + responseType;
}
}
var loadWithXhr = function(url, responseType, success, error) {
var dataUriRegexResult = dataUriRegex.exec(url);
if (dataUriRegexResult !== null) {
success(decodeDataUri(dataUriRegexResult, responseType));
return;
}
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
if (typeof responseType !== 'undefined') {
xhr.responseType = responseType;
}
xhr.onload = function(e) {
if (xhr.status === 200) {
success(xhr.response);
} else {
error(xhr);
}
};
xhr.onerror = function(e) {
error(xhr);
};
xhr.send();
};
/**
* Asynchronously loads the given URL as raw binary data. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {String} url The URL of the binary data.
* @param {Function} success A function that will be called with an ArrayBuffer object
* once the data has loaded successfully.
* @param {Function} [error] A function that will be called with the XMLHttpRequest object
* if the request fails.
*
* @see <a href="http://en.wikipedia.org/wiki/XMLHttpRequest">XMLHttpRequest</a>
* @see <a href='http://www.w3.org/TR/cors/'>Cross-Origin Resource Sharing</a>
*/
var loadArrayBuffer = function(url, success, error) {
loadWithXhr(url, 'arraybuffer', success, error);
};
/**
* Asynchronously loads the given URL as text. The data is loaded
* using XMLHttpRequest, which means that in order to make requests to another origin,
* the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
*
* @param {String} url The URL to request.
* @param {Function} success A function that will be called with a String
* once the data has loaded successfully.
* @param {Function} [error] A function that will be called with the XMLHttpRequest object
* if the request fails.
*
* @see <a href="http://en.wikipedia.org/wiki/XMLHttpRequest">XMLHttpRequest</a>
* @see <a href='http://www.w3.org/TR/cors/'>Cross-Origin Resource Sharing</a>
*/
var loadText = function(url, success, error) {
return loadWithXhr(url, undefined, success, error);
};
return {
loadImage : loadImage,
loadArrayBuffer : loadArrayBuffer,
loadText : loadText
};
}));
Donated by Cesium for glTF testing. Please follow the Cesium Trademark Terms and Conditions: https://github.com/AnalyticalGraphicsInc/cesium/wiki/CesiumTrademark.pdf
\ No newline at end of file
此差异已折叠。
precision highp float;
varying vec3 v_normal;
uniform vec4 u_ambient;
varying vec2 v_texcoord0;
uniform sampler2D u_diffuse;
uniform vec4 u_emission;
uniform vec4 u_specular;
uniform float u_shininess;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec4 emission;
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = texture2D(u_diffuse, v_texcoord0);
emission = u_emission;
specular = u_specular;
diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.);
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;
attribute vec4 a_joint;
attribute vec4 a_weight;
uniform mat4 u_jointMat[19];
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 = u_normalMatrix * mat3(skinMat)* a_normal;
v_texcoord0 = a_texcoord0;
gl_Position = u_projectionMatrix * pos;
}
Donated by Cesium for glTF testing. Please follow the Cesium Trademark Terms and Conditions: https://github.com/AnalyticalGraphicsInc/cesium/wiki/CesiumTrademark.pdf
\ No newline at end of file
precision highp float;
varying vec3 v_normal;
uniform vec4 u_diffuse;
uniform vec4 u_specular;
uniform float u_shininess;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec4 specular;
diffuse = u_diffuse;
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;
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
void main(void) {
vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);
v_normal = u_normalMatrix * a_normal;
gl_Position = u_projectionMatrix * pos;
}
precision highp float;
varying vec3 v_normal;
varying vec2 v_texcoord0;
uniform sampler2D u_diffuse;
uniform vec4 u_specular;
uniform float u_shininess;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec4 specular;
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;
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
attribute vec2 a_texcoord0;
varying vec2 v_texcoord0;
void main(void) {
vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);
v_normal = u_normalMatrix * a_normal;
v_texcoord0 = a_texcoord0;
gl_Position = u_projectionMatrix * pos;
}
---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
Copyright 2006 Sony Computer Entertainment Inc.
Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:
http://research.scea.com/scea_shared_source_license.html
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{
"accessors": {
"accessor_21": {
"bufferView": "bufferView_29",
"byteOffset": 0,
"byteStride": 0,
"componentType": 5123,
"count": 12636,
"type": "SCALAR"
},
"accessor_23": {
"bufferView": "bufferView_30",
"byteOffset": 0,
"byteStride": 12,
"componentType": 5126,
"count": 2399,
"max": [
0.961799,
1.6397,
0.539252
],
"min": [
-0.692985,
0.0992937,
-0.613282
],
"type": "VEC3"
},
"accessor_25": {
"bufferView": "bufferView_30",
"byteOffset": 28788,
"byteStride": 12,
"componentType": 5126,
"count": 2399,
"max": [
0.999599,
0.999581,
0.998436
],
"min": [
-0.999084,
-1,
-0.999832
],
"type": "VEC3"
},
"accessor_27": {
"bufferView": "bufferView_30",
"byteOffset": 57576,
"byteStride": 8,
"componentType": 5126,
"count": 2399,
"max": [
0.983346,
0.980037
],
"min": [
0.026409,
0.019963
],
"type": "VEC2"
}
},
"animations": {},
"asset": {
"generator": "collada2gltf@cf6371beb0bdc18ba603378d5e40c966da53d385",
"premultipliedAlpha": true,
"profile": {
"api": "WebGL",
"version": "1.0.2"
},
"version": "1.0"
},
"bufferViews": {
"bufferView_29": {
"buffer": "duck",
"byteLength": 25272,
"byteOffset": 0,
"target": 34963
},
"bufferView_30": {
"buffer": "duck",
"byteLength": 76768,
"byteOffset": 25272,
"target": 34962
}
},
"buffers": {
"duck": {
"byteLength": 102040,
"type": "arraybuffer",
"uri": "duck.bin"
}
},
"cameras": {
"cameraShape1": {
"name": "cameraShape1",
"perspective": {
"aspect_ratio": 1.5,
"yfov": 0.660593,
"zfar": 100,
"znear": 0.01
},
"type": "perspective"
}
},
"extensions": {
"KHR_materials_common": {
"lights": {
"directionalLightShape1-lib": {
"directional": {
"color": [
1,
1,
1
]
},
"name": "directionalLightShape1",
"type": "directional"
}
}
}
},
"extensionsUsed": [
"KHR_materials_common"
],
"images": {
"file2": {
"name": "file2",
"uri": "duckCM.png"
}
},
"materials": {
"blinn3-fx": {
"extensions": {
"KHR_materials_common": {
"doubleSided": false,
"jointCount": 0,
"technique": "BLINN",
"transparent": false,
"values": {
"ambient": [
0,
0,
0,
1
],
"diffuse": "texture_file2",
"emission": [
0,
0,
0,
1
],
"shininess": 38.4,
"specular": [
0,
0,
0,
1
]
}
}
},
"name": "blinn3"
}
},
"meshes": {
"LOD3spShape-lib": {
"name": "LOD3spShape",
"primitives": [
{
"attributes": {
"NORMAL": "accessor_25",
"POSITION": "accessor_23",
"TEXCOORD_0": "accessor_27"
},
"indices": "accessor_21",
"material": "blinn3-fx",
"mode": 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": "cameraShape1",
"children": [],
"matrix": [
-0.728969,
0,
-0.684547,
0,
-0.425205,
0.783693,
0.452797,
0,
0.536475,
0.621148,
-0.571288,
0,
4.00113,
4.63264,
-4.31078,
1
],
"name": "camera1"
},
"directionalLight1": {
"children": [],
"extensions": {
"KHR_materials_common": {
"light": "directionalLightShape1-lib"
}
},
"matrix": [
-0.954692,
0.218143,
-0.202429,
0,
0.014672,
0.713885,
0.700109,
0,
0.297235,
0.665418,
-0.684741,
0,
1.48654,
1.83672,
-2.92179,
1
],
"name": "directionalLight1"
}
},
"samplers": {
"sampler_0": {
"magFilter": 9729,
"minFilter": 9987,
"wrapS": 10497,
"wrapT": 10497
}
},
"scene": "defaultScene",
"scenes": {
"defaultScene": {
"nodes": [
"LOD3sp",
"camera1",
"directionalLight1"
]
}
},
"skins": {},
"textures": {
"texture_file2": {
"format": 6408,
"internalFormat": 6408,
"sampler": "sampler_0",
"source": "file2",
"target": 3553,
"type": 5121
}
}
}
\ 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;
uniform float u_shininess;
varying vec3 v_light0Direction;
varying vec3 v_position;
uniform vec3 u_light0Color;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
......@@ -16,21 +17,21 @@ vec3 diffuseLight = vec3(0., 0., 0.);
vec4 emission;
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = texture2D(u_diffuse, v_texcoord0);
emission = u_emission;
specular = u_specular;
vec3 specularLight = vec3(0., 0., 0.);
{
float diffuseIntensity;
float specularIntensity;
float specularIntensity = 0.;
float attenuation = 1.0;
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);
vec3 viewDir = -normalize(v_position);
vec3 h = normalize(l+viewDir);
specularIntensity = max(0., pow(max(dot(normal,h), 0.) , u_shininess)) * attenuation;
specularLight += u_light0Color * specularIntensity;
diffuseLight += u_light0Color * diffuseIntensity;
diffuseLight += u_light0Color * max(dot(normal,l), 0.) * attenuation;
}
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;
......
......@@ -5,14 +5,16 @@ 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;
varying vec3 v_light0Direction;
varying vec3 v_position;
uniform mat4 u_light0Transform;
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_normal = u_normalMatrix * a_normal;
v_texcoord0 = a_texcoord0;
v_position = pos.xyz;
v_light0Direction = mat3(u_light0Transform) * vec3(0.,0.,1.);
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_emission;
uniform vec4 u_specular;
uniform float u_shininess;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec4 emission;
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = texture2D(u_diffuse, v_texcoord0);
emission = u_emission;
specular = u_specular;
diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.);
color.xyz += diffuse.xyz;
color.xyz += emission.xyz;
color = vec4(color.rgb * diffuse.a, diffuse.a);
gl_FragColor = color;
}
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册