emsApplication/applications/WebConfigure/web/js/threed.js

365 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

function Threed(div, modelFile, background, buttons) {
this.dom = div;
this.exitFlag = false;
if (buttons) {
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = function () {
this.camera.position.copy(this.originPosition);
this.camera.updateProjectionMatrix();
buttons[0].classList.remove('mdc-3d-button-active');
buttons[1].classList.remove('mdc-3d-button-active');
buttons[2].classList.remove('mdc-3d-button-active');
buttons[i].classList.add('mdc-3d-button-active');
for (var action of this.actions) {
action.stop();
}
this.controls.autoRotate = i === 1;
if (i === 2) {
for (const action of this.actions) {
action.play();
}
}
}
}
}
if (this.isWebGL2Available()) {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
} else if (this.isWebGLAvailable()) {
this.renderer = new THREE.WebGL1Renderer({
antialias: true,
alpha: true
});
} else {
throw new Error('该浏览器不支持WEBGL3D渲染请尝试使用最新版本的Chrome或Edge浏览器。');
}
// renderer.setClearColor(0xFFFFFF, 0.0);
this.dom.appendChild(this.renderer.domElement);
this.renderer.domElement.style.width = '100%';
this.renderer.domElement.style.height = '100%';
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
this.camera.position.set(1500, 700, 500);
this.actions = [];
this.mixer = new THREE.AnimationMixer();
this.clock = new THREE.Clock();
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.target.set(0, 5, 0);
this.controls.enablePan = false;
this.controls.enableDamping = false;
this.controls.minPolarAngle = 0;
this.controls.maxPolarAngle = Math.PI * 0.5;
this.controls.autoRotate = false;
this.controls.update();
this.scene = new THREE.Scene();
if (background) {
this.scene.background = new THREE.TextureLoader().load(background);
}
const pmremGenerator = new THREE.PMREMGenerator(this.renderer);
const texture = pmremGenerator.fromScene(this.RoomEnvironment()).texture;
this.scene.environment = texture;
pmremGenerator.dispose();
const light = new THREE.AmbientLight(0xFFFFFF, 0.2); // soft white light
this.scene.add(light);
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 0.5;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
this.scene.add(light);
} {
const loader = new THREE.FBXLoader();
loader.load(modelFile || './img/3d/molds/mdc.fbx', function (root) {
root.position.set(0, 0, 0);
root.updateMatrixWorld();
const box = new THREE.Box3().setFromObject(root);
const boxSize = box.getSize(new THREE.Vector3()).length();
const boxCenter = box.getCenter(new THREE.Vector3());
// root.position.y = -boxCenter.y; // box.min.y;
// root.position.x = -boxCenter.x;
// root.position.z = -boxCenter.z;
root.updateMatrixWorld();
root.traverse(function (e) {
if (e instanceof THREE.Light) {
e.intensity = 0.5;
}
});
this.scene.add(root);
// set the camera to frame the box
this.frameArea(boxSize * 0.7, boxSize, boxCenter);
// update the Trackball controls to handle the new size
this.controls.maxDistance = boxSize * 10;
this.controls.target.copy(boxCenter);
this.controls.update();
this.rootObject = root;
// const box2 = new THREE.BoxHelper(root, 0xffffff);
// this.scene.add(box2);
if (root.animations && root.animations.length > 0) {
for (var animation of root.animations) {
const action = this.mixer.clipAction(animation, root);
action.loop = THREE.LoopRepeat;
this.actions.push(action);
}
}
});
}
requestAnimationFrame(this.render.bind(this));
return this;
}
Threed.prototype.dispose = function () {
this.exitFlag = true;
if (this.renderer) {
this.scene.traverse(function (e) {
if (e instanceof THREE.Mesh) {
if (e.geometry) e.geometry.dispose();
if (e.material instanceof Array) {
for (const material of e.material) {
material.dispose();
}
} else if (e.material) e.material.dispose();
}
});
this.renderer.dispose();
this.renderer = null;
}
};
Threed.prototype.getViewSize = function () {
var SCREEN_WIDTH = window.innerWidth - this.dom.offsetLeft;
var SCREEN_HEIGHT = window.innerHeight - this.dom.offsetTop - 17;
return {
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT
};
};
Threed.prototype.render = function () {
if (this.exitFlag) return;
this.controls.update();
var delta = this.clock.getDelta();
this.mixer.update(delta);
if (this.resizeRendererToDisplaySize()) {
const canvas = this.renderer.domElement;
this.camera.aspect = canvas.clientWidth / canvas.clientHeight;
this.camera.updateProjectionMatrix();
}
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.render.bind(this));
};
Threed.prototype.isWebGLAvailable = function () {
try {
var canvas = document.createElement('canvas');
return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
} catch (e) {
return false;
}
};
Threed.prototype.isWebGL2Available = function () {
try {
var canvas = document.createElement('canvas');
return !!(window.WebGL2RenderingContext && canvas.getContext('webgl2'));
} catch (e) {
return false;
}
};
Threed.prototype.resizeRendererToDisplaySize = function () {
const canvas = this.renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
const size = this.getViewSize();
this.camera.aspect = size.width / size.height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(width, height, false);
}
return needResize;
};
Threed.prototype.frameArea = function (sizeToFitOnScreen, boxSize, boxCenter) {
const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
const halfFovY = THREE.MathUtils.degToRad(this.camera.fov * .5);
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
// compute a unit vector that points in the direction the camera is now
// in the xz plane from the center of the box
const direction = (new THREE.Vector3())
.subVectors(this.camera.position, boxCenter)
.multiply(new THREE.Vector3(1, 0, 1))
.normalize();
// move the camera to a position distance units way from the center
// in whatever direction the camera was from the center already
this.camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
// pick some near and far values for the frustum that
// will contain the box.
this.camera.near = boxSize / 100;
this.camera.far = boxSize * 100;
this.camera.position.setY(700);
this.originPosition = this.camera.position.clone();
this.camera.updateProjectionMatrix();
// point the camera to look at the center of the box
this.camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
};
Threed.prototype.RoomEnvironment = function () {
const scene = new THREE.Scene();
const geometry = new THREE.BoxBufferGeometry();
geometry.deleteAttribute('uv');
const roomMaterial = new THREE.MeshStandardMaterial({
side: THREE.BackSide
});
const boxMaterial = new THREE.MeshStandardMaterial();
const mainLight = new THREE.PointLight(0xffffff, 5.0, 28, 2);
mainLight.position.set(0.418, 16.199, 0.300);
scene.add(mainLight);
const room = new THREE.Mesh(geometry, roomMaterial);
room.position.set(-0.757, 13.219, 0.717);
room.scale.set(31.713, 28.305, 28.591);
scene.add(room);
const box1 = new THREE.Mesh(geometry, boxMaterial);
box1.position.set(-10.906, 2.009, 1.846);
box1.rotation.set(0, -0.195, 0);
box1.scale.set(2.328, 7.905, 4.651);
scene.add(box1);
const box2 = new THREE.Mesh(geometry, boxMaterial);
box2.position.set(-5.607, -0.754, -0.758);
box2.rotation.set(0, 0.994, 0);
box2.scale.set(1.970, 1.534, 3.955);
scene.add(box2);
const box3 = new THREE.Mesh(geometry, boxMaterial);
box3.position.set(6.167, 0.857, 7.803);
box3.rotation.set(0, 0.561, 0);
box3.scale.set(3.927, 6.285, 3.687);
scene.add(box3);
const box4 = new THREE.Mesh(geometry, boxMaterial);
box4.position.set(-2.017, 0.018, 6.124);
box4.rotation.set(0, 0.333, 0);
box4.scale.set(2.002, 4.566, 2.064);
scene.add(box4);
const box5 = new THREE.Mesh(geometry, boxMaterial);
box5.position.set(2.291, -0.756, -2.621);
box5.rotation.set(0, -0.286, 0);
box5.scale.set(1.546, 1.552, 1.496);
scene.add(box5);
const box6 = new THREE.Mesh(geometry, boxMaterial);
box6.position.set(-2.193, -0.369, -5.547);
box6.rotation.set(0, 0.516, 0);
box6.scale.set(3.875, 3.487, 2.986);
scene.add(box6);
// -x right
const light1 = new THREE.Mesh(geometry, createAreaLightMaterial(50));
light1.position.set(-16.116, 14.37, 8.208);
light1.scale.set(0.1, 2.428, 2.739);
scene.add(light1);
// -x left
const light2 = new THREE.Mesh(geometry, createAreaLightMaterial(50));
light2.position.set(-16.109, 18.021, -8.207);
light2.scale.set(0.1, 2.425, 2.751);
scene.add(light2);
// +x
const light3 = new THREE.Mesh(geometry, createAreaLightMaterial(17));
light3.position.set(14.904, 12.198, -1.832);
light3.scale.set(0.15, 4.265, 6.331);
scene.add(light3);
// +z
const light4 = new THREE.Mesh(geometry, createAreaLightMaterial(43));
light4.position.set(-0.462, 8.89, 14.520);
light4.scale.set(4.38, 5.441, 0.088);
scene.add(light4);
// -z
const light5 = new THREE.Mesh(geometry, createAreaLightMaterial(20));
light5.position.set(3.235, 11.486, -12.541);
light5.scale.set(2.5, 2.0, 0.1);
scene.add(light5);
// +y
const light6 = new THREE.Mesh(geometry, createAreaLightMaterial(100));
light6.position.set(0.0, 20.0, 0.0);
light6.scale.set(1.0, 0.1, 1.0);
scene.add(light6);
function createAreaLightMaterial(intensity) {
const material = new THREE.MeshBasicMaterial();
material.color.setScalar(intensity);
return material;
}
return scene;
}