849 lines
25 KiB
JavaScript
849 lines
25 KiB
JavaScript
|
/**
|
|||
|
* @Documents
|
|||
|
*
|
|||
|
* 配置3D时选择模型文件后使用 MDCThreeD.readCabinetList 读取模型文件中的柜子列表,返回所有柜子的编号
|
|||
|
* MDCThreeD.readCabinetList('./img/3d/molds/mdc.fbx').then(indexs => {
|
|||
|
* console.log(indexs);
|
|||
|
* });
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 3D页面
|
|||
|
* @param {*} options 初始化选项
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
function MDCThreeD(options) {
|
|||
|
this.options = options;
|
|||
|
this.container = options.container;
|
|||
|
this.touchHandle = this.onTouch.bind(this);
|
|||
|
this.touchendHandle = this.onTouchEnd.bind(this);
|
|||
|
this.touchMoveHandle = this.onTouchMove.bind(this);
|
|||
|
this.mousemoveHandle = this.onMouseMove.bind(this);
|
|||
|
this.mouseleaveHandle = this.onMouseLeave.bind(this);
|
|||
|
this.scope = options.scope;
|
|||
|
this.exitFlag = false;
|
|||
|
if (this.options.buttons) {
|
|||
|
for (var i = 0; i < this.options.buttons.length; i++) {
|
|||
|
var self = this;
|
|||
|
this.options.buttons[i].index = i;
|
|||
|
this.options.buttons[i].onclick = function (arg) {
|
|||
|
var index = arg[0];
|
|||
|
var position = self.originPosition;
|
|||
|
if (index === 0) {
|
|||
|
if (self.camera.position.distanceTo(self.originPosition) < 1) {
|
|||
|
position = self.getAnotherSide(self.originPosition);
|
|||
|
}
|
|||
|
}
|
|||
|
self.camera.position.copy(position);
|
|||
|
self.camera.updateProjectionMatrix();
|
|||
|
for (var i = 0; i < self.options.buttons.length; i++) {
|
|||
|
self.options.buttons[i].classList.remove('mdc-3d-button-active');
|
|||
|
}
|
|||
|
self.options.buttons[index].classList.add('mdc-3d-button-active');
|
|||
|
for (var i = 0; i < self.actions.length; i++) {
|
|||
|
self.actions[i].stop();
|
|||
|
}
|
|||
|
self.controls.autoRotate = index === 1;
|
|||
|
if (index === 2) {
|
|||
|
for (var i = 0; i < self.actions.length; i++) {
|
|||
|
self.actions[i].play();
|
|||
|
}
|
|||
|
}
|
|||
|
}.bind(this, [i])
|
|||
|
}
|
|||
|
}
|
|||
|
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浏览器。');
|
|||
|
}
|
|||
|
|
|||
|
if (typeof this.renderer.domElement.onpointerdown != 'undefined') {
|
|||
|
this.renderer.domElement.addEventListener('pointerdown', this.touchHandle, false);
|
|||
|
} else {
|
|||
|
this.renderer.domElement.addEventListener('mousedown', this.touchHandle, false);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (typeof this.renderer.domElement.onpointerup != 'undefined') {
|
|||
|
this.renderer.domElement.addEventListener('pointerup', this.touchendHandle, false);
|
|||
|
} else {
|
|||
|
this.renderer.domElement.addEventListener('mouseup', this.touchendHandle, false);
|
|||
|
}
|
|||
|
|
|||
|
if (typeof this.renderer.domElement.onpointermove != 'undefined') {
|
|||
|
this.renderer.domElement.addEventListener('pointermove', this.touchMoveHandle, false);
|
|||
|
} else {
|
|||
|
this.renderer.domElement.addEventListener('mousemove', this.touchMoveHandle, false);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// 鼠标停留
|
|||
|
this.renderer.domElement.addEventListener('mousemove', this.mousemoveHandle, false);
|
|||
|
// 鼠标离开
|
|||
|
this.renderer.domElement.addEventListener('mouseleave', this.mouseleaveHandle, false);
|
|||
|
|
|||
|
// this.renderer.domElement.addEventListener('touchstart', this.touchHandle, false);
|
|||
|
// this.renderer.domElement.addEventListener('touchmove', this.touchMoveHandle, false);
|
|||
|
// this.renderer.domElement.addEventListener('touchend', this.touchendHandle, false);
|
|||
|
|
|||
|
|
|||
|
this.container.appendChild(this.renderer.domElement);
|
|||
|
this.renderer.domElement.style.width = '100%';
|
|||
|
this.renderer.domElement.style.height = '100%';
|
|||
|
this.initData();
|
|||
|
this.loadCamera();
|
|||
|
this.loadControls();
|
|||
|
this.loadEnvironment();
|
|||
|
this.loadTemplate();
|
|||
|
requestAnimationFrame(this.render.bind(this));
|
|||
|
return this;
|
|||
|
}
|
|||
|
/**
|
|||
|
* 定义柜子对象的命名规则
|
|||
|
*/
|
|||
|
MDCThreeD.cabinetRegExp = /cabinet[1-9]+[0-9]*/;
|
|||
|
|
|||
|
/*:1
|
|||
|
* 机柜对象表
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.cabinets = {};
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 3D配置选项
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.options = {
|
|||
|
/**
|
|||
|
* 容器DIV对象,初始化传入\
|
|||
|
*/
|
|||
|
container: null,
|
|||
|
/**
|
|||
|
* 静态背景图路径,可选\
|
|||
|
*/
|
|||
|
background: null,
|
|||
|
/**
|
|||
|
* 控制按钮列表\
|
|||
|
* 传入button对象数组
|
|||
|
* [0:静止,1:旋转,2:动画]
|
|||
|
*/
|
|||
|
buttons: [],
|
|||
|
/**
|
|||
|
* 是否使用环境光贴图?\
|
|||
|
* 模拟房间的环境光
|
|||
|
*/
|
|||
|
environmentLight: true,
|
|||
|
|
|||
|
/**
|
|||
|
* 模型文件
|
|||
|
*/
|
|||
|
modelFile: './img/3d/molds/mdc.fbx',
|
|||
|
|
|||
|
/**
|
|||
|
* 机柜点击变色 \
|
|||
|
* #007ACC
|
|||
|
*/
|
|||
|
touchDiscolor: null
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 初始化数据
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.initData = function () {
|
|||
|
this.cabinets = {};
|
|||
|
this.actions = [];
|
|||
|
this.touchObject = null;
|
|||
|
this.mixer = new THREE.AnimationMixer();
|
|||
|
this.clock = new THREE.Clock();
|
|||
|
this.scene = new THREE.Scene();
|
|||
|
this.raycaster = new THREE.Raycaster();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 命中对象事件
|
|||
|
* @param {*} object 命中对象
|
|||
|
* @param {*} cabinetIndex 对象的柜子编号
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.objectTouch = function (object, cabinetIndex) {
|
|||
|
this.scope.cabinetClk(cabinetIndex);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 获取一个坐标围绕中心点的另一面
|
|||
|
* Y轴旋转180度
|
|||
|
* @param {*} position
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.getAnotherSide = function (position) {
|
|||
|
var ps = position.clone().sub(this.controls.target);
|
|||
|
this.transformGroup.rotation.set(0, 0, 0);
|
|||
|
this.transformObject.position.copy(ps);
|
|||
|
this.transformGroup.rotation.y = Math.PI;
|
|||
|
this.transformGroup.updateMatrixWorld(true);
|
|||
|
const pos = new THREE.Vector3();
|
|||
|
pos.setFromMatrixPosition(this.transformObject.matrixWorld)
|
|||
|
return pos.add(this.controls.target);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 鼠标按下事件处理
|
|||
|
* @param {*} event
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.onTouch = function (event) {
|
|||
|
event.preventDefault();
|
|||
|
const position = this.getPlatformMousePosition(event);
|
|||
|
var rect = this.renderer.domElement.getBoundingClientRect();
|
|||
|
position.sub(new THREE.Vector2(rect.x | rect.left, rect.y | rect.top));
|
|||
|
var x = (position.x / rect.width) * 2 - 1;
|
|||
|
var y = -(position.y / rect.height) * 2 + 1;
|
|||
|
this.coord = new THREE.Vector2(x, y);
|
|||
|
this.raycaster.setFromCamera(this.coord, this.camera);
|
|||
|
var hitobjects = this.raycaster.intersectObjects(this.scene.children, true);
|
|||
|
if (hitobjects.length > 0) {
|
|||
|
const object = hitobjects[0].object;
|
|||
|
if (this.isCabinet(object)) {
|
|||
|
this.touchPosition = position;
|
|||
|
this.touchObject = object;
|
|||
|
this.discolor(this.touchObject, true);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 鼠标停留
|
|||
|
* @Author: Eddy
|
|||
|
* @Date: 2021-06-05 16:59:25
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.onMouseMove = function (event) {
|
|||
|
event.preventDefault();
|
|||
|
const position = this.getPlatformMousePosition(event);
|
|||
|
var rect = this.renderer.domElement.getBoundingClientRect();
|
|||
|
position.sub(new THREE.Vector2(rect.x | rect.left, rect.y | rect.top));
|
|||
|
var x = (position.x / rect.width) * 2 - 1;
|
|||
|
var y = -(position.y / rect.height) * 2 + 1;
|
|||
|
this.coord = new THREE.Vector2(x, y);
|
|||
|
this.raycaster.setFromCamera(this.coord, this.camera);
|
|||
|
var hitobjects = this.raycaster.intersectObjects(this.scene.children, true);
|
|||
|
var currentObject = null;
|
|||
|
if (hitobjects.length > 0) {
|
|||
|
const object = hitobjects[0].object;
|
|||
|
if (this.isCabinet(object)) {
|
|||
|
currentObject = object;
|
|||
|
}
|
|||
|
}
|
|||
|
if (this.nouseObject != currentObject) {
|
|||
|
if (this.nouseObject != null) {
|
|||
|
this.discolor(this.nouseObject, false);
|
|||
|
this.nouseObject = null;
|
|||
|
}
|
|||
|
this.nouseObject = currentObject;
|
|||
|
if (this.nouseObject != null) {
|
|||
|
this.discolor(this.nouseObject, true);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 鼠标离开画布
|
|||
|
* @Author: Eddy
|
|||
|
* @Date: 2021-06-05 17:02:45
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.onMouseLeave = function (event) {
|
|||
|
if (this.nouseObject) {
|
|||
|
this.discolor(this.nouseObject, false);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 鼠标移动事件
|
|||
|
* @param {*} event
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.onTouchMove = function (event) {
|
|||
|
if (this.touchObject && this.touchPosition) {
|
|||
|
const position = this.getPlatformMousePosition(event);
|
|||
|
var rect = this.renderer.domElement.getBoundingClientRect();
|
|||
|
position.sub(new THREE.Vector2(rect.x | rect.left, rect.y | rect.top));
|
|||
|
/* 按下后拖动距离大于5像素,取消点击处理 */
|
|||
|
const distance = this.touchPosition.clone().distanceTo(position.clone());
|
|||
|
if (distance > 5) {
|
|||
|
this.discolor(this.touchObject, false);
|
|||
|
this.touchPosition = null;
|
|||
|
this.touchObject = null;
|
|||
|
}
|
|||
|
event.preventDefault();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 鼠标抬起事件
|
|||
|
* @param {*} event
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.onTouchEnd = function (event) {
|
|||
|
if (this.touchPosition == null || this.touchObject == null) return;
|
|||
|
event.preventDefault();
|
|||
|
this.discolor(this.touchObject, false);
|
|||
|
this.objectTouch(this.touchObject, this.touchObject.userData.cabinetIndex);
|
|||
|
this.touchPosition = null;
|
|||
|
this.touchObject = null;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 变色
|
|||
|
* @param {*} object
|
|||
|
* @param {*} enabled
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.discolor = function (object, enabled) {
|
|||
|
if (this.options.touchDiscolor == null) return;
|
|||
|
var emissive = new THREE.Color(this.options.touchDiscolor);
|
|||
|
if (enabled) {
|
|||
|
if (object._material == null) {
|
|||
|
object._material = object.material;
|
|||
|
if (object._material instanceof THREE.Material) {
|
|||
|
object.material = object.material.clone();
|
|||
|
object.material.emissive = emissive;
|
|||
|
} else if (object.material instanceof Array) {
|
|||
|
const materials = [];
|
|||
|
for (var i = 0; i < object.material.length; i++) {
|
|||
|
const m = object.material[i].clone();
|
|||
|
m.emissive = emissive;
|
|||
|
materials.push(m);
|
|||
|
}
|
|||
|
object.material = materials;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (object._material) {
|
|||
|
if (object.material instanceof THREE.Material) {
|
|||
|
object.material.dispose();
|
|||
|
} else if (object.material instanceof Array) {
|
|||
|
for (var i = 0; i < object.material.length; i++) {
|
|||
|
object.material[i].dispose();
|
|||
|
}
|
|||
|
object.material.length = 0;
|
|||
|
}
|
|||
|
object.material = object._material;
|
|||
|
delete object._material;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.prototype.loadObjectLabels = function () {
|
|||
|
var scope = this.options.scope;
|
|||
|
var devices = scope.NewMdcConfigures;
|
|||
|
var configs = scope.cabinets;
|
|||
|
for (var key in this.cabinets) {
|
|||
|
var cabinet = this.cabinets[key];
|
|||
|
var object3d = cabinet.object;
|
|||
|
var index = cabinet.index;
|
|||
|
var txtobject = object3d.getObjectByName('txt' + index);
|
|||
|
if (txtobject) {
|
|||
|
var info = this.createCanvasMaterial(this.options.labelOptions.width, this.options.labelOptions.height);
|
|||
|
var cfg = _.findWhere(configs, {
|
|||
|
no: index
|
|||
|
});
|
|||
|
if (cfg) {
|
|||
|
this.drawCanvasLabel(info, cfg.cabinetName);
|
|||
|
// var dev = _.findWhere(devices, {
|
|||
|
// configId: cfg.configId
|
|||
|
// });
|
|||
|
// if (dev) {
|
|||
|
// this.drawCanvasLabel(info, dev.configName);
|
|||
|
// }
|
|||
|
}
|
|||
|
//this.drawCanvasLabel(info, "Txt"+index);
|
|||
|
txtobject.material = info.material;
|
|||
|
}else
|
|||
|
console.log("3D模型不正确!");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 渲染标签文本
|
|||
|
* @param {*} info 材质纹理等信息
|
|||
|
* @param {*} text 渲染文本
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.drawCanvasLabel = function (info, text) {
|
|||
|
var options = this.options.labelOptions;
|
|||
|
var ctx = info.context;
|
|||
|
var fontsize = options.fontSize == null ? info.height * 0.8 : options.fontSize;
|
|||
|
var fontstyle = fontsize + 'px ' + options.font;
|
|||
|
if (options.bold) fontstyle += " bold";
|
|||
|
ctx.font = fontstyle;
|
|||
|
ctx.clearRect(0, 0, info.width, info.height);
|
|||
|
ctx.fillStyle = options.color;
|
|||
|
ctx.globalAlpha = 1;
|
|||
|
ctx.textBaseline = "top";
|
|||
|
var textwidth = ctx.measureText(text).width;
|
|||
|
var left = (info.width - textwidth) / 2;
|
|||
|
var top = (info.height - fontsize) / 2;
|
|||
|
ctx.fillText(text, left, top);
|
|||
|
info.texture.needsUpdate = true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 创建材质和贴图
|
|||
|
* @param {*} width
|
|||
|
* @param {*} height
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.createCanvasMaterial = function (width, height) {
|
|||
|
var canvas = document.createElement('canvas');
|
|||
|
var devicePixelRatio = window.devicePixelRatio;
|
|||
|
canvas.style.width = width + "px";
|
|||
|
canvas.style.height = height + "px";
|
|||
|
canvas.height = height * devicePixelRatio;
|
|||
|
canvas.width = width * devicePixelRatio;
|
|||
|
var context = canvas.getContext('2d');
|
|||
|
context.scale(devicePixelRatio, devicePixelRatio);
|
|||
|
context.imageSmoothingEnabled = true;
|
|||
|
context.translate(0, 0);
|
|||
|
context.imageSmoothingEnabled = true;
|
|||
|
context.imageSmoothingQuality = "high";
|
|||
|
context.clearRect(0, 0, width, height);
|
|||
|
|
|||
|
var texture = new THREE.CanvasTexture(canvas);
|
|||
|
// texture.encoding = THREE.sRGBEncoding;
|
|||
|
texture.magFilter = THREE.NearestFilter;
|
|||
|
texture.minFilter = THREE.LinearMipmapLinearFilter;
|
|||
|
|
|||
|
var material = new THREE.MeshBasicMaterial({
|
|||
|
map: texture,
|
|||
|
transparent: true,
|
|||
|
depthTest : false
|
|||
|
});
|
|||
|
return {
|
|||
|
width: width,
|
|||
|
height: height,
|
|||
|
canvas: canvas,
|
|||
|
context: context,
|
|||
|
texture: texture,
|
|||
|
material: material
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 加载模型
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.loadTemplate = function () {
|
|||
|
const loader = new THREE.FBXLoader();
|
|||
|
var self = this;
|
|||
|
|
|||
|
loader.load(this.options.modelFile, function (root) {
|
|||
|
root.position.set(0, 0, 0);
|
|||
|
root.traverse(function (e) {
|
|||
|
if (e instanceof THREE.Light) {
|
|||
|
e.intensity = 0.5;
|
|||
|
}
|
|||
|
self.initCabinet(e);
|
|||
|
});
|
|||
|
self.scene.add(root);
|
|||
|
root.updateMatrixWorld();
|
|||
|
// set the camera to frame the box
|
|||
|
self.frameArea(root, 0.9);
|
|||
|
// update the Trackball controls to handle the new size
|
|||
|
|
|||
|
if (root.animations && root.animations.length > 0) {
|
|||
|
for (var i = 0; i < root.animations.length; i++) {
|
|||
|
const action = self.mixer.clipAction(root.animations[i], root);
|
|||
|
action.loop = THREE.LoopRepeat;
|
|||
|
self.actions.push(action);
|
|||
|
}
|
|||
|
}
|
|||
|
self.loadObjectLabels();
|
|||
|
});
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* [静态方法]\
|
|||
|
* 从模型文件读取柜子的列表
|
|||
|
* @param {string} modelFile 模型文件路径
|
|||
|
*/
|
|||
|
// MDCThreeD.readCabinetList = async function (modelFile) {
|
|||
|
// const result = [];
|
|||
|
// const loader = new THREE.FBXLoader();
|
|||
|
// const root = await loader.loadAsync(modelFile);
|
|||
|
// root.traverse(function (object) {
|
|||
|
// if (object instanceof THREE.Mesh) {
|
|||
|
// const indexs = object.name.match(/\d+(\.\d+)?/g);
|
|||
|
// if (MDCThreeD.cabinetRegExp.test(object.name) && indexs.length === 1) {
|
|||
|
// const index = Number.parseInt(indexs[0]);
|
|||
|
// result.push(index);
|
|||
|
// }
|
|||
|
// }
|
|||
|
// });
|
|||
|
// return result.sort(function (a, b) {
|
|||
|
// return a < b ? -1 : (a === b) ? 0 : 1
|
|||
|
// });
|
|||
|
// }
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 初始化柜子
|
|||
|
* @param {*} object
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.initCabinet = function (object) {
|
|||
|
if (object instanceof THREE.Mesh) {
|
|||
|
const indexs = object.name.match(/\d+(\.\d+)?/g);
|
|||
|
if (MDCThreeD.cabinetRegExp.test(object.name) && indexs.length === 1) {
|
|||
|
const index = parseInt(indexs[0]);
|
|||
|
object.userData.selectable = true;
|
|||
|
object.userData.cabinetIndex = index;
|
|||
|
this.cabinets[index] = {
|
|||
|
index: index,
|
|||
|
object: object,
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 判断命中对象是否是柜子
|
|||
|
* @param {*} object
|
|||
|
* @returns
|
|||
|
*/
|
|||
|
MDCThreeD.prototype.isCabinet = function (object) {
|
|||
|
return object.userData.selectable && object.userData.cabinetIndex;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.prototype.dispose = function () {
|
|||
|
this.exitFlag = true;
|
|||
|
this.renderer.domElement.removeEventListener('pointerdown', this.touchHandle);
|
|||
|
this.renderer.domElement.removeEventListener('pointermove', this.touchMoveHandle);
|
|||
|
this.renderer.domElement.removeEventListener('pointerup', this.touchendHandle);
|
|||
|
|
|||
|
this.renderer.domElement.removeEventListener('touchstart', this.touchHandle);
|
|||
|
this.renderer.domElement.removeEventListener('touchmove', this.touchMoveHandle);
|
|||
|
this.renderer.domElement.removeEventListener('touchend', this.touchendHandle);
|
|||
|
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 (var i = 0; i < e.material.length; i++) {
|
|||
|
e.material[i].dispose();
|
|||
|
}
|
|||
|
} else if (e.material) e.material.dispose();
|
|||
|
}
|
|||
|
});
|
|||
|
this.renderer.dispose();
|
|||
|
this.renderer = null;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.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));
|
|||
|
};
|
|||
|
|
|||
|
MDCThreeD.prototype.isWebGLAvailable = function () {
|
|||
|
try {
|
|||
|
var canvas = document.createElement('canvas');
|
|||
|
return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
|
|||
|
} catch (e) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.prototype.getPlatformMousePosition = function (event) {
|
|||
|
if (event.touches != null && event.touches.length > 0) {
|
|||
|
return new THREE.Vector2(event.touches[0].clientX, event.touches[0].clientY);
|
|||
|
} else {
|
|||
|
var u = window.navigator.userAgent.toLocaleLowerCase();
|
|||
|
var b = u.match(/(trident)\/([\d.]+)/);
|
|||
|
if (b) {
|
|||
|
var rect = event.target.getBoundingClientRect();
|
|||
|
return new THREE.Vector2(event.pageX - rect.left, event.pageY - rect.top);
|
|||
|
} else {
|
|||
|
return new THREE.Vector2(event.clientX, event.clientY);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.prototype.isWebGL2Available = function () {
|
|||
|
try {
|
|||
|
var canvas = document.createElement('canvas');
|
|||
|
return !!(window.WebGL2RenderingContext && canvas.getContext('webgl2'));
|
|||
|
} catch (e) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
};
|
|||
|
MDCThreeD.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) {
|
|||
|
this.camera.aspect = width / height;
|
|||
|
this.camera.updateProjectionMatrix();
|
|||
|
this.renderer.setSize(width, height, false);
|
|||
|
}
|
|||
|
return needResize;
|
|||
|
};
|
|||
|
|
|||
|
MDCThreeD.prototype.frameArea = function (object, sizeToFitOnScreen) {
|
|||
|
const box = new THREE.Box3().setFromObject(object);
|
|||
|
const size = box.getSize(new THREE.Vector3());
|
|||
|
const boxSize = size.length();
|
|||
|
const boxCenter = box.getCenter(new THREE.Vector3());
|
|||
|
boxCenter.setY(-size.y / 2); //起始位置
|
|||
|
const halfSizeToFitOnScreen = boxSize * sizeToFitOnScreen * 0.5;
|
|||
|
const halfFovY = THREE.MathUtils.degToRad(this.camera.fov * .5);
|
|||
|
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
|
|||
|
const direction = (new THREE.Vector3())
|
|||
|
.subVectors(this.camera.position, boxCenter)
|
|||
|
.multiply(new THREE.Vector3(1, 0, 1))
|
|||
|
.normalize();
|
|||
|
this.camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
|
|||
|
this.camera.near = boxSize / 100;
|
|||
|
this.camera.far = boxSize * 100;
|
|||
|
this.camera.position.setX(1300);
|
|||
|
this.camera.position.setY(700);
|
|||
|
this.camera.position.setZ(300);
|
|||
|
this.originPosition = this.camera.position.clone();
|
|||
|
this.camera.updateProjectionMatrix();
|
|||
|
this.camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
|
|||
|
this.controls.maxDistance = boxSize * 10;
|
|||
|
this.controls.target.copy(boxCenter);
|
|||
|
this.controls.update();
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.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;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
MDCThreeD.prototype.loadCamera = function () {
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
MDCThreeD.prototype.loadControls = function () {
|
|||
|
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();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
MDCThreeD.prototype.loadEnvironment = function () {
|
|||
|
// if (this.options.environmentLight) {
|
|||
|
// const pmremGenerator = new THREE.PMREMGenerator(this.renderer);
|
|||
|
// const texture = pmremGenerator.fromScene(this.RoomEnvironment()).texture;
|
|||
|
// this.scene.environment = texture;
|
|||
|
// pmremGenerator.dispose();
|
|||
|
// }
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (this.options.background) {
|
|||
|
this.scene.background = new THREE.TextureLoader().load(this.options.background);
|
|||
|
}
|
|||
|
//
|
|||
|
const light = new THREE.AmbientLight(0xFFFFFF, 0.2);
|
|||
|
this.scene.add(light);
|
|||
|
//
|
|||
|
const skyColor = 0xB1E1FF;
|
|||
|
const groundColor = 0xB97A20;
|
|||
|
const intensity = 0.5;
|
|||
|
const hemisophereLight = new THREE.HemisphereLight(skyColor, groundColor, intensity);
|
|||
|
this.scene.add(hemisophereLight);
|
|||
|
|
|||
|
|
|||
|
/* 旋转变换 */
|
|||
|
this.transformGroup = new THREE.Object3D();
|
|||
|
this.transformObject = new THREE.Object3D();
|
|||
|
this.transformGroup.add(this.transformObject);
|
|||
|
}
|