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

365 lines
11 KiB
JavaScript
Raw Normal View History

2024-05-24 12:19:45 +08:00
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;
}