2018-09-24 10:36:23 +08:00

396 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import History from '../core/History';
import Storage from '../core/Storage';
import AnimationManager from '../animation/AnimationManager';
/**
* 编辑器
* @author mrdoob / http://mrdoob.com/
* @author tengge / https://github.com/tengge1
*/
function Editor(app) {
this.app = app;
this.app.editor = this;
// 基础
this.history = new History(this);
this.storage = new Storage();
// 场景
this.scene = new THREE.Scene();
this.scene.name = '场景';
this.scene.background = new THREE.Color(0xaaaaaa);
this.sceneHelpers = new THREE.Scene();
this.sceneID = null; // 当前场景ID
this.sceneName = null; // 当前场景名称
// 相机
this.DEFAULT_CAMERA = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);
this.DEFAULT_CAMERA.name = '默认相机';
this.DEFAULT_CAMERA.userData.isDefault = true;
this.DEFAULT_CAMERA.position.set(20, 10, 20);
this.DEFAULT_CAMERA.lookAt(new THREE.Vector3());
this.camera = this.DEFAULT_CAMERA.clone();
// 渲染器
this.renderer = new THREE.WebGLRenderer({
antialias: true
});
this.renderer.gammaInput = false;
this.renderer.gammaOutput = false;
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.autoClear = false;
this.renderer.autoUpdateScene = false;
this.renderer.setPixelRatio(window.devicePixelRatio);
this.app.viewport.container.dom.appendChild(this.renderer.domElement);
this.renderer.setSize(this.app.viewport.container.dom.offsetWidth, this.app.viewport.container.dom.offsetHeight);
// 音频监听器
this.audioListener = new THREE.AudioListener();
this.audioListener.name = '音频监听器';
// 物体
this.object = {};
// 物体
this.objects = [];
// 脚本 格式:{ uuid: { id: 'mongoDB id', name: 'Script Name', type: 'Script Type', source: 'Source Code', uuid: 'uuid' }}
// 其中uuid是创建脚本时自动生成不可改变关联时使用id是mongo数据库ID字段name随便填写typejavascriptvertexShader, fragmentShader, jsonsource源码。
this.scripts = {};
this.animation = new AnimationManager(this.app);
// 帮助器
this.helpers = {};
// 当前选中物体
this.selected = null;
// 网格
this.grid = new THREE.GridHelper(30, 30, 0x444444, 0x888888);
this.grid.visible = this.app.options.showGrid;
this.sceneHelpers.add(this.grid);
// 平移旋转缩放控件
this.transformControls = new THREE.TransformControls(this.camera, this.app.viewport.container.dom);
this.sceneHelpers.add(this.transformControls);
// 编辑器控件
this.controls = new THREE.EditorControls(this.camera, this.app.viewport.container.dom);
// 性能控件
this.stats = new Stats();
this.stats.dom.style.position = 'absolute';
this.stats.dom.style.left = '8px';
this.stats.dom.style.top = '8px';
this.stats.dom.style.zIndex = 'initial';
this.app.viewport.container.dom.appendChild(this.stats.dom);
// 事件
this.app.on(`appStarted.${this.id}`, this.onAppStarted.bind(this));
this.app.on(`optionsChanged.${this.id}`, this.onOptionsChanged.bind(this));
};
Editor.prototype.onAppStarted = function () {
this.clear();
};
// -------------------- 场景 --------------------------
Editor.prototype.setScene = function (scene) { // 设置场景
// 移除原有物体
var objects = this.scene.children;
while (objects.length > 0) {
this.removeObject(objects[0]);
}
// 添加新物体
var children = scene.children.slice();
scene.children.length = 0;
this.scene = scene;
children.forEach(n => {
this.addObject(n);
});
this.app.call('sceneGraphChanged', this);
};
Editor.prototype.clear = function (addObject = true) { // 清空场景
this.history.clear();
this.storage.clear();
this.camera.copy(this.DEFAULT_CAMERA);
if (this.camera.children.findIndex(o => o instanceof THREE.AudioListener) === -1) {
this.camera.add(this.audioListener);
}
if (this.scene.background instanceof THREE.Texture) {
this.scene.background = new THREE.Color(0xaaaaaa);
} else if (this.scene.background instanceof THREE.Color) {
this.scene.background.setHex(0xaaaaaa);
}
this.scene.fog = null;
var objects = this.scene.children;
while (objects.length > 0) {
this.removeObject(objects[0]);
}
this.textures = {};
this.scripts = {};
this.animation.clear();
this.deselect();
// 添加默认元素
if (addObject) {
var light1 = new THREE.AmbientLight(0xffffff, 0.24);
light1.name = '环境光';
this.addObject(light1);
var light2 = new THREE.DirectionalLight(0xffffff, 0.56);
light2.name = '平行光';
light2.castShadow = true;
light2.position.set(5, 10, 7.5);
light2.shadow.mapSize.x = 2048;
light2.shadow.mapSize.y = 2048;
light2.shadow.camera.left = -100;
light2.shadow.camera.right = 100;
light2.shadow.camera.top = 100;
light2.shadow.camera.bottom = -100;
this.addObject(light2);
}
this.app.call('editorCleared', this);
this.app.call('scriptChanged', this);
this.app.call('animationChanged', this);
};
// ---------------------- 物体 ---------------------------
Editor.prototype.objectByUuid = function (uuid) { // 根据uuid获取物体
return this.scene.getObjectByProperty('uuid', uuid, true);
};
Editor.prototype.addObject = function (object) { // 添加物体
this.scene.add(object);
object.traverse(child => {
this.addHelper(child);
});
this.app.call('objectAdded', this, object);
this.app.call('sceneGraphChanged', this);
};
Editor.prototype.moveObject = function (object, parent, before) { // 移动物体
if (parent === undefined) {
parent = this.scene;
}
parent.add(object);
// sort children array
if (before !== undefined) {
var index = parent.children.indexOf(before);
parent.children.splice(index, 0, object);
parent.children.pop();
}
this.app.call('sceneGraphChanged', this);
};
Editor.prototype.removeObject = function (object) { // 移除物体
if (object.parent === null) { // 避免删除相机或场景
return;
}
object.traverse(child => {
this.removeHelper(child);
});
object.parent.remove(object);
this.app.call('objectRemoved', this, object);
this.app.call('sceneGraphChanged', this);
};
// ------------------------- 帮助 ------------------------------
Editor.prototype.addHelper = function (object) { // 添加物体帮助器
var options = this.app.options;
var helper = null;
if (object instanceof THREE.Camera) { // 相机
helper = new THREE.CameraHelper(object, 1);
helper.visible = options.showCameraHelper;
} else if (object instanceof THREE.PointLight) { // 点光源
helper = new THREE.PointLightHelper(object, 1);
helper.visible = options.showPointLightHelper;
} else if (object instanceof THREE.DirectionalLight) { // 平行光
helper = new THREE.DirectionalLightHelper(object, 1);
helper.visible = options.showDirectionalLightHelper;
} else if (object instanceof THREE.SpotLight) { // 聚光灯
helper = new THREE.SpotLightHelper(object, 1);
helper.visible = options.showSpotLightHelper;
} else if (object instanceof THREE.HemisphereLight) { // 半球光
helper = new THREE.HemisphereLightHelper(object, 1);
helper.visible = options.showHemisphereLightHelper;
} else if (object instanceof THREE.RectAreaLight) { // 矩形光
helper = new THREE.RectAreaLightHelper(object, 0xffffff);
helper.visible = options.showRectAreaLightHelper;
} else if (object instanceof THREE.SkinnedMesh) { // 骨骼
helper = new THREE.SkeletonHelper(object);
helper.visible = options.showSkeletonHelper;
} else {
// 该类型物体没有帮助器
return;
}
var geometry = new THREE.SphereBufferGeometry(2, 4, 2);
var material = new THREE.MeshBasicMaterial({
color: 0xff0000,
visible: false
});
var picker = new THREE.Mesh(geometry, material);
picker.name = 'picker';
picker.userData.object = object;
helper.add(picker);
this.sceneHelpers.add(helper);
this.helpers[object.id] = helper;
this.objects.push(picker);
};
Editor.prototype.removeHelper = function (object) { // 移除物体帮助
if (this.helpers[object.id] !== undefined) {
var helper = this.helpers[object.id];
helper.parent.remove(helper);
delete this.helpers[object.id];
var objects = this.objects;
objects.splice(objects.indexOf(helper.getObjectByName('picker')), 1);
}
};
Editor.prototype.onOptionsChanged = function (options) { // 帮助器改变事件
this.grid.visible = options.showGrid === undefined ? true : options.showGrid;
Object.keys(this.helpers).forEach(n => {
var helper = this.helpers[n];
if (helper instanceof THREE.CameraHelper) {
helper.visible = options.showCameraHelper;
} else if (helper instanceof THREE.PointLightHelper) {
helper.visible = options.showPointLightHelper;
} else if (helper instanceof THREE.DirectionalLightHelper) {
helper.visible = options.showDirectionalLightHelper;
} else if (helper instanceof THREE.SpotLightHelper) {
helper.visible = options.showSpotLightHelper;
} else if (helper instanceof THREE.HemisphereLightHelper) {
helper.visible = options.showHemisphereLightHelper;
} else if (helper instanceof THREE.RectAreaLightHelper) {
helper.visible = options.showRectAreaLightHelper;
} else if (helper instanceof THREE.SkeletonHelper) {
helper.visible = options.showSkeletonHelper;
}
});
};
// ------------------------ 脚本 ----------------------------
Editor.prototype.addScript = function (object, script) { // 添加脚本
if (this.scripts[object.uuid] === undefined) {
this.scripts[object.uuid] = [];
}
this.scripts[object.uuid].push(script);
this.app.call('scriptAdded', this, script);
};
Editor.prototype.removeScript = function (object, script) { // 移除脚本
if (this.scripts[object.uuid] === undefined) {
return;
}
var index = this.scripts[object.uuid].indexOf(script);
if (index !== -1) {
this.scripts[object.uuid].splice(index, 1);
}
this.app.call('scriptRemoved', this);
};
// ------------------------ 选中事件 --------------------------------
Editor.prototype.select = function (object) { // 选中物体
if (this.selected === object) {
return;
}
this.selected = object;
this.app.call('objectSelected', this, object);
};
Editor.prototype.selectById = function (id) { // 根据id选中物体
if (id === this.camera.id) {
this.select(this.camera);
return;
}
this.select(this.scene.getObjectById(id, true));
};
Editor.prototype.selectByUuid = function (uuid) { // 根据uuid选中物体
var _this = this;
this.scene.traverse(function (child) {
if (child.uuid === uuid) {
_this.select(child);
}
});
};
Editor.prototype.deselect = function () { // 取消选中物体
this.select(null);
};
// ---------------------- 焦点事件 --------------------------
Editor.prototype.focus = function (object) { // 设置焦点
this.app.call('objectFocused', this, object);
};
Editor.prototype.focusById = function (id) { // 根据id设置交点
var obj = this.scene.getObjectById(id, true);
if (obj) {
this.focus(obj);
}
};
// ----------------------- 命令事件 --------------------------
Editor.prototype.execute = function (cmd, optionalName) { // 执行事件
this.history.execute(cmd, optionalName);
};
Editor.prototype.undo = function () { // 撤销事件
this.history.undo();
};
Editor.prototype.redo = function () { // 重做事件
this.history.redo();
};
export default Editor;