365 lines
11 KiB
JavaScript
365 lines
11 KiB
JavaScript
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;
|
||
|
||
} |