383 lines
9.6 KiB
JavaScript
383 lines
9.6 KiB
JavaScript
|
import {
|
||
|
Vector2,
|
||
|
Geometry,
|
||
|
Mesh,
|
||
|
BufferGeometry,
|
||
|
LoadingManager,
|
||
|
JSONLoader,
|
||
|
TextureLoader,
|
||
|
MeshBasicMaterial,
|
||
|
MeshPhysicalMaterial,
|
||
|
MeshStandardMaterial,
|
||
|
AmbientLight,
|
||
|
RepeatWrapping,
|
||
|
EquirectangularReflectionMapping
|
||
|
} from "./three_modules";
|
||
|
|
||
|
var loadingtextFrame = document.getElementById("loadingtext-frame");
|
||
|
|
||
|
function outputLog(log) {
|
||
|
loadingtextFrame.innerHTML = log;
|
||
|
}
|
||
|
|
||
|
function finishedLoading() {
|
||
|
loadingtextFrame.classList.add("loadingtextframe-out");
|
||
|
window.setTimeout(function () {
|
||
|
loadingtextFrame.remove();
|
||
|
}, 500);
|
||
|
}
|
||
|
|
||
|
const Lazyloader = (function () {
|
||
|
"use strict";
|
||
|
let stack = [];
|
||
|
let loader = new TextureLoader();
|
||
|
let started = false;
|
||
|
|
||
|
const loadAll = () => {
|
||
|
if (!started && stack.length > 0) {
|
||
|
|
||
|
let obj = stack[0];
|
||
|
stack.splice(0, 1);
|
||
|
|
||
|
loader.load(obj.url, (tex) => {
|
||
|
if (obj.scale !== 1) {
|
||
|
tex.repeat.set(obj.scale, obj.scale);
|
||
|
tex.wrapT = tex.wrapS = RepeatWrapping;
|
||
|
}
|
||
|
obj.material[obj.texture] = tex;
|
||
|
requestAnimationFrame(loadAll);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return {
|
||
|
add: function (url, texture, material, scale) {
|
||
|
stack.push({
|
||
|
url: url,
|
||
|
material: material,
|
||
|
texture: texture,
|
||
|
scale: scale || 1
|
||
|
});
|
||
|
},
|
||
|
start: loadAll
|
||
|
};
|
||
|
|
||
|
})();
|
||
|
|
||
|
class cLoader {
|
||
|
constructor(scene, callback) {
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
this.callback = callback;
|
||
|
|
||
|
this.scene = scene;
|
||
|
|
||
|
this.manager = new LoadingManager();
|
||
|
this.texloader = new TextureLoader(this.manager);
|
||
|
this.jsonloader = new JSONLoader(this.manager);
|
||
|
|
||
|
this.manager.onProgress = function (item) {
|
||
|
outputLog("Loading: " + item.replace("./data/", ""));
|
||
|
};
|
||
|
|
||
|
this.manager.onLoad = function () {
|
||
|
scene.updateMatrixWorld();
|
||
|
finishedLoading();
|
||
|
var ambientLight = new AmbientLight(0xffffff, 1.1);
|
||
|
scene.add(ambientLight);
|
||
|
};
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cLoader.prototype.final = function () {
|
||
|
"use strict";
|
||
|
|
||
|
setTimeout(Lazyloader.start, 500);
|
||
|
|
||
|
this.callback();
|
||
|
};
|
||
|
|
||
|
cLoader.prototype.load = function (jsonpath, callback) {
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
outputLog("Loading Scene Config");
|
||
|
|
||
|
//Load the entire JSON File
|
||
|
this.callback = callback;
|
||
|
|
||
|
fetch(jsonpath)
|
||
|
.then(response => {
|
||
|
return response.json();
|
||
|
})
|
||
|
.then(json => {
|
||
|
this.json = json;
|
||
|
})
|
||
|
.then(() => {
|
||
|
fetch("./data/" + this.json.name + "/" + this.json.name + "_objects.json")
|
||
|
.then(response => {
|
||
|
return response.json();
|
||
|
})
|
||
|
.then(json => {
|
||
|
this.objects = json;
|
||
|
this.createScene();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
|
||
|
};
|
||
|
|
||
|
cLoader.prototype.looper = (function () {
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
let looperCount = 0;
|
||
|
|
||
|
return function (array, callback, finished) {
|
||
|
array.forEach((item, index, array) => {
|
||
|
callback(item, () => {
|
||
|
looperCount++;
|
||
|
if (looperCount === array.length) {
|
||
|
looperCount = 0;
|
||
|
finished();
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
})();
|
||
|
|
||
|
cLoader.prototype.createScene = function () {
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
this.name = this.json.name;
|
||
|
this.scene.name = this.name;
|
||
|
|
||
|
let hdris = {};
|
||
|
let materialArray = [];
|
||
|
let materials = {};
|
||
|
|
||
|
let staticmeshes = [];
|
||
|
|
||
|
let staticMesh = new Geometry();
|
||
|
|
||
|
const mergingMeshes = (item, callback) => {
|
||
|
staticMesh.merge(item.mesh, item.matrix, item.materialIndex);
|
||
|
callback();
|
||
|
};
|
||
|
|
||
|
const buildMaterial = (material, callback) => {
|
||
|
|
||
|
let _material;
|
||
|
|
||
|
//Creating the basic material
|
||
|
switch (material.type) {
|
||
|
case "basic":
|
||
|
_material = new MeshBasicMaterial();
|
||
|
break;
|
||
|
case "physical":
|
||
|
_material = new MeshPhysicalMaterial();
|
||
|
break;
|
||
|
default:
|
||
|
_material = new MeshStandardMaterial();
|
||
|
}
|
||
|
|
||
|
|
||
|
//Go through all properties of the material
|
||
|
//and assign it to the new _material created above
|
||
|
for (var key in material) {
|
||
|
|
||
|
//Filter out Properties that arent values or textures
|
||
|
if (key === "type" || key === "scale") {
|
||
|
//Do nothing, type is set above, scale is set below
|
||
|
} else if (key === "shading") {
|
||
|
_material.flatShading = true;
|
||
|
}
|
||
|
//Filter out envMap property
|
||
|
else if (key === "envMap") {
|
||
|
_material.envMap = hdris[material.envMap];
|
||
|
}
|
||
|
//Filter out the color attribute
|
||
|
else if (key === "color") {
|
||
|
_material.color.setHex(material[key]);
|
||
|
} else if (key === "normalScale") {
|
||
|
_material.normalScale = new Vector2(material[key][0], material[key][1]);
|
||
|
}
|
||
|
//If the property is a texture
|
||
|
else if (isNaN(material[key])) {
|
||
|
_material[key] = this.texloader.load("./data/" + this.name + "/textures/small/" + material[key]);
|
||
|
|
||
|
if (material.scale && key !== "lightMap") {
|
||
|
|
||
|
_material[key].repeat.set(material.scale, material.scale);
|
||
|
_material[key].wrapT = _material[key].wrapS = RepeatWrapping;
|
||
|
Lazyloader.add("./data/" + this.name + "/textures/" + material[key], key, _material, material.scale);
|
||
|
} else {
|
||
|
Lazyloader.add("./data/" + this.name + "/textures/" + material[key], key, _material);
|
||
|
}
|
||
|
}
|
||
|
//If the property is a value
|
||
|
else {
|
||
|
_material[key] = material[key];
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
callback(_material);
|
||
|
|
||
|
};
|
||
|
|
||
|
const buildGeometry = (item, callback) => {
|
||
|
|
||
|
if (!this.json.materials[item.material]) {
|
||
|
console.error("Material for " + item.name.toUpperCase() + " is missing");
|
||
|
}
|
||
|
|
||
|
let geometry = this.jsonloader.parse(this.objects[item.name]).geometry;
|
||
|
geometry.computeBoundingBox();
|
||
|
|
||
|
if (item.type === "static") {
|
||
|
if (item.size) {
|
||
|
geometry.scale(item.size);
|
||
|
}
|
||
|
|
||
|
if (item.rot) {
|
||
|
geometry.rotateX(item.rot[0] * Math.PI / 180);
|
||
|
geometry.rotateY(item.rot[1] * Math.PI / 180);
|
||
|
geometry.rotateZ(item.rot[2] * Math.PI / 180);
|
||
|
}
|
||
|
|
||
|
if (item.pos) {
|
||
|
geometry.translate(item.pos[0], item.pos[1], item.pos[2]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (materials[item.material] === undefined) {
|
||
|
buildMaterial(this.json.materials[item.material], function (material) {
|
||
|
material.name = item.material;
|
||
|
buildMesh(item, geometry, material, callback)
|
||
|
});
|
||
|
} else {
|
||
|
buildMesh(item, geometry, materials[item.material], callback)
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const buildMesh = (item, geometry, material, callback) => {
|
||
|
|
||
|
switch (item.type) {
|
||
|
case "static":
|
||
|
if (!materials[item.material]) {
|
||
|
materialArray.push(material);
|
||
|
materials[item.material] = materialArray.length - 1;
|
||
|
staticmeshes.push({
|
||
|
"name": item.name,
|
||
|
"mesh": geometry,
|
||
|
"materialIndex": materialArray.length - 1
|
||
|
});
|
||
|
} else {
|
||
|
staticmeshes.push({
|
||
|
"name": item.name,
|
||
|
"mesh": geometry,
|
||
|
"materialIndex": materials[item.material]
|
||
|
});
|
||
|
}
|
||
|
break;
|
||
|
case "instanced":
|
||
|
|
||
|
for (let i = 0; i < item.duplicates.length; i++) {
|
||
|
|
||
|
let mesh = new Mesh(geometry, material);
|
||
|
mesh.name = item.name;
|
||
|
if (item.duplicates[i].pos) {
|
||
|
mesh.position.set(item.duplicates[i].pos[0], item.duplicates[i].pos[1], item.duplicates[i].pos[2]);
|
||
|
}
|
||
|
if (item.duplicates[i].size) {
|
||
|
mesh.scale.set(item.duplicates[i].size, item.duplicates[i].size, item.duplicates[i].size);
|
||
|
}
|
||
|
if (item.duplicates[i].rot) {
|
||
|
mesh.rotation.set(item.duplicates[i].rot[0] * Math.PI / 180, item.duplicates[i].rot[1] * Math.PI / 180, item.duplicates[i].rot[2] * Math.PI / 180);
|
||
|
}
|
||
|
|
||
|
this.scene.add(mesh);
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
|
||
|
let mesh = new Mesh(geometry, material);
|
||
|
mesh.name = item.name;
|
||
|
|
||
|
if (item.pos) {
|
||
|
mesh.position.set(item.pos[0], item.pos[1], item.pos[2]);
|
||
|
}
|
||
|
if (item.size) {
|
||
|
mesh.scale.set(item.size, item.size, item.size);
|
||
|
}
|
||
|
if (item.rot) {
|
||
|
mesh.rotation.set(item.rot[0] * Math.PI / 180, item.rot[1] * Math.PI / 180, item.rot[2] * Math.PI / 180);
|
||
|
}
|
||
|
if (item.fpos) {
|
||
|
mesh.userData.fpos = item.fpos;
|
||
|
}
|
||
|
if (item.type === "clickable") {
|
||
|
mesh.userData.clickable = true;
|
||
|
}
|
||
|
if (item.camAngle) {
|
||
|
mesh.userData.camAngle = item.camAngle;
|
||
|
}
|
||
|
if (item.text) {
|
||
|
mesh.userData.text = item.text;
|
||
|
}
|
||
|
|
||
|
this.scene.add(mesh);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
callback();
|
||
|
};
|
||
|
|
||
|
const loadHdri = (item, callback) => {
|
||
|
this.texloader.load(
|
||
|
|
||
|
"./data/" + this.name + "/hdris/" + item.path,
|
||
|
|
||
|
function (texture) {
|
||
|
texture.mapping = EquirectangularReflectionMapping;
|
||
|
hdris[item.name] = texture;
|
||
|
callback();
|
||
|
}
|
||
|
);
|
||
|
};
|
||
|
|
||
|
//Loops through the hdris, loading every single one
|
||
|
//and setting it as a new child of the hdris variable
|
||
|
//when finished runs the load meshes function
|
||
|
this.looper(this.json.hdris, loadHdri, () => {
|
||
|
//Loop through the objects, create a new material if panorama_nature
|
||
|
//exist for the mesh. If the mesh is static put it in the staticmeshes array
|
||
|
//else just add it to the scene
|
||
|
this.looper(this.json.objects, buildGeometry, () => {
|
||
|
//Merge the meshes in the static meshes array
|
||
|
this.looper(staticmeshes, mergingMeshes, () => {
|
||
|
//Convert to Buffergeometry
|
||
|
staticMesh.computeVertexNormals();
|
||
|
let tempGeometry = new BufferGeometry().fromGeometry(staticMesh);
|
||
|
//Create mesh from the geometry
|
||
|
let tempMesh = new Mesh(tempGeometry, materialArray);
|
||
|
tempMesh.name = "staticMesh";
|
||
|
tempMesh.userData.clickable = false;
|
||
|
this.scene.add(tempMesh);
|
||
|
|
||
|
this.final();
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
export default cLoader;
|