mirror of
https://github.com/tengge1/ShadowEditor.git
synced 2026-01-25 15:08:11 +00:00
1132 lines
23 KiB
JavaScript
1132 lines
23 KiB
JavaScript
/**
|
|
* @author alteredq / http://alteredqualia.com/
|
|
*/
|
|
|
|
THREE.SceneLoader = function (manager) {
|
|
|
|
this.onLoadStart = function () { };
|
|
this.onLoadProgress = function () { };
|
|
this.onLoadComplete = function () { };
|
|
|
|
this.callbackSync = function () { };
|
|
this.callbackProgress = function () { };
|
|
|
|
this.geometryHandlers = {};
|
|
this.hierarchyHandlers = {};
|
|
|
|
this.addGeometryHandler("ascii", THREE.JSONLoader);
|
|
|
|
this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager;
|
|
|
|
};
|
|
|
|
THREE.SceneLoader.prototype = {
|
|
|
|
constructor: THREE.SceneLoader,
|
|
|
|
load: function (url, onLoad, onProgress, onError) {
|
|
|
|
var scope = this;
|
|
|
|
var loader = new THREE.FileLoader(scope.manager);
|
|
loader.load(url, function (text) {
|
|
|
|
scope.parse(JSON.parse(text), onLoad, url);
|
|
|
|
}, onProgress, onError);
|
|
|
|
},
|
|
|
|
addGeometryHandler: function (typeID, loaderClass) {
|
|
|
|
this.geometryHandlers[typeID] = { "loaderClass": loaderClass };
|
|
|
|
},
|
|
|
|
addHierarchyHandler: function (typeID, loaderClass) {
|
|
|
|
this.hierarchyHandlers[typeID] = { "loaderClass": loaderClass };
|
|
|
|
},
|
|
|
|
parse: function (json, callbackFinished, url) {
|
|
|
|
var scope = this;
|
|
|
|
var urlBase = THREE.Loader.prototype.extractUrlBase(url);
|
|
|
|
var geometry, material, camera, fog,
|
|
texture, images, color,
|
|
light, hex, intensity,
|
|
counter_models, counter_textures,
|
|
total_models, total_textures,
|
|
result;
|
|
|
|
var target_array = [];
|
|
|
|
var data = json;
|
|
|
|
// async geometry loaders
|
|
|
|
for (var typeID in this.geometryHandlers) {
|
|
|
|
var loaderClass = this.geometryHandlers[typeID]["loaderClass"];
|
|
this.geometryHandlers[typeID]["loaderObject"] = new loaderClass();
|
|
|
|
}
|
|
|
|
// async hierachy loaders
|
|
|
|
for (var typeID in this.hierarchyHandlers) {
|
|
|
|
var loaderClass = this.hierarchyHandlers[typeID]["loaderClass"];
|
|
this.hierarchyHandlers[typeID]["loaderObject"] = new loaderClass();
|
|
|
|
}
|
|
|
|
counter_models = 0;
|
|
counter_textures = 0;
|
|
|
|
result = {
|
|
|
|
scene: new THREE.Scene(),
|
|
geometries: {},
|
|
face_materials: {},
|
|
materials: {},
|
|
textures: {},
|
|
objects: {},
|
|
cameras: {},
|
|
lights: {},
|
|
fogs: {},
|
|
empties: {},
|
|
groups: {}
|
|
|
|
};
|
|
|
|
if (data.transform) {
|
|
|
|
var position = data.transform.position,
|
|
rotation = data.transform.rotation,
|
|
scale = data.transform.scale;
|
|
|
|
if (position) {
|
|
|
|
result.scene.position.fromArray(position);
|
|
|
|
}
|
|
|
|
if (rotation) {
|
|
|
|
result.scene.rotation.fromArray(rotation);
|
|
|
|
}
|
|
|
|
if (scale) {
|
|
|
|
result.scene.scale.fromArray(scale);
|
|
|
|
}
|
|
|
|
if (position || rotation || scale) {
|
|
|
|
result.scene.updateMatrix();
|
|
result.scene.updateMatrixWorld();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function get_url(source_url, url_type) {
|
|
|
|
if (url_type == "relativeToHTML") {
|
|
|
|
return source_url;
|
|
|
|
} else {
|
|
|
|
return urlBase + source_url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// toplevel loader function, delegates to handle_children
|
|
|
|
function handle_objects() {
|
|
|
|
handle_children(result.scene, data.objects);
|
|
|
|
}
|
|
|
|
// handle all the children from the loaded json and attach them to given parent
|
|
|
|
function handle_children(parent, children) {
|
|
|
|
var mat, dst, pos, rot, scl, quat;
|
|
|
|
for (var objID in children) {
|
|
|
|
// check by id if child has already been handled,
|
|
// if not, create new object
|
|
|
|
var object = result.objects[objID];
|
|
var objJSON = children[objID];
|
|
|
|
if (object === undefined) {
|
|
|
|
// meshes
|
|
|
|
if (objJSON.type && (objJSON.type in scope.hierarchyHandlers)) {
|
|
|
|
if (objJSON.loading === undefined) {
|
|
|
|
material = result.materials[objJSON.material];
|
|
|
|
objJSON.loading = true;
|
|
|
|
var loader = scope.hierarchyHandlers[objJSON.type]["loaderObject"];
|
|
|
|
// ColladaLoader
|
|
|
|
if (loader.options) {
|
|
|
|
loader.load(get_url(objJSON.url, data.urlBaseType), create_callback_hierachy(objID, parent, material, objJSON));
|
|
|
|
// UTF8Loader
|
|
// OBJLoader
|
|
|
|
} else {
|
|
|
|
loader.load(get_url(objJSON.url, data.urlBaseType), create_callback_hierachy(objID, parent, material, objJSON));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (objJSON.geometry !== undefined) {
|
|
|
|
geometry = result.geometries[objJSON.geometry];
|
|
|
|
// geometry already loaded
|
|
|
|
if (geometry) {
|
|
|
|
material = result.materials[objJSON.material];
|
|
|
|
pos = objJSON.position;
|
|
rot = objJSON.rotation;
|
|
scl = objJSON.scale;
|
|
mat = objJSON.matrix;
|
|
quat = objJSON.quaternion;
|
|
|
|
// use materials from the model file
|
|
// if there is no material specified in the object
|
|
|
|
if (!objJSON.material) {
|
|
|
|
material = new THREE.MultiMaterial(result.face_materials[objJSON.geometry]);
|
|
|
|
}
|
|
|
|
// use materials from the model file
|
|
// if there is just empty face material
|
|
// (must create new material as each model has its own face material)
|
|
|
|
if ((material instanceof THREE.MultiMaterial) && material.materials.length === 0) {
|
|
|
|
material = new THREE.MultiMaterial(result.face_materials[objJSON.geometry]);
|
|
|
|
}
|
|
|
|
if (objJSON.skin) {
|
|
|
|
object = new THREE.SkinnedMesh(geometry, material);
|
|
|
|
} else if (objJSON.morph) {
|
|
|
|
object = new THREE.MorphAnimMesh(geometry, material);
|
|
|
|
if (objJSON.duration !== undefined) {
|
|
|
|
object.duration = objJSON.duration;
|
|
|
|
}
|
|
|
|
if (objJSON.time !== undefined) {
|
|
|
|
object.time = objJSON.time;
|
|
|
|
}
|
|
|
|
if (objJSON.mirroredLoop !== undefined) {
|
|
|
|
object.mirroredLoop = objJSON.mirroredLoop;
|
|
|
|
}
|
|
|
|
if (material.morphNormals) {
|
|
|
|
geometry.computeMorphNormals();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
object = new THREE.Mesh(geometry, material);
|
|
|
|
}
|
|
|
|
object.name = objID;
|
|
|
|
if (mat) {
|
|
|
|
object.matrixAutoUpdate = false;
|
|
object.matrix.set(
|
|
mat[0], mat[1], mat[2], mat[3],
|
|
mat[4], mat[5], mat[6], mat[7],
|
|
mat[8], mat[9], mat[10], mat[11],
|
|
mat[12], mat[13], mat[14], mat[15]
|
|
);
|
|
|
|
} else {
|
|
|
|
object.position.fromArray(pos);
|
|
|
|
if (quat) {
|
|
|
|
object.quaternion.fromArray(quat);
|
|
|
|
} else {
|
|
|
|
object.rotation.fromArray(rot);
|
|
|
|
}
|
|
|
|
object.scale.fromArray(scl);
|
|
|
|
}
|
|
|
|
object.visible = objJSON.visible;
|
|
object.castShadow = objJSON.castShadow;
|
|
object.receiveShadow = objJSON.receiveShadow;
|
|
|
|
parent.add(object);
|
|
|
|
result.objects[objID] = object;
|
|
|
|
}
|
|
|
|
// lights
|
|
|
|
} else if (objJSON.type === "AmbientLight" || objJSON.type === "PointLight" ||
|
|
objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" ||
|
|
objJSON.type === "HemisphereLight") {
|
|
|
|
var color = objJSON.color;
|
|
var intensity = objJSON.intensity;
|
|
var distance = objJSON.distance;
|
|
var position = objJSON.position;
|
|
var rotation = objJSON.rotation;
|
|
|
|
switch (objJSON.type) {
|
|
|
|
case 'AmbientLight':
|
|
light = new THREE.AmbientLight(color);
|
|
break;
|
|
|
|
case 'PointLight':
|
|
light = new THREE.PointLight(color, intensity, distance);
|
|
light.position.fromArray(position);
|
|
break;
|
|
|
|
case 'DirectionalLight':
|
|
light = new THREE.DirectionalLight(color, intensity);
|
|
light.position.fromArray(objJSON.direction);
|
|
break;
|
|
|
|
case 'SpotLight':
|
|
light = new THREE.SpotLight(color, intensity, distance);
|
|
light.angle = objJSON.angle;
|
|
light.position.fromArray(position);
|
|
light.target.set(position[0], position[1] - distance, position[2]);
|
|
light.target.applyEuler(new THREE.Euler(rotation[0], rotation[1], rotation[2], 'XYZ'));
|
|
break;
|
|
|
|
case 'HemisphereLight':
|
|
light = new THREE.DirectionalLight(color, intensity, distance);
|
|
light.target.set(position[0], position[1] - distance, position[2]);
|
|
light.target.applyEuler(new THREE.Euler(rotation[0], rotation[1], rotation[2], 'XYZ'));
|
|
break;
|
|
|
|
}
|
|
|
|
parent.add(light);
|
|
|
|
light.name = objID;
|
|
result.lights[objID] = light;
|
|
result.objects[objID] = light;
|
|
|
|
// cameras
|
|
|
|
} else if (objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera") {
|
|
|
|
pos = objJSON.position;
|
|
rot = objJSON.rotation;
|
|
quat = objJSON.quaternion;
|
|
|
|
if (objJSON.type === "PerspectiveCamera") {
|
|
|
|
camera = new THREE.PerspectiveCamera(objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far);
|
|
|
|
} else if (objJSON.type === "OrthographicCamera") {
|
|
|
|
camera = new THREE.OrthographicCamera(objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far);
|
|
|
|
}
|
|
|
|
camera.name = objID;
|
|
camera.position.fromArray(pos);
|
|
|
|
if (quat !== undefined) {
|
|
|
|
camera.quaternion.fromArray(quat);
|
|
|
|
} else if (rot !== undefined) {
|
|
|
|
camera.rotation.fromArray(rot);
|
|
|
|
} else if (objJSON.target) {
|
|
|
|
camera.lookAt(new THREE.Vector3().fromArray(objJSON.target));
|
|
|
|
}
|
|
|
|
parent.add(camera);
|
|
|
|
result.cameras[objID] = camera;
|
|
result.objects[objID] = camera;
|
|
|
|
// pure Object3D
|
|
|
|
} else {
|
|
|
|
pos = objJSON.position;
|
|
rot = objJSON.rotation;
|
|
scl = objJSON.scale;
|
|
quat = objJSON.quaternion;
|
|
|
|
object = new THREE.Object3D();
|
|
object.name = objID;
|
|
object.position.fromArray(pos);
|
|
|
|
if (quat) {
|
|
|
|
object.quaternion.fromArray(quat);
|
|
|
|
} else {
|
|
|
|
object.rotation.fromArray(rot);
|
|
|
|
}
|
|
|
|
object.scale.fromArray(scl);
|
|
object.visible = (objJSON.visible !== undefined) ? objJSON.visible : false;
|
|
|
|
parent.add(object);
|
|
|
|
result.objects[objID] = object;
|
|
result.empties[objID] = object;
|
|
|
|
}
|
|
|
|
if (object) {
|
|
|
|
if (objJSON.userData !== undefined) {
|
|
|
|
for (var key in objJSON.userData) {
|
|
|
|
var value = objJSON.userData[key];
|
|
object.userData[key] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (objJSON.groups !== undefined) {
|
|
|
|
for (var i = 0; i < objJSON.groups.length; i++) {
|
|
|
|
var groupID = objJSON.groups[i];
|
|
|
|
if (result.groups[groupID] === undefined) {
|
|
|
|
result.groups[groupID] = [];
|
|
|
|
}
|
|
|
|
result.groups[groupID].push(objID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (object !== undefined && objJSON.children !== undefined) {
|
|
|
|
handle_children(object, objJSON.children);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function handle_mesh(geo, mat, id) {
|
|
|
|
result.geometries[id] = geo;
|
|
result.face_materials[id] = mat;
|
|
handle_objects();
|
|
|
|
}
|
|
|
|
function handle_hierarchy(node, id, parent, material, obj) {
|
|
|
|
var p = obj.position;
|
|
var r = obj.rotation;
|
|
var q = obj.quaternion;
|
|
var s = obj.scale;
|
|
|
|
node.position.fromArray(p);
|
|
|
|
if (q) {
|
|
|
|
node.quaternion.fromArray(q);
|
|
|
|
} else {
|
|
|
|
node.rotation.fromArray(r);
|
|
|
|
}
|
|
|
|
node.scale.fromArray(s);
|
|
|
|
// override children materials
|
|
// if object material was specified in JSON explicitly
|
|
|
|
if (material) {
|
|
|
|
node.traverse(function (child) {
|
|
|
|
child.material = material;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// override children visibility
|
|
// with root node visibility as specified in JSON
|
|
|
|
var visible = (obj.visible !== undefined) ? obj.visible : true;
|
|
|
|
node.traverse(function (child) {
|
|
|
|
child.visible = visible;
|
|
|
|
});
|
|
|
|
parent.add(node);
|
|
|
|
node.name = id;
|
|
|
|
result.objects[id] = node;
|
|
handle_objects();
|
|
|
|
}
|
|
|
|
function create_callback_geometry(id) {
|
|
|
|
return function (geo, mat) {
|
|
|
|
geo.name = id;
|
|
|
|
handle_mesh(geo, mat, id);
|
|
|
|
counter_models -= 1;
|
|
|
|
scope.onLoadComplete();
|
|
|
|
async_callback_gate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function create_callback_hierachy(id, parent, material, obj) {
|
|
|
|
return function (event) {
|
|
|
|
var result;
|
|
|
|
// loaders which use EventDispatcher
|
|
|
|
if (event.content) {
|
|
|
|
result = event.content;
|
|
|
|
// ColladaLoader
|
|
|
|
} else if (event.dae) {
|
|
|
|
result = event.scene;
|
|
|
|
|
|
// UTF8Loader
|
|
|
|
} else {
|
|
|
|
result = event;
|
|
|
|
}
|
|
|
|
handle_hierarchy(result, id, parent, material, obj);
|
|
|
|
counter_models -= 1;
|
|
|
|
scope.onLoadComplete();
|
|
|
|
async_callback_gate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function create_callback_embed(id) {
|
|
|
|
return function (geo, mat) {
|
|
|
|
geo.name = id;
|
|
|
|
result.geometries[id] = geo;
|
|
result.face_materials[id] = mat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function async_callback_gate() {
|
|
|
|
var progress = {
|
|
|
|
totalModels: total_models,
|
|
totalTextures: total_textures,
|
|
loadedModels: total_models - counter_models,
|
|
loadedTextures: total_textures - counter_textures
|
|
|
|
};
|
|
|
|
scope.callbackProgress(progress, result);
|
|
|
|
scope.onLoadProgress();
|
|
|
|
if (counter_models === 0 && counter_textures === 0) {
|
|
|
|
finalize();
|
|
callbackFinished(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function finalize() {
|
|
|
|
// take care of targets which could be asynchronously loaded objects
|
|
|
|
for (var i = 0; i < target_array.length; i++) {
|
|
|
|
var ta = target_array[i];
|
|
|
|
var target = result.objects[ta.targetName];
|
|
|
|
if (target) {
|
|
|
|
ta.object.target = target;
|
|
|
|
} else {
|
|
|
|
// if there was error and target of specified name doesn't exist in the scene file
|
|
// create instead dummy target
|
|
// (target must be added to scene explicitly as parent is already added)
|
|
|
|
ta.object.target = new THREE.Object3D();
|
|
result.scene.add(ta.object.target);
|
|
|
|
}
|
|
|
|
ta.object.target.userData.targetInverse = ta.object;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var callbackTexture = function (count) {
|
|
|
|
counter_textures -= count;
|
|
async_callback_gate();
|
|
|
|
scope.onLoadComplete();
|
|
|
|
};
|
|
|
|
// must use this instead of just directly calling callbackTexture
|
|
// because of closure in the calling context loop
|
|
|
|
var generateTextureCallback = function (count) {
|
|
|
|
return function () {
|
|
|
|
callbackTexture(count);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
function traverse_json_hierarchy(objJSON, callback) {
|
|
|
|
callback(objJSON);
|
|
|
|
if (objJSON.children !== undefined) {
|
|
|
|
for (var objChildID in objJSON.children) {
|
|
|
|
traverse_json_hierarchy(objJSON.children[objChildID], callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// first go synchronous elements
|
|
|
|
// fogs
|
|
|
|
var fogID, fogJSON;
|
|
|
|
for (fogID in data.fogs) {
|
|
|
|
fogJSON = data.fogs[fogID];
|
|
|
|
if (fogJSON.type === "linear") {
|
|
|
|
fog = new THREE.Fog(0x000000, fogJSON.near, fogJSON.far);
|
|
|
|
} else if (fogJSON.type === "exp2") {
|
|
|
|
fog = new THREE.FogExp2(0x000000, fogJSON.density);
|
|
|
|
}
|
|
|
|
color = fogJSON.color;
|
|
fog.color.setRGB(color[0], color[1], color[2]);
|
|
|
|
result.fogs[fogID] = fog;
|
|
|
|
}
|
|
|
|
// now come potentially asynchronous elements
|
|
|
|
// geometries
|
|
|
|
// count how many geometries will be loaded asynchronously
|
|
|
|
var geoID, geoJSON;
|
|
|
|
for (geoID in data.geometries) {
|
|
|
|
geoJSON = data.geometries[geoID];
|
|
|
|
if (geoJSON.type in this.geometryHandlers) {
|
|
|
|
counter_models += 1;
|
|
|
|
scope.onLoadStart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// count how many hierarchies will be loaded asynchronously
|
|
|
|
for (var objID in data.objects) {
|
|
|
|
traverse_json_hierarchy(data.objects[objID], function (objJSON) {
|
|
|
|
if (objJSON.type && (objJSON.type in scope.hierarchyHandlers)) {
|
|
|
|
counter_models += 1;
|
|
|
|
scope.onLoadStart();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
total_models = counter_models;
|
|
|
|
for (geoID in data.geometries) {
|
|
|
|
geoJSON = data.geometries[geoID];
|
|
|
|
if (geoJSON.type === "cube") {
|
|
|
|
geometry = new THREE.BoxGeometry(geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments);
|
|
geometry.name = geoID;
|
|
result.geometries[geoID] = geometry;
|
|
|
|
} else if (geoJSON.type === "plane") {
|
|
|
|
geometry = new THREE.PlaneGeometry(geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments);
|
|
geometry.name = geoID;
|
|
result.geometries[geoID] = geometry;
|
|
|
|
} else if (geoJSON.type === "sphere") {
|
|
|
|
geometry = new THREE.SphereGeometry(geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments);
|
|
geometry.name = geoID;
|
|
result.geometries[geoID] = geometry;
|
|
|
|
} else if (geoJSON.type === "cylinder") {
|
|
|
|
geometry = new THREE.CylinderGeometry(geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs);
|
|
geometry.name = geoID;
|
|
result.geometries[geoID] = geometry;
|
|
|
|
} else if (geoJSON.type === "torus") {
|
|
|
|
geometry = new THREE.TorusGeometry(geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT);
|
|
geometry.name = geoID;
|
|
result.geometries[geoID] = geometry;
|
|
|
|
} else if (geoJSON.type === "icosahedron") {
|
|
|
|
geometry = new THREE.IcosahedronGeometry(geoJSON.radius, geoJSON.subdivisions);
|
|
geometry.name = geoID;
|
|
result.geometries[geoID] = geometry;
|
|
|
|
} else if (geoJSON.type in this.geometryHandlers) {
|
|
|
|
var loader = this.geometryHandlers[geoJSON.type]["loaderObject"];
|
|
loader.load(get_url(geoJSON.url, data.urlBaseType), create_callback_geometry(geoID));
|
|
|
|
} else if (geoJSON.type === "embedded") {
|
|
|
|
var modelJson = data.embeds[geoJSON.id],
|
|
texture_path = "";
|
|
|
|
// pass metadata along to jsonLoader so it knows the format version
|
|
|
|
modelJson.metadata = data.metadata;
|
|
|
|
if (modelJson) {
|
|
|
|
var jsonLoader = this.geometryHandlers["ascii"]["loaderObject"];
|
|
var model = jsonLoader.parse(modelJson, texture_path);
|
|
create_callback_embed(geoID)(model.geometry, model.materials);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// textures
|
|
|
|
// count how many textures will be loaded asynchronously
|
|
|
|
var textureID, textureJSON;
|
|
|
|
for (textureID in data.textures) {
|
|
|
|
textureJSON = data.textures[textureID];
|
|
|
|
if (Array.isArray(textureJSON.url)) {
|
|
|
|
counter_textures += textureJSON.url.length;
|
|
|
|
for (var n = 0; n < textureJSON.url.length; n++) {
|
|
|
|
scope.onLoadStart();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
counter_textures += 1;
|
|
|
|
scope.onLoadStart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
total_textures = counter_textures;
|
|
|
|
for (textureID in data.textures) {
|
|
|
|
textureJSON = data.textures[textureID];
|
|
|
|
if (textureJSON.mapping !== undefined && THREE[textureJSON.mapping] !== undefined) {
|
|
|
|
textureJSON.mapping = THREE[textureJSON.mapping];
|
|
|
|
}
|
|
|
|
var texture;
|
|
|
|
if (Array.isArray(textureJSON.url)) {
|
|
|
|
var count = textureJSON.url.length;
|
|
var urls = [];
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
|
|
urls[i] = get_url(textureJSON.url[i], data.urlBaseType);
|
|
|
|
}
|
|
|
|
var loader = THREE.Loader.Handlers.get(urls[0]);
|
|
|
|
if (loader !== null) {
|
|
|
|
texture = loader.load(urls, generateTextureCallback(count));
|
|
|
|
if (textureJSON.mapping !== undefined)
|
|
texture.mapping = textureJSON.mapping;
|
|
|
|
} else {
|
|
|
|
texture = new THREE.CubeTextureLoader().load(urls, generateTextureCallback(count));
|
|
texture.mapping = textureJSON.mapping;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var fullUrl = get_url(textureJSON.url, data.urlBaseType);
|
|
var textureCallback = generateTextureCallback(1);
|
|
|
|
var loader = THREE.Loader.Handlers.get(fullUrl);
|
|
|
|
if (loader !== null) {
|
|
|
|
texture = loader.load(fullUrl, textureCallback);
|
|
|
|
} else {
|
|
|
|
texture = new THREE.Texture();
|
|
loader = new THREE.ImageLoader();
|
|
|
|
(function (texture) {
|
|
|
|
loader.load(fullUrl, function (image) {
|
|
|
|
texture.image = image;
|
|
texture.needsUpdate = true;
|
|
|
|
textureCallback();
|
|
|
|
});
|
|
|
|
})(texture)
|
|
|
|
|
|
}
|
|
|
|
if (textureJSON.mapping !== undefined)
|
|
texture.mapping = textureJSON.mapping;
|
|
|
|
if (THREE[textureJSON.minFilter] !== undefined)
|
|
texture.minFilter = THREE[textureJSON.minFilter];
|
|
|
|
if (THREE[textureJSON.magFilter] !== undefined)
|
|
texture.magFilter = THREE[textureJSON.magFilter];
|
|
|
|
if (textureJSON.anisotropy) texture.anisotropy = textureJSON.anisotropy;
|
|
|
|
if (textureJSON.repeat) {
|
|
|
|
texture.repeat.set(textureJSON.repeat[0], textureJSON.repeat[1]);
|
|
|
|
if (textureJSON.repeat[0] !== 1) texture.wrapS = THREE.RepeatWrapping;
|
|
if (textureJSON.repeat[1] !== 1) texture.wrapT = THREE.RepeatWrapping;
|
|
|
|
}
|
|
|
|
if (textureJSON.offset) {
|
|
|
|
texture.offset.set(textureJSON.offset[0], textureJSON.offset[1]);
|
|
|
|
}
|
|
|
|
// handle wrap after repeat so that default repeat can be overriden
|
|
|
|
if (textureJSON.wrap) {
|
|
|
|
var wrapMap = {
|
|
"repeat": THREE.RepeatWrapping,
|
|
"mirror": THREE.MirroredRepeatWrapping
|
|
};
|
|
|
|
if (wrapMap[textureJSON.wrap[0]] !== undefined) texture.wrapS = wrapMap[textureJSON.wrap[0]];
|
|
if (wrapMap[textureJSON.wrap[1]] !== undefined) texture.wrapT = wrapMap[textureJSON.wrap[1]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result.textures[textureID] = texture;
|
|
|
|
}
|
|
|
|
// materials
|
|
|
|
var matID, matJSON;
|
|
var parID;
|
|
|
|
for (matID in data.materials) {
|
|
|
|
matJSON = data.materials[matID];
|
|
|
|
for (parID in matJSON.parameters) {
|
|
|
|
if (parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" || parID === "normalMap" || parID === "alphaMap") {
|
|
|
|
matJSON.parameters[parID] = result.textures[matJSON.parameters[parID]];
|
|
|
|
} else if (parID === "shading") {
|
|
|
|
matJSON.parameters[parID] = (matJSON.parameters[parID] === "flat") ? THREE.FlatShading : THREE.SmoothShading;
|
|
|
|
} else if (parID === "side") {
|
|
|
|
if (matJSON.parameters[parID] == "double") {
|
|
|
|
matJSON.parameters[parID] = THREE.DoubleSide;
|
|
|
|
} else if (matJSON.parameters[parID] == "back") {
|
|
|
|
matJSON.parameters[parID] = THREE.BackSide;
|
|
|
|
} else {
|
|
|
|
matJSON.parameters[parID] = THREE.FrontSide;
|
|
|
|
}
|
|
|
|
} else if (parID === "blending") {
|
|
|
|
matJSON.parameters[parID] = matJSON.parameters[parID] in THREE ? THREE[matJSON.parameters[parID]] : THREE.NormalBlending;
|
|
|
|
} else if (parID === "combine") {
|
|
|
|
matJSON.parameters[parID] = matJSON.parameters[parID] in THREE ? THREE[matJSON.parameters[parID]] : THREE.MultiplyOperation;
|
|
|
|
} else if (parID === "vertexColors") {
|
|
|
|
if (matJSON.parameters[parID] == "face") {
|
|
|
|
matJSON.parameters[parID] = THREE.FaceColors;
|
|
|
|
// default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false
|
|
|
|
} else if (matJSON.parameters[parID]) {
|
|
|
|
matJSON.parameters[parID] = THREE.VertexColors;
|
|
|
|
}
|
|
|
|
} else if (parID === "wrapRGB") {
|
|
|
|
var v3 = matJSON.parameters[parID];
|
|
matJSON.parameters[parID] = new THREE.Vector3(v3[0], v3[1], v3[2]);
|
|
|
|
} else if (parID === "normalScale") {
|
|
|
|
var v2 = matJSON.parameters[parID];
|
|
matJSON.parameters[parID] = new THREE.Vector2(v2[0], v2[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0) {
|
|
|
|
matJSON.parameters.transparent = true;
|
|
|
|
}
|
|
|
|
material = new THREE[matJSON.type](matJSON.parameters);
|
|
material.name = matID;
|
|
|
|
result.materials[matID] = material;
|
|
|
|
}
|
|
|
|
// second pass through all materials to initialize MultiMaterials
|
|
// that could be referring to other materials out of order
|
|
|
|
for (matID in data.materials) {
|
|
|
|
matJSON = data.materials[matID];
|
|
|
|
if (matJSON.parameters.materials) {
|
|
|
|
var materialArray = [];
|
|
|
|
for (var i = 0; i < matJSON.parameters.materials.length; i++) {
|
|
|
|
var label = matJSON.parameters.materials[i];
|
|
materialArray.push(result.materials[label]);
|
|
|
|
}
|
|
|
|
result.materials[matID].materials = materialArray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// objects ( synchronous init of procedural primitives )
|
|
|
|
handle_objects();
|
|
|
|
// defaults
|
|
|
|
if (result.cameras && data.defaults.camera) {
|
|
|
|
result.currentCamera = result.cameras[data.defaults.camera];
|
|
|
|
}
|
|
|
|
if (result.fogs && data.defaults.fog) {
|
|
|
|
result.scene.fog = result.fogs[data.defaults.fog];
|
|
|
|
}
|
|
|
|
// synchronous callback
|
|
|
|
scope.callbackSync(result);
|
|
|
|
// just in case there are no async elements
|
|
|
|
async_callback_gate();
|
|
|
|
}
|
|
|
|
}; |