three-base 1.0.62 → 1.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ApngTexture.js +61 -0
- package/lib/ApngTextureManage.js +87 -0
- package/lib/EventMesh.js +59 -0
- package/lib/ExtrudeMesh.js +362 -0
- package/lib/FPScontrol.js +170 -0
- package/lib/InstancedGroupMesh.js +63 -0
- package/lib/KeyFrameAnimation.js +78 -0
- package/lib/PlaneText.js +30 -0
- package/lib/PointLight.js +64 -0
- package/lib/Sky/Sky.js +28 -0
- package/lib/Text3D/Text3D.js +61 -0
- package/lib/Text3D/Text3D.ts +3 -3
- package/lib/Text3D/fontController.js +200 -0
- package/lib/ThreeBase.js +393 -0
- package/lib/ThreeMouse.js +357 -0
- package/lib/Transition.js +193 -0
- package/lib/index.d.ts +22 -0
- package/lib/keyContorls.js +98 -0
- package/lib/lib/ApngTexture.d.ts +13 -0
- package/lib/lib/ApngTextureManage.d.ts +18 -0
- package/lib/lib/EventMesh.d.ts +18 -0
- package/lib/lib/ExtrudeMesh.d.ts +111 -0
- package/lib/lib/FPScontrol.d.ts +44 -0
- package/lib/lib/InstancedGroupMesh.d.ts +10 -0
- package/lib/lib/KeyFrameAnimation.d.ts +25 -0
- package/lib/lib/PlaneText.d.ts +37 -0
- package/lib/lib/PointLight.d.ts +13 -0
- package/lib/lib/Sky/Sky.d.ts +13 -0
- package/lib/lib/Text3D/Text3D.d.ts +20 -0
- package/lib/lib/Text3D/fontController.d.ts +59 -0
- package/lib/lib/ThreeBase.d.ts +59 -0
- package/lib/lib/ThreeMouse.d.ts +39 -0
- package/lib/lib/Transition.d.ts +45 -0
- package/lib/lib/keyContorls.d.ts +25 -0
- package/lib/lib/planeModal1/PlaneModal1.d.ts +32 -0
- package/lib/lib/shaders.d.ts +17 -0
- package/lib/lib/spriteModal1/SpriteModal1.d.ts +31 -0
- package/lib/lib/threeLoader.d.ts +20 -0
- package/lib/lib/threeUtils.d.ts +41 -0
- package/lib/lib/type.d.ts +0 -0
- package/lib/planeModal1/PlaneModal1.js +104 -0
- package/lib/shaders.js +245 -0
- package/lib/spriteModal1/SpriteModal1.js +109 -0
- package/lib/threeLoader.js +110 -0
- package/lib/threeUtils.js +179 -0
- package/lib/type.js +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2021-04-15 00:34:44
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2022-06-08 14:33:45
|
|
6
|
+
*/
|
|
7
|
+
import Dexie from "dexie";
|
|
8
|
+
import { filter, first, isEmpty } from "lodash";
|
|
9
|
+
import { Font } from "three/examples/jsm/loaders/FontLoader.js";
|
|
10
|
+
import threeUtils from "../threeUtils";
|
|
11
|
+
import gentilisJSON from "./gentilis.json";
|
|
12
|
+
class indexBD extends Dexie {
|
|
13
|
+
constructor(dbName) {
|
|
14
|
+
super(dbName);
|
|
15
|
+
}
|
|
16
|
+
threeFont;
|
|
17
|
+
}
|
|
18
|
+
// 字体加载器
|
|
19
|
+
class fontContorl {
|
|
20
|
+
constructor() { }
|
|
21
|
+
THREEFontMap = new Map();
|
|
22
|
+
// 专门存储字体的数据库
|
|
23
|
+
fontBD = (() => {
|
|
24
|
+
let fontDB = new indexBD("three-base-font");
|
|
25
|
+
fontDB.version(1).stores({ threeFont: "++KeyPath,fontType,fontName,fontJson" });
|
|
26
|
+
return fontDB;
|
|
27
|
+
})();
|
|
28
|
+
/**
|
|
29
|
+
* 保存 字体json到本地数据库中
|
|
30
|
+
* @param {saveFontParam} { fontType = "simhei", fontName, fontJson }
|
|
31
|
+
* @memberof fontContorl
|
|
32
|
+
*/
|
|
33
|
+
async saveFont({ fontType = "simhei", fontName, fontJson = "" }) {
|
|
34
|
+
let findResult = await this.getFont({ fontType, fontName });
|
|
35
|
+
if (isEmpty(findResult)) {
|
|
36
|
+
await this.fontBD.threeFont.add({ fontType, fontName, fontJson });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 通过 fontType 和 fontName 查询 fontJson
|
|
41
|
+
* @param {getFontParam} { fontType = "simhei", fontName }
|
|
42
|
+
* @returns
|
|
43
|
+
* @memberof fontContorl
|
|
44
|
+
*/
|
|
45
|
+
async getFont({ fontType = "simhei", fontName }) {
|
|
46
|
+
let fondResult = await this.fontBD.threeFont
|
|
47
|
+
.filter(d => (d.fontType === fontType && d.fontName === fontName))
|
|
48
|
+
.toArray();
|
|
49
|
+
if (isEmpty(fondResult)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return first(fondResult).fontJson;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// 加载字体的回调函数们
|
|
57
|
+
_loadTextCall = new Map();
|
|
58
|
+
// 加载文字 提供给需要创建字体模型的方法使用 以节流的形式调用 回调函数
|
|
59
|
+
async loadText({ fontType = "simhei", text = "", fontBasePath, callback }) {
|
|
60
|
+
// 加载字体容器
|
|
61
|
+
await this._loadFontIndexJson({ fontType, fontBasePath });
|
|
62
|
+
let newCallback = () => {
|
|
63
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
64
|
+
if (callback && fontFamily) {
|
|
65
|
+
callback(fontFamily);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
// 遍历文本
|
|
69
|
+
filter(text).map(fontName => {
|
|
70
|
+
// 没有的就去加载
|
|
71
|
+
if (!this.hasFont({ fontType, fontName })) {
|
|
72
|
+
// 添加文字的默认模型 避免报错
|
|
73
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
74
|
+
// 创建 three 字体对象
|
|
75
|
+
if (fontFamily) {
|
|
76
|
+
//@ts-ignore
|
|
77
|
+
fontFamily.data.glyphs[fontName] = { "ha": 1389, "x_min": 477, "x_max": 949, "o": "m 700 901 q 906 770 830 906 q 770 477 949 618 q 711 288 711 412 l 613 288 q 781 608 613 494 q 819 722 825 651 q 700 808 808 803 l 684 808 q 581 673 575 803 l 477 673 q 613 884 477 836 q 700 901 629 901 m 732 184 l 732 71 l 591 71 l 591 184 l 732 184 z " };
|
|
78
|
+
}
|
|
79
|
+
this._loadFontJson({ fontType, fontName, fontBasePath });
|
|
80
|
+
}
|
|
81
|
+
// 加入待执行的回调
|
|
82
|
+
let origin_callbacks = this._loadTextCall.get(`${fontType}_${fontName}`) || [];
|
|
83
|
+
if (newCallback) {
|
|
84
|
+
this._loadTextCall.set(`${fontType}_${fontName}`, [...origin_callbacks, newCallback]);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// 执行任务队列
|
|
88
|
+
threeUtils.addWork(newCallback);
|
|
89
|
+
}
|
|
90
|
+
// 加载字体
|
|
91
|
+
async _loadFontIndexJson({ fontType = "simhei", fontBasePath }) {
|
|
92
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
93
|
+
// 创建 three 字体对象
|
|
94
|
+
if (!fontFamily) {
|
|
95
|
+
// 初始字体结构
|
|
96
|
+
fontFamily = new Font({
|
|
97
|
+
"underlineThickness": 69,
|
|
98
|
+
"underlinePosition": -174,
|
|
99
|
+
"resolution": 1000,
|
|
100
|
+
"original_font_information": {},
|
|
101
|
+
"familyName": "Source Han Sans CN Normal",
|
|
102
|
+
"descender": -167,
|
|
103
|
+
"cssFontWeight": "normal",
|
|
104
|
+
"cssFontStyle": "normal",
|
|
105
|
+
"boundingBox": {
|
|
106
|
+
"yMin": -700,
|
|
107
|
+
"xMin": -1389,
|
|
108
|
+
"yMax": 700,
|
|
109
|
+
"xMax": 4067
|
|
110
|
+
},
|
|
111
|
+
"glyphs": {}
|
|
112
|
+
});
|
|
113
|
+
this.THREEFontMap.set(fontType, fontFamily);
|
|
114
|
+
// 读取本地数据库中的字体初始结构文件
|
|
115
|
+
let fontFamilyIndexJson = await this.getFont({ fontType, fontName: "index" });
|
|
116
|
+
// 加载外部字体初始结构文件
|
|
117
|
+
if (!fontFamilyIndexJson) {
|
|
118
|
+
this._loadFontJson({ fontType, fontName: "index", fontBasePath });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 加载外部字体.js
|
|
123
|
+
async _loadFontJson({ fontType = "simhei", fontName, fontBasePath }) {
|
|
124
|
+
let fontJson = await this.getFont({ fontType, fontName });
|
|
125
|
+
if (!fontJson) {
|
|
126
|
+
fontJson = gentilisJSON.glyphs[fontName];
|
|
127
|
+
}
|
|
128
|
+
// 数据库中没有 就去加载字体js
|
|
129
|
+
if (!fontJson) {
|
|
130
|
+
// 加载字体js
|
|
131
|
+
await new Promise(resolve => {
|
|
132
|
+
let script = document.createElement("script");
|
|
133
|
+
Object.assign(script, {
|
|
134
|
+
type: "text/javascript",
|
|
135
|
+
src: `${fontBasePath}${fontType}/${fontName}.js`,
|
|
136
|
+
async: true,
|
|
137
|
+
onload: () => {
|
|
138
|
+
script.remove();
|
|
139
|
+
resolve();
|
|
140
|
+
},
|
|
141
|
+
onerror: () => {
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
document.head.appendChild(script);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// 数据库或者默认字体中 有就加入字体文件中
|
|
149
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
150
|
+
// 创建 three 字体对象
|
|
151
|
+
if (fontFamily) {
|
|
152
|
+
//@ts-ignore
|
|
153
|
+
fontFamily.data.glyphs[fontName] = fontJson;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// 执行相应的回调函数
|
|
157
|
+
let origin_callbacks = this._loadTextCall.get(`${fontType}_${fontName}`) || [];
|
|
158
|
+
// // 删除待执行的回调
|
|
159
|
+
this._loadTextCall.delete(`${fontType}_${fontName}`);
|
|
160
|
+
origin_callbacks.map(callback => {
|
|
161
|
+
// 执行任务队列
|
|
162
|
+
threeUtils.addWork(callback);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// 判断是否有这个文字
|
|
166
|
+
hasFont({ fontType, fontName }) {
|
|
167
|
+
return !isEmpty(this.THREEFontMap.get(fontType) &&
|
|
168
|
+
//@ts-ignore
|
|
169
|
+
this.THREEFontMap.get(fontType).data.glyphs[fontName]);
|
|
170
|
+
}
|
|
171
|
+
// 这个方法是提供给外部字体文件调用的
|
|
172
|
+
addFont({ fontType = "simhei", fontName, fontJson }) {
|
|
173
|
+
// 保存字体json到本地数据中
|
|
174
|
+
this.saveFont({ fontType, fontName, fontJson });
|
|
175
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
176
|
+
// 创建 three 字体对象
|
|
177
|
+
if (fontFamily) {
|
|
178
|
+
//@ts-ignore
|
|
179
|
+
fontFamily.data.glyphs[fontName] = fontJson;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 这个方法是提供给外部字体文件调用的
|
|
183
|
+
addFontFamily({ fontType = "simhei", fontFamilyJson }) {
|
|
184
|
+
// 保存字体初始结构到数据库中
|
|
185
|
+
this.saveFont({ fontType, fontName: "index", fontJson: fontFamilyJson });
|
|
186
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
187
|
+
// 创建 three 字体对象
|
|
188
|
+
if (fontFamily) {
|
|
189
|
+
//@ts-ignore
|
|
190
|
+
fontFamily.data = {
|
|
191
|
+
...fontFamilyJson,
|
|
192
|
+
//@ts-ignore
|
|
193
|
+
glyphs: fontFamily.data.glyphs
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const fontContorller = new fontContorl();
|
|
199
|
+
Object.assign(window, { fontContorller });
|
|
200
|
+
export default fontContorller;
|
package/lib/ThreeBase.js
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2021-12-20 13:38:22
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2023-03-16 14:31:32
|
|
6
|
+
*/
|
|
7
|
+
import elementResizeEvent from "element-resize-event";
|
|
8
|
+
import { round } from "lodash";
|
|
9
|
+
import { AxesHelper, EventDispatcher, GridHelper, LinearFilter, Mesh, MOUSE, NoBlending, NormalBlending, PerspectiveCamera, RGBAFormat, Scene, TOUCH, Vector2, Vector3, WebGLRenderer, WebGLRenderTarget } from "three";
|
|
10
|
+
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
11
|
+
import { generateUUID } from "three/src/math/MathUtils";
|
|
12
|
+
import { clearShader, coptyShader, fullScreenMesh, gaussBlurShader, strokeShader } from "./shaders";
|
|
13
|
+
import threeLoader from "./threeLoader";
|
|
14
|
+
import ThreeMouse from "./ThreeMouse";
|
|
15
|
+
import threeUtils from "./threeUtils";
|
|
16
|
+
import Transition from "./Transition";
|
|
17
|
+
// three.js 的基础对象
|
|
18
|
+
export default class ThreeBase extends EventDispatcher {
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.init();
|
|
22
|
+
}
|
|
23
|
+
// 公用渲染目标1
|
|
24
|
+
renderTarget = new WebGLRenderTarget(128, 128, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
25
|
+
// 渲染目标2
|
|
26
|
+
renderTarget2 = new WebGLRenderTarget(128, 128, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
27
|
+
// 公用二维向量
|
|
28
|
+
tempVector2 = new Vector2();
|
|
29
|
+
// 公用的三维向量
|
|
30
|
+
tempVector3 = new Vector3();
|
|
31
|
+
//渲染器的尺寸
|
|
32
|
+
size = new Vector2(0, 0);
|
|
33
|
+
// 渲染器对象
|
|
34
|
+
renderer = (() => {
|
|
35
|
+
const renderer = new WebGLRenderer({
|
|
36
|
+
alpha: true,
|
|
37
|
+
antialias: true,
|
|
38
|
+
precision: "highp",
|
|
39
|
+
logarithmicDepthBuffer: true,
|
|
40
|
+
preserveDrawingBuffer: false,
|
|
41
|
+
stencil: false, // 模版
|
|
42
|
+
});
|
|
43
|
+
renderer.domElement.id = generateUUID();
|
|
44
|
+
renderer.localClippingEnabled = true;
|
|
45
|
+
renderer.setPixelRatio(window.devicePixelRatio);
|
|
46
|
+
renderer.autoClear = false;
|
|
47
|
+
threeLoader.setAnisotropy(renderer.capabilities.getMaxAnisotropy());
|
|
48
|
+
return renderer;
|
|
49
|
+
})();
|
|
50
|
+
//透视相机
|
|
51
|
+
camera = new PerspectiveCamera(45, 1, 0.0001, 10000);
|
|
52
|
+
// 场景对象
|
|
53
|
+
scene = new Scene();
|
|
54
|
+
///鼠标事件对象
|
|
55
|
+
threeMouse = new ThreeMouse(this.renderer, this.camera, this.scene);
|
|
56
|
+
// 轨道控制器
|
|
57
|
+
controls = (() => {
|
|
58
|
+
const controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
59
|
+
controls.addEventListener("change", () => {
|
|
60
|
+
this.needRender = true;
|
|
61
|
+
});
|
|
62
|
+
controls.rotateSpeed = 0.2;
|
|
63
|
+
controls.maxPolarAngle = Math.PI;
|
|
64
|
+
controls.enableDamping = true;
|
|
65
|
+
controls.dampingFactor = 0.1;
|
|
66
|
+
controls.screenSpacePanning = true;
|
|
67
|
+
return controls;
|
|
68
|
+
})();
|
|
69
|
+
// 上下文是否被销毁了
|
|
70
|
+
isRendererContextLost = false;
|
|
71
|
+
// 设置 dom 容器
|
|
72
|
+
async setContainer(div) {
|
|
73
|
+
if (div) {
|
|
74
|
+
//删除这个容器里面的所有canvas
|
|
75
|
+
const canvas = div.getElementsByTagName("canvas");
|
|
76
|
+
for (let c of canvas)
|
|
77
|
+
c.remove();
|
|
78
|
+
div.append(this.renderer.domElement);
|
|
79
|
+
// 监听容器的尺寸的改变
|
|
80
|
+
elementResizeEvent(div, () => {
|
|
81
|
+
let rect = window.getComputedStyle(div);
|
|
82
|
+
let width = parseInt(rect.width);
|
|
83
|
+
let height = parseInt(rect.height);
|
|
84
|
+
this.resize(width, height);
|
|
85
|
+
});
|
|
86
|
+
// 如果上下文被销毁了, 就恢复上下文
|
|
87
|
+
if (this.isRendererContextLost) {
|
|
88
|
+
this.renderer.forceContextRestore();
|
|
89
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
90
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
91
|
+
this.renderer.domElement.style.opacity = "1";
|
|
92
|
+
}
|
|
93
|
+
let rect = window.getComputedStyle(div);
|
|
94
|
+
let width = parseInt(rect.width);
|
|
95
|
+
let height = parseInt(rect.height);
|
|
96
|
+
this.resize(width, height);
|
|
97
|
+
// 开启时时渲染
|
|
98
|
+
threeUtils.removeEventListener("requestAnimationFrame", this.renderBindThis);
|
|
99
|
+
threeUtils.addEventListener("requestAnimationFrame", this.renderBindThis);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// 修改尺寸
|
|
103
|
+
resize(width, height) {
|
|
104
|
+
this.camera.aspect = width / height;
|
|
105
|
+
this.camera.updateProjectionMatrix();
|
|
106
|
+
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
107
|
+
this.renderer.setSize(width, height);
|
|
108
|
+
this.size.set(width, height);
|
|
109
|
+
// 渲染场景
|
|
110
|
+
this.renderer.clear();
|
|
111
|
+
this.renderer.render(this.scene, this.camera);
|
|
112
|
+
}
|
|
113
|
+
// 控制器的位置缓动的计算的顶点对象
|
|
114
|
+
controlsPosition = (() => {
|
|
115
|
+
const controlsPosition = new Transition({ x: 100, y: 100, z: 100 });
|
|
116
|
+
controlsPosition.setDuration(1000);
|
|
117
|
+
controlsPosition.onChange(({ x, y, z }) => {
|
|
118
|
+
this.camera.position.set(x, y, z);
|
|
119
|
+
this.camera.lookAt(this.controls.target);
|
|
120
|
+
this.needRender = true;
|
|
121
|
+
});
|
|
122
|
+
return controlsPosition;
|
|
123
|
+
})();
|
|
124
|
+
// 控制器的 朝向带缓动的计算的顶点对象
|
|
125
|
+
controlsCenter = (() => {
|
|
126
|
+
const controlsCenter = new Transition({ x: 0, y: 0, z: 0 });
|
|
127
|
+
controlsCenter.setDuration(1000);
|
|
128
|
+
controlsCenter.onChange(({ x, y, z }) => {
|
|
129
|
+
this.controls.target.set(x, y, z);
|
|
130
|
+
this.camera.lookAt(this.controls.target);
|
|
131
|
+
this.needRender = true;
|
|
132
|
+
});
|
|
133
|
+
return controlsCenter;
|
|
134
|
+
})();
|
|
135
|
+
init() {
|
|
136
|
+
// 非开发模式添加网格辅助线
|
|
137
|
+
if (threeUtils.isDev) {
|
|
138
|
+
const gridHelper = new GridHelper(1000, 100, 0x303030, 0x303030);
|
|
139
|
+
gridHelper.position.set(0, -0.001, 0);
|
|
140
|
+
this.scene.add(gridHelper);
|
|
141
|
+
const axesHelper = new AxesHelper(10000);
|
|
142
|
+
this.scene.add(axesHelper);
|
|
143
|
+
}
|
|
144
|
+
// 资源加载进度有更新时, 需要渲染
|
|
145
|
+
threeLoader.addEventListener("progress", () => {
|
|
146
|
+
this.needRender = true;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// 重置控制器的位置
|
|
150
|
+
resetLookAt({ position, center, }) {
|
|
151
|
+
// 停止控制器的惯性
|
|
152
|
+
this.controls.enableDamping = false;
|
|
153
|
+
this.controls.saveState();
|
|
154
|
+
this.controls.update();
|
|
155
|
+
this.controls.reset();
|
|
156
|
+
this.controls.enableDamping = true;
|
|
157
|
+
position && this.controlsPosition.reset({ x: position.x, y: position.y, z: position.z });
|
|
158
|
+
center && this.controlsCenter.reset({ x: center.x, y: center.y, z: center.z });
|
|
159
|
+
this.needRender = true;
|
|
160
|
+
}
|
|
161
|
+
// 设置控制器的位置 以动画的方式移动控制器
|
|
162
|
+
async setLookAt({ position, center, duration = 1000 }) {
|
|
163
|
+
// 停止控制器的惯性
|
|
164
|
+
this.controls.enableDamping = false;
|
|
165
|
+
this.controls.saveState();
|
|
166
|
+
this.controls.update();
|
|
167
|
+
this.controls.reset();
|
|
168
|
+
this.controls.enableDamping = true;
|
|
169
|
+
let currentPosition = this.camera.position.clone();
|
|
170
|
+
let currentCenter = this.controls.target.clone();
|
|
171
|
+
// 等待动画执行完成
|
|
172
|
+
await Promise.all([
|
|
173
|
+
new Promise(async (resolve, reject) => {
|
|
174
|
+
if (position) {
|
|
175
|
+
this.controlsPosition.setDuration(duration).reset({ x: currentPosition.x, y: currentPosition.y, z: currentPosition.z });
|
|
176
|
+
await this.controlsPosition.set({ x: position.x, y: position.y, z: position.z });
|
|
177
|
+
}
|
|
178
|
+
resolve();
|
|
179
|
+
}),
|
|
180
|
+
new Promise(async (resolve, reject) => {
|
|
181
|
+
if (center) {
|
|
182
|
+
this.controlsCenter.setDuration(duration).reset({ x: currentCenter.x, y: currentCenter.y, z: currentCenter.z });
|
|
183
|
+
await this.controlsCenter.set({ x: center.x, y: center.y, z: center.z });
|
|
184
|
+
}
|
|
185
|
+
resolve();
|
|
186
|
+
}),
|
|
187
|
+
]);
|
|
188
|
+
}
|
|
189
|
+
// 获取控制的位置和朝向 保留3位小数
|
|
190
|
+
getLookAt() {
|
|
191
|
+
const position = this.camera.position.toArray().map(v => round(v, 3));
|
|
192
|
+
const center = this.controls.target.toArray().map(v => round(v, 3));
|
|
193
|
+
return {
|
|
194
|
+
center: new Vector3(...center),
|
|
195
|
+
position: new Vector3(...position),
|
|
196
|
+
centerPosition: `center: new Vector3(${center.join(",")}),position: new Vector3(${position.join(",")})`
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// 三维向量转化成屏幕上的2维向量
|
|
200
|
+
v3tov2(v3) {
|
|
201
|
+
v3.project(this.camera);
|
|
202
|
+
const v2 = new Vector2((v3.x + 1) * this.size.x * 0.5, (-v3.y + 1) * this.size.y * 0.5);
|
|
203
|
+
return v2;
|
|
204
|
+
}
|
|
205
|
+
// 控制器类型
|
|
206
|
+
controlType = "OrbitControls";
|
|
207
|
+
// 记录一下空间平移方式 在切换控制器的时候保留一下平移方式
|
|
208
|
+
originScreenSpacePanning = false;
|
|
209
|
+
//改变控制器的类型
|
|
210
|
+
setControlType(controlType) {
|
|
211
|
+
if (controlType === "OrbitControls") {
|
|
212
|
+
this.controls.screenSpacePanning = this.originScreenSpacePanning;
|
|
213
|
+
this.controls.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
|
|
214
|
+
this.controls.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
|
|
215
|
+
}
|
|
216
|
+
else if (controlType === "MapControls") {
|
|
217
|
+
this.originScreenSpacePanning = this.controls.screenSpacePanning;
|
|
218
|
+
// pan orthogonal to world-space direction camera.up
|
|
219
|
+
this.controls.screenSpacePanning = false;
|
|
220
|
+
this.controls.mouseButtons.LEFT = MOUSE.PAN;
|
|
221
|
+
this.controls.mouseButtons.RIGHT = MOUSE.ROTATE;
|
|
222
|
+
this.controls.touches.ONE = TOUCH.PAN;
|
|
223
|
+
this.controls.touches.TWO = TOUCH.DOLLY_ROTATE;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// 是否自动渲染
|
|
227
|
+
autoRender = true;
|
|
228
|
+
//是否需要渲染, 当autoRender=false的时候就需要 手动触发渲染
|
|
229
|
+
needRender = false;
|
|
230
|
+
// 停止渲染
|
|
231
|
+
stopRender() {
|
|
232
|
+
threeUtils.removeEventListener("requestAnimationFrame", this.renderBindThis);
|
|
233
|
+
this.renderer.forceContextLoss();
|
|
234
|
+
// 标记上下文被销毁了
|
|
235
|
+
this.isRendererContextLost = true;
|
|
236
|
+
this.resize(100, 100);
|
|
237
|
+
this.renderer.domElement.style.opacity = "0";
|
|
238
|
+
}
|
|
239
|
+
// 渲染场景
|
|
240
|
+
render() {
|
|
241
|
+
// 控制器在移动时鼠标不能操作
|
|
242
|
+
this.controls.enabled = (this.controlsPosition.isDone() || this.controlsCenter.isDone());
|
|
243
|
+
// canvas 没有在页面上面的话 就跳过渲染
|
|
244
|
+
if (!threeUtils.inDocument(this.renderer.domElement)) {
|
|
245
|
+
this.stopRender();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// 分发鼠标事件
|
|
249
|
+
this.threeMouse.dispatchEvent();
|
|
250
|
+
// 在不自动渲染时, needRender=false 就跳过渲染
|
|
251
|
+
if (!this.autoRender && !this.needRender) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this.needRender = false;
|
|
255
|
+
if (this.controls.enabled) {
|
|
256
|
+
this.controls.update();
|
|
257
|
+
}
|
|
258
|
+
this.renderer.clear();
|
|
259
|
+
// 渲染场景
|
|
260
|
+
this.dispatchEvent({ type: "beforeRender" });
|
|
261
|
+
this.renderer.render(this.scene, this.camera);
|
|
262
|
+
this.dispatchEvent({ type: "afterRender" });
|
|
263
|
+
}
|
|
264
|
+
renderBindThis = this.render.bind(this);
|
|
265
|
+
// 下载渲染图
|
|
266
|
+
download(fileName = "download") {
|
|
267
|
+
this.render();
|
|
268
|
+
const base64 = this.renderer.domElement.toDataURL('image/png');
|
|
269
|
+
let saveLink = document.createElement("a");
|
|
270
|
+
saveLink.download = `${fileName}.png`;
|
|
271
|
+
saveLink.href = base64;
|
|
272
|
+
document.body.append(saveLink);
|
|
273
|
+
saveLink.click();
|
|
274
|
+
}
|
|
275
|
+
_preMesh = new Mesh();
|
|
276
|
+
_preRT = new WebGLRenderTarget(128, 128, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
277
|
+
//预加载纹理图片
|
|
278
|
+
async preloadTexture(src) {
|
|
279
|
+
const texture = threeLoader.getTexture(src);
|
|
280
|
+
while (texture && !texture.image || !texture.image.complete) {
|
|
281
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
282
|
+
}
|
|
283
|
+
// 添加到计划任务中去
|
|
284
|
+
threeUtils.addWork(() => {
|
|
285
|
+
const originRenderTarget = this.renderer.getRenderTarget();
|
|
286
|
+
this.renderer.setRenderTarget(this._preRT);
|
|
287
|
+
this._preMesh.material.map = texture;
|
|
288
|
+
this.renderer.render(this._preMesh, this.camera);
|
|
289
|
+
this.renderer.setRenderTarget(originRenderTarget);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
//预加载网格
|
|
293
|
+
async preloadGeometry(geometry) {
|
|
294
|
+
// 添加到计划任务中去
|
|
295
|
+
threeUtils.addWork(() => {
|
|
296
|
+
const originRenderTarget = this.renderer.getRenderTarget();
|
|
297
|
+
this.renderer.setRenderTarget(this._preRT);
|
|
298
|
+
this._preMesh.geometry = geometry;
|
|
299
|
+
this.renderer.render(this._preMesh, this.camera);
|
|
300
|
+
this.renderer.setRenderTarget(originRenderTarget);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
// 清理渲染目标
|
|
304
|
+
clearRendererTargte(rendererTarget) {
|
|
305
|
+
const originTarget = this.renderer.getRenderTarget();
|
|
306
|
+
this.renderer.setRenderTarget(rendererTarget);
|
|
307
|
+
fullScreenMesh.material = clearShader;
|
|
308
|
+
fullScreenMesh.render(this.renderer);
|
|
309
|
+
this.renderer.clearDepth();
|
|
310
|
+
this.renderer.setRenderTarget(originTarget);
|
|
311
|
+
}
|
|
312
|
+
// 拷贝纹理到渲染目标
|
|
313
|
+
copyTextureToRenderTarget(texture, rendererTarget, alpha = false, opactity = 1) {
|
|
314
|
+
const originTarget = this.renderer.getRenderTarget();
|
|
315
|
+
if (rendererTarget) {
|
|
316
|
+
this.renderer.getSize(this.tempVector2);
|
|
317
|
+
rendererTarget.setSize(this.tempVector2.x, this.tempVector2.y);
|
|
318
|
+
}
|
|
319
|
+
this.renderer.setRenderTarget(rendererTarget);
|
|
320
|
+
fullScreenMesh.material = coptyShader;
|
|
321
|
+
coptyShader.uniforms.map.value = texture;
|
|
322
|
+
coptyShader.uniforms.opacity.value = opactity;
|
|
323
|
+
coptyShader.blending = alpha ? NoBlending : NormalBlending;
|
|
324
|
+
fullScreenMesh.render(this.renderer);
|
|
325
|
+
this.renderer.setRenderTarget(originTarget);
|
|
326
|
+
}
|
|
327
|
+
// 把对象绘制到渲染目标中
|
|
328
|
+
object3dToRendererTarget(obj, rendererTarget) {
|
|
329
|
+
this.clearRendererTargte(rendererTarget);
|
|
330
|
+
const originTarget = this.renderer.getRenderTarget();
|
|
331
|
+
this.renderer.setRenderTarget(rendererTarget);
|
|
332
|
+
this.renderer.getSize(this.tempVector2);
|
|
333
|
+
rendererTarget.setSize(this.tempVector2.x, this.tempVector2.y);
|
|
334
|
+
this.renderer.render(obj, this.camera);
|
|
335
|
+
this.renderer.setRenderTarget(originTarget);
|
|
336
|
+
}
|
|
337
|
+
// 给渲染目标的内容加描边
|
|
338
|
+
rendererTagetAddStroke(rendererTarget, strockWidth, color, opacity) {
|
|
339
|
+
const originTarget = this.renderer.getRenderTarget();
|
|
340
|
+
this.clearRendererTargte(this.renderTarget2);
|
|
341
|
+
this.renderer.setRenderTarget(this.renderTarget2);
|
|
342
|
+
this.renderer.getSize(this.tempVector2);
|
|
343
|
+
this.renderTarget2.setSize(this.tempVector2.x, this.tempVector2.y);
|
|
344
|
+
fullScreenMesh.material = strokeShader;
|
|
345
|
+
strokeShader.uniforms.map.value = rendererTarget.texture;
|
|
346
|
+
strokeShader.uniforms.resolution.value.set(this.tempVector2.x, this.tempVector2.y);
|
|
347
|
+
strokeShader.uniforms.strokeWidth.value = strockWidth;
|
|
348
|
+
strokeShader.uniforms.strokeColor.value.set(color);
|
|
349
|
+
strokeShader.uniforms.opacity.value = opacity;
|
|
350
|
+
fullScreenMesh.render(this.renderer);
|
|
351
|
+
this.copyTextureToRenderTarget(this.renderTarget2.texture, rendererTarget, true);
|
|
352
|
+
this.renderer.setRenderTarget(originTarget);
|
|
353
|
+
}
|
|
354
|
+
// 渲染对象的描边
|
|
355
|
+
renderObject3dStroke(obj, strockWidth, color, opacity) {
|
|
356
|
+
this.object3dToRendererTarget(obj, this.renderTarget);
|
|
357
|
+
this.rendererTagetAddStroke(this.renderTarget, strockWidth, color, opacity);
|
|
358
|
+
this.copyTextureToRenderTarget(this.renderTarget.texture, null);
|
|
359
|
+
}
|
|
360
|
+
//给渲染目标加上高斯模糊计算
|
|
361
|
+
renderTargetgaussBlur(rendererTarget, radius, opacity) {
|
|
362
|
+
const originTarget = this.renderer.getRenderTarget();
|
|
363
|
+
this.clearRendererTargte(this.renderTarget2);
|
|
364
|
+
this.renderer.setRenderTarget(this.renderTarget2);
|
|
365
|
+
this.renderer.getSize(this.tempVector2);
|
|
366
|
+
this.renderTarget2.setSize(this.tempVector2.x, this.tempVector2.y);
|
|
367
|
+
fullScreenMesh.material = gaussBlurShader;
|
|
368
|
+
gaussBlurShader.uniforms.map.value = rendererTarget.texture;
|
|
369
|
+
gaussBlurShader.uniforms.radius.value = radius;
|
|
370
|
+
gaussBlurShader.uniforms.opacity.value = opacity;
|
|
371
|
+
gaussBlurShader.uniforms.resolution.value.set(this.tempVector2.x, this.tempVector2.y);
|
|
372
|
+
fullScreenMesh.render(this.renderer);
|
|
373
|
+
this.copyTextureToRenderTarget(this.renderTarget2.texture, rendererTarget, true);
|
|
374
|
+
this.renderer.setRenderTarget(originTarget);
|
|
375
|
+
}
|
|
376
|
+
// 渲染目标上的纹理添加辉光效果
|
|
377
|
+
renderTargetAddGlow(renderTarget, width, color) {
|
|
378
|
+
this.rendererTagetAddStroke(renderTarget, 1 * width, color, 0.3);
|
|
379
|
+
this.rendererTagetAddStroke(renderTarget, 2 * width, color, 0.2);
|
|
380
|
+
this.rendererTagetAddStroke(renderTarget, 3 * width, color, 0.05);
|
|
381
|
+
this.renderTargetgaussBlur(renderTarget, 1, 1);
|
|
382
|
+
this.renderTargetgaussBlur(renderTarget, 1, 1);
|
|
383
|
+
this.renderTargetgaussBlur(renderTarget, 1, 1);
|
|
384
|
+
}
|
|
385
|
+
// 渲染 渲染目标
|
|
386
|
+
renderRendererTarget(renderTarget, alpha = false) {
|
|
387
|
+
coptyShader.uniforms.map.value = renderTarget.texture;
|
|
388
|
+
coptyShader.uniforms.opacity.value = 1.0;
|
|
389
|
+
fullScreenMesh.material = coptyShader;
|
|
390
|
+
coptyShader.blending = alpha ? NoBlending : NormalBlending;
|
|
391
|
+
fullScreenMesh.render(this.renderer);
|
|
392
|
+
}
|
|
393
|
+
}
|