three-base 0.0.1 → 1.0.2

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.
@@ -0,0 +1,209 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2022-05-04 23:01:36
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2022-06-06 13:32:08
6
+ */
7
+
8
+ import { Camera, Clock, EventDispatcher, Object3D, Vector3 } from "three";
9
+ import { Capsule } from "three/examples/jsm/math/Capsule";
10
+ import { Octree } from "three/examples/jsm/math/Octree";
11
+ import { clamp, degToRad } from "three/src/math/MathUtils";
12
+
13
+
14
+ /**
15
+ * 第一人称控制器
16
+ *
17
+ * @export
18
+ * @class FPScontrol
19
+ * @extends {EventDispatcher}
20
+ */
21
+ export default class FPScontrol extends EventDispatcher {
22
+
23
+ canvas!: HTMLCanvasElement
24
+
25
+ constructor(camera: Camera, canvas: HTMLCanvasElement) {
26
+ super();
27
+
28
+ // 相机对象
29
+ this.camera = camera;
30
+
31
+ this.camera.rotation.order = 'YXZ';
32
+
33
+ this.canvas = canvas;
34
+
35
+ this.init(canvas);
36
+ }
37
+
38
+ // 是否启用
39
+ enable = false;
40
+
41
+ GRAVITY = 30; // 重力
42
+ STEPS_PER_FRAME = 5; // 速度
43
+
44
+ camera!: Camera;
45
+
46
+ // 世界八叉树对象
47
+ worldOctree = new Octree();
48
+
49
+ // 用户自己的碰撞体积
50
+ playerCollider = new Capsule(new Vector3(0, 0.35, 0), new Vector3(0, 1, 0), 0.35);
51
+
52
+ // 时钟对象
53
+ clock = new Clock();
54
+
55
+ playerVelocity = new Vector3();
56
+ playerDirection = new Vector3();
57
+
58
+ playerOnFloor = false;
59
+ mouseTime = 0;
60
+ isMousedown = false;
61
+ keyStates: { [key: string]: boolean } = {};
62
+
63
+
64
+ init(canvas: HTMLCanvasElement) {
65
+ this.playerCollider.end.set(0, 1, 0);
66
+ document.addEventListener('keydown', this.keydown);
67
+ document.addEventListener('keyup', this.keyup);
68
+ canvas.addEventListener('pointerdown', this.mousedown);
69
+ document.addEventListener('pointerup', this.mouseup);
70
+ document.body.addEventListener('pointermove', this.mousemove);
71
+ this.enable = true;
72
+ }
73
+
74
+
75
+ keydown = (event: KeyboardEvent) => {
76
+ this.keyStates[event.code] = true;
77
+ }
78
+
79
+ keyup = (event: KeyboardEvent) => {
80
+ this.keyStates[event.code] = false;
81
+ }
82
+
83
+ mousedown = () => {
84
+ this.isMousedown = true;
85
+ this.mouseTime = performance.now();
86
+ }
87
+
88
+ mouseup = () => {
89
+ this.isMousedown = false;
90
+ }
91
+
92
+ mousemove = (event: MouseEvent) => {
93
+ if (this.enable && this.isMousedown) {
94
+ this.camera.rotation.y -= event.movementX / 500;
95
+ this.camera.rotation.x -= event.movementY / 500;
96
+
97
+ }
98
+ }
99
+
100
+ // 设置 八叉树 节点
101
+ fromGraphNode(object3d: Object3D) {
102
+ this.worldOctree.fromGraphNode(object3d);
103
+ }
104
+
105
+ // 获取前进的向量
106
+ getForwardVector = () => {
107
+ this.camera.getWorldDirection(this.playerDirection);
108
+ this.playerDirection.y = 0;
109
+ this.playerDirection.normalize();
110
+ return this.playerDirection;
111
+ }
112
+
113
+ // 获取 后退的向量
114
+ getSideVector = () => {
115
+ this.camera.getWorldDirection(this.playerDirection);
116
+ this.playerDirection.y = 0;
117
+ this.playerDirection.normalize();
118
+ this.playerDirection.cross(this.camera.up);
119
+ return this.playerDirection;
120
+ }
121
+
122
+ // 玩家移动控制器
123
+ controls = (deltaTime: number) => {
124
+ const speedDelta = deltaTime * (this.playerOnFloor ? 25 : 8);
125
+ if (this.keyStates['KeyW']) {
126
+ this.playerVelocity.add(this.getForwardVector().multiplyScalar(speedDelta));
127
+ }
128
+ if (this.keyStates['KeyS']) {
129
+ this.playerVelocity.add(this.getForwardVector().multiplyScalar(-speedDelta));
130
+ }
131
+ if (this.keyStates['KeyA']) {
132
+ this.playerVelocity.add(this.getSideVector().multiplyScalar(-speedDelta));
133
+ }
134
+ if (this.keyStates['KeyD']) {
135
+ this.playerVelocity.add(this.getSideVector().multiplyScalar(speedDelta));
136
+ }
137
+
138
+ if (this.playerOnFloor) {
139
+ if (this.keyStates['Space']) {
140
+ this.playerVelocity.y = 15;
141
+ }
142
+ }
143
+
144
+ }
145
+
146
+ // 更新玩家的位置
147
+ updatePlayer = (deltaTime: number) => {
148
+ let damping = Math.exp(-4 * deltaTime) - 1;
149
+ if (!this.playerOnFloor) {
150
+ this.playerVelocity.y -= this.GRAVITY * deltaTime;
151
+ damping *= 0.1;
152
+ }
153
+ this.playerVelocity.addScaledVector(this.playerVelocity, damping);
154
+ const deltaPosition = this.playerVelocity.clone().multiplyScalar(deltaTime);
155
+ this.playerCollider.translate(deltaPosition);
156
+ this.playerCollisions();
157
+ this.camera.position.copy(this.playerCollider.end);
158
+ this.camera.position.y += 1;
159
+ this.camera.rotation.x = clamp(this.camera.rotation.x, degToRad(-20), degToRad(20));
160
+ }
161
+
162
+ // 玩家的碰撞检测
163
+ playerCollisions() {
164
+ const result = this.worldOctree.capsuleIntersect(this.playerCollider);
165
+ this.playerOnFloor = false;
166
+ if (result) {
167
+ this.playerOnFloor = result.normal.y > 0;
168
+ if (!this.playerOnFloor) {
169
+ this.playerVelocity.addScaledVector(result.normal, -result.normal.dot(this.playerVelocity));
170
+
171
+ }
172
+ this.playerCollider.translate(result.normal.multiplyScalar(result.depth));
173
+ }
174
+ }
175
+ // 更新控制器的位置
176
+ teleportPlayerIfOob = () => {
177
+ if (this.camera.position.y <= -10) {
178
+ this.playerCollider.start.set(0, 0.35, 0);
179
+ this.playerCollider.end.set(0, 1, 10);
180
+ this.playerCollider.radius = 0.35;
181
+ this.camera.position.copy(this.playerCollider.end);
182
+ // this.camera.position.set(0, 3, 0);
183
+ }
184
+ }
185
+
186
+ // 更新
187
+ update() {
188
+ if (this.enable) {
189
+ const deltaTime = Math.min(0.05, this.clock.getDelta()) / this.STEPS_PER_FRAME;
190
+ for (let i = 0; i < this.STEPS_PER_FRAME; i++) {
191
+ this.controls(deltaTime);
192
+ this.updatePlayer(deltaTime);
193
+ this.teleportPlayerIfOob();
194
+ }
195
+ }
196
+ }
197
+
198
+ // 销毁事件
199
+ disposer() {
200
+ this.enable = false;
201
+ document.removeEventListener('keydown', this.keydown);
202
+ document.removeEventListener('keyup', this.keyup);
203
+ this.canvas.removeEventListener('pointerdown', this.mousedown);
204
+ document.removeEventListener('pointerup', this.mouseup);
205
+ document.body.removeEventListener('pointermove', this.mousemove);
206
+ }
207
+
208
+
209
+ }
@@ -0,0 +1,78 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2022-05-18 16:02:55
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2022-06-23 21:02:45
6
+ */
7
+
8
+ import { Mesh, MeshBasicMaterial, PointLight as THREEPointLight, SphereGeometry } from "three";
9
+ import threeSpritetext from "three-spritetext";
10
+ import threeUtils from "./threeUtils";
11
+
12
+
13
+ /**
14
+ * 点光源
15
+ * @export
16
+ * @class PointLight
17
+ * @extends {THREEPointLight}
18
+ */
19
+ export default class PointLight extends THREEPointLight {
20
+
21
+ constructor(color = "#fff", intensity?: number, distance?: number, decay?: number) {
22
+ super(color, intensity, distance, decay);
23
+
24
+ if (threeUtils.isDev) {
25
+ if (this.label) {
26
+ this.label.borderColor = color;
27
+ this.label.color = color;
28
+ this.label.scale.multiplyScalar(0.03);
29
+ }
30
+
31
+ }
32
+
33
+ }
34
+
35
+ sphere = threeUtils.isDev && (() => {
36
+ // 点光源辅助小球
37
+ const sphere = new SphereGeometry(0.1, 10, 10);
38
+ const materils = new MeshBasicMaterial({
39
+ color: this.color,
40
+ wireframe: true
41
+ });
42
+ const mesh = new Mesh(sphere, materils);
43
+
44
+ mesh.userData = {
45
+ cursor: "pointer"
46
+ };
47
+
48
+ mesh.addEventListener("mouseenter", () => {
49
+ if (this.label) {
50
+ this.label.visible = true;
51
+ }
52
+ });
53
+
54
+ mesh.addEventListener("mouseleave", () => {
55
+ if (this.label) {
56
+ this.label.visible = false;
57
+ }
58
+ });
59
+
60
+ this.add(mesh);
61
+ })();
62
+
63
+ label = threeUtils.isDev && (() => {
64
+ const label = new threeSpritetext("点光源");
65
+ label.renderOrder = Infinity;
66
+ label.backgroundColor = "rgba(0, 0, 0, 0.5)";
67
+ label.padding = 4;
68
+ label.borderRadius = 4;
69
+ label.borderWidth = 1;
70
+ label.position.set(0, 0.5, 0);
71
+ label.visible = false;
72
+ label.material.depthTest = false;
73
+ label.scale.multiplyScalar(0.001);
74
+ this.add(label);
75
+ return label;
76
+ })();
77
+
78
+ }
@@ -0,0 +1,399 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2021-12-20 13:38:22
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2022-08-23 10:00:35
6
+ */
7
+
8
+ import elementResizeEvent from "element-resize-event";
9
+ import { AxesHelper, EventDispatcher, GridHelper, LinearFilter, NoBlending, NormalBlending, Object3D, PerspectiveCamera, RGBAFormat, Scene, Texture, 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
+
18
+ // three.js 的基础对象
19
+ export default class ThreeBasic extends EventDispatcher {
20
+
21
+ constructor() {
22
+ super();
23
+ this.init();
24
+ }
25
+
26
+ // 公用渲染目标1
27
+ renderTarget = new WebGLRenderTarget(128, 128, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
28
+
29
+ // 渲染目标2
30
+ renderTarget2 = new WebGLRenderTarget(128, 128, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
31
+
32
+ // 公用二维向量
33
+ tempVector2 = new Vector2();
34
+
35
+ // 公用的三维向量
36
+ tempVector3 = new Vector3();
37
+
38
+ //渲染器的尺寸
39
+ size = new Vector2(0, 0);
40
+
41
+ // 渲染器对象
42
+ renderer = (() => {
43
+ const renderer = new WebGLRenderer({
44
+ alpha: true,// 透明背景
45
+ antialias: true, // 阴影抗锯齿
46
+ precision: "highp", //precision:highp/mediump/lowp着色精度选择
47
+ logarithmicDepthBuffer: true, // 对数深度缓冲区 避免当2个面完全重合时闪烁
48
+ preserveDrawingBuffer: false, // 是否保存绘图缓冲
49
+ stencil: false, // 模版
50
+ });
51
+
52
+ renderer.domElement.id = generateUUID();
53
+ renderer.localClippingEnabled = true;
54
+ renderer.setPixelRatio(window.devicePixelRatio);
55
+ renderer.autoClear = false;
56
+ threeLoader.setAnisotropy(renderer.capabilities.getMaxAnisotropy());
57
+ return renderer;
58
+ })();
59
+
60
+ //透视相机
61
+ camera = new PerspectiveCamera(45, 1, 0.0001, 10000);
62
+
63
+ // 场景对象
64
+ scene = new Scene();
65
+
66
+ ///鼠标事件对象
67
+ threeMouse = new ThreeMouse(this.renderer, this.camera, this.scene);
68
+
69
+ // 轨道控制器
70
+ controls = (() => {
71
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
72
+ controls.addEventListener("change", () => {
73
+ this.needRender = true;
74
+ });
75
+ controls.rotateSpeed = 0.2;
76
+ controls.maxPolarAngle = Math.PI;
77
+ controls.enableDamping = true;
78
+ controls.dampingFactor = 0.1;
79
+ controls.screenSpacePanning = true;
80
+ return controls;
81
+ })();
82
+
83
+ // 上下文是否被销毁了
84
+ isRendererContextLost = false;
85
+
86
+ // 设置 dom 容器
87
+ async setContainer(div: HTMLDivElement | null) {
88
+ if (div) {
89
+ const canvas = div.getElementsByTagName("canvas");
90
+ for (let c of canvas) c.remove();
91
+ div.append(this.renderer.domElement);
92
+
93
+ elementResizeEvent(div, () => {
94
+ let rect = window.getComputedStyle(div);
95
+ let width = parseInt(rect.width);
96
+ let height = parseInt(rect.height);
97
+ this.resize(width, height);
98
+ });
99
+
100
+
101
+ // 如果上下文被销毁了, 就恢复上下文
102
+ if (this.isRendererContextLost) {
103
+ this.renderer.forceContextRestore();
104
+ }
105
+
106
+ await new Promise(resolve => requestAnimationFrame(resolve));
107
+ await new Promise(resolve => requestAnimationFrame(resolve));
108
+
109
+ let rect = window.getComputedStyle(div);
110
+ let width = parseInt(rect.width);
111
+ let height = parseInt(rect.height);
112
+ this.resize(width, height);
113
+
114
+ // 开启时时渲染
115
+ threeUtils.removeEventListener("requestAnimationFrame", this.renderBindThis);
116
+ threeUtils.addEventListener("requestAnimationFrame", this.renderBindThis);
117
+ }
118
+ }
119
+
120
+ // 修改尺寸
121
+ resize(width: number, height: number) {
122
+ this.camera.aspect = width / height;
123
+ this.camera.updateProjectionMatrix();
124
+ this.renderer.setPixelRatio(window.devicePixelRatio);
125
+ this.renderer.setSize(width, height);
126
+ this.size.set(width, height);
127
+ // 渲染场景
128
+ this.renderer.clear();
129
+ this.renderer.render(this.scene, this.camera);
130
+ }
131
+
132
+ // 控制器的位置缓动的计算的顶点对象
133
+ controlsPosition = (() => {
134
+ const controlsPosition = new Transition({ x: 100, y: 100, z: 100 });
135
+ controlsPosition.setDuration(1000);
136
+ controlsPosition.onChange(({ x, y, z }) => {
137
+ this.camera.position.set(x, y, z);
138
+ this.camera.lookAt(this.controls.target);
139
+ this.needRender = true;
140
+ });
141
+ return controlsPosition;
142
+ })();
143
+
144
+ // 控制器的 朝向带缓动的计算的顶点对象
145
+ controlsCenter = (() => {
146
+ const controlsCenter = new Transition({ x: 0, y: 0, z: 0 });
147
+ controlsCenter.setDuration(1000);
148
+ controlsCenter.onChange(({ x, y, z }) => {
149
+ this.controls.target.set(x, y, z);
150
+ this.camera.lookAt(this.controls.target);
151
+ this.needRender = true;
152
+ });
153
+ return controlsCenter;
154
+ })();
155
+
156
+ init() {
157
+ // 非开发模式添加网格辅助线
158
+ if (threeUtils.isDev) {
159
+ const gridHelper = new GridHelper(1000, 100, 0x303030, 0x303030);
160
+ gridHelper.position.set(0, -0.01, 0);
161
+ this.scene.add(gridHelper);
162
+ const axesHelper = new AxesHelper(10000);
163
+ this.scene.add(axesHelper);
164
+ }
165
+
166
+ // 资源加载进度有更新时, 需要渲染
167
+ threeLoader.addEventListener("progress", () => {
168
+ this.needRender = true;
169
+ })
170
+
171
+ }
172
+
173
+ // 重置控制器的位置
174
+ resetLookAt({ position, center, }: { position?: Vector3, center?: Vector3, }) {
175
+ position && this.controlsPosition.reset({ x: position.x, y: position.y, z: position.z });
176
+ center && this.controlsCenter.reset({ x: center.x, y: center.y, z: center.z });
177
+ this.needRender = true;
178
+ }
179
+
180
+ // 设置控制器的位置 以动画的方式移动控制器
181
+ async setLookAt({ position, center, duration = 1000 }: { position?: Vector3, center?: Vector3, duration?: number }) {
182
+
183
+ let currentPosition = this.camera.position.clone();
184
+ let currentCenter = this.controls.target.clone();
185
+
186
+ if (position) {
187
+ this.controlsPosition
188
+ .setDuration(duration)
189
+ .reset({
190
+ x: currentPosition.x,
191
+ y: currentPosition.y,
192
+ z: currentPosition.z
193
+ })
194
+ .set({
195
+ x: position.x,
196
+ y: position.y,
197
+ z: position.z
198
+ });
199
+ }
200
+
201
+ if (center) {
202
+ this.controlsCenter
203
+ .setDuration(duration)
204
+ .reset({
205
+ x: currentCenter.x,
206
+ y: currentCenter.y,
207
+ z: currentCenter.z
208
+ }).set({
209
+ x: center.x,
210
+ y: center.y,
211
+ z: center.z
212
+ });
213
+ }
214
+
215
+ // 等待动画执行完成
216
+ while (!this.controlsCenter.isDone() || !this.controlsPosition.isDone()) {
217
+ await new Promise(resolve => setTimeout(resolve, 100));
218
+ }
219
+
220
+ }
221
+
222
+ // 获取控制的位置和朝向 保留3位小数
223
+ getLookAt() {
224
+ return {
225
+ position: new Vector3().copy(this.camera.position).multiplyScalar(1000).ceil().divideScalar(1000),
226
+ center: new Vector3().copy(this.controls.target).multiplyScalar(1000).ceil().divideScalar(1000)
227
+ }
228
+ }
229
+
230
+ // 三维向量转化成屏幕上的2维向量
231
+ v3tov2(v3: Vector3) {
232
+ v3.project(this.camera);
233
+ v3.x = ((v3.x + 1) * this.size.x * 0.5);
234
+ v3.y = ((-v3.y + 1) * this.size.y * 0.5);
235
+ v3.z = 0;
236
+ }
237
+
238
+ // 寻找最顶层的父元素
239
+ findRoot(dom: ParentNode): ParentNode | undefined {
240
+ if (dom.parentNode) {
241
+ return this.findRoot(dom.parentNode);
242
+ } else {
243
+ return dom;
244
+ }
245
+ }
246
+
247
+ // 是否自动渲染
248
+ autoRender = true;
249
+
250
+ //是否需要渲染, 当autoRender=false的时候就需要 手动触发渲染
251
+ needRender = false;
252
+
253
+ // 渲染场景
254
+ render() {
255
+
256
+ // 控制器在移动时鼠标不能操作
257
+ this.controls.enabled = (this.controlsPosition.isDone() || this.controlsCenter.isDone());
258
+
259
+ // canvas 没有在页面上面的话 就跳过渲染
260
+ if (this.findRoot(this.renderer.domElement) !== document) {
261
+ threeUtils.removeEventListener("requestAnimationFrame", this.renderBindThis);
262
+ this.renderer.forceContextLoss();
263
+ // 标记上下文被销毁了
264
+ this.isRendererContextLost = true;
265
+ this.resize(100, 100);
266
+ return;
267
+ }
268
+
269
+ // 分发鼠标事件
270
+ this.threeMouse.dispatchEvent();
271
+
272
+ // 在不自动渲染时, needRender=false 就跳过渲染
273
+ if (!this.autoRender && !this.needRender) {
274
+ return;
275
+ }
276
+ this.needRender = false;
277
+
278
+ if (this.controls.enabled) {
279
+ this.controls.update();
280
+ }
281
+
282
+ this.renderer.clear();
283
+
284
+ // 渲染场景
285
+ this.dispatchEvent({ type: "beforeRender" });
286
+ this.renderer.render(this.scene, this.camera);
287
+ this.dispatchEvent({ type: "afterRender" });
288
+ }
289
+
290
+ renderBindThis = this.render.bind(this);
291
+
292
+ // 清理渲染目标
293
+ clearRendererTargte(rendererTarget: WebGLRenderTarget | null) {
294
+ const originTarget = this.renderer.getRenderTarget();
295
+ this.renderer.setRenderTarget(rendererTarget);
296
+ fullScreenMesh.material = clearShader;
297
+ fullScreenMesh.render(this.renderer);
298
+ this.renderer.clearDepth();
299
+ this.renderer.setRenderTarget(originTarget);
300
+ }
301
+
302
+ // 拷贝纹理到渲染目标
303
+ copyTextureToRenderTarget(texture: Texture, rendererTarget: WebGLRenderTarget | null, alpha: boolean = false, opactity: number = 1) {
304
+ const originTarget = this.renderer.getRenderTarget();
305
+ if (rendererTarget) {
306
+ this.renderer.getSize(this.tempVector2);
307
+ rendererTarget.setSize(this.tempVector2.x, this.tempVector2.y);
308
+ }
309
+ this.renderer.setRenderTarget(rendererTarget);
310
+ fullScreenMesh.material = coptyShader;
311
+ coptyShader.uniforms.map.value = texture;
312
+ coptyShader.uniforms.opacity.value = opactity;
313
+ coptyShader.blending = alpha ? NoBlending : NormalBlending;
314
+ fullScreenMesh.render(this.renderer);
315
+ this.renderer.setRenderTarget(originTarget);
316
+ }
317
+
318
+ // 把对象绘制到渲染目标中
319
+ object3dToRendererTarget(obj: Object3D, rendererTarget: WebGLRenderTarget) {
320
+ this.clearRendererTargte(rendererTarget);
321
+ const originTarget = this.renderer.getRenderTarget();
322
+ this.renderer.setRenderTarget(rendererTarget);
323
+ this.renderer.getSize(this.tempVector2);
324
+ rendererTarget.setSize(this.tempVector2.x, this.tempVector2.y);
325
+ this.renderer.render(obj, this.camera);
326
+ this.renderer.setRenderTarget(originTarget);
327
+ }
328
+
329
+ // 给渲染目标的内容加描边
330
+ rendererTagetAddStroke(rendererTarget: WebGLRenderTarget, strockWidth: number, color: string, opacity: number) {
331
+ const originTarget = this.renderer.getRenderTarget();
332
+ this.clearRendererTargte(this.renderTarget2);
333
+ this.renderer.setRenderTarget(this.renderTarget2);
334
+ this.renderer.getSize(this.tempVector2);
335
+ this.renderTarget2.setSize(this.tempVector2.x, this.tempVector2.y);
336
+
337
+ fullScreenMesh.material = strokeShader;
338
+ strokeShader.uniforms.map.value = rendererTarget.texture;
339
+ strokeShader.uniforms.resolution.value.set(this.tempVector2.x, this.tempVector2.y);
340
+ strokeShader.uniforms.strokeWidth.value = strockWidth;
341
+ strokeShader.uniforms.strokeColor.value.set(color);
342
+ strokeShader.uniforms.opacity.value = opacity;
343
+ fullScreenMesh.render(this.renderer);
344
+
345
+ this.copyTextureToRenderTarget(this.renderTarget2.texture, rendererTarget, true);
346
+
347
+ this.renderer.setRenderTarget(originTarget);
348
+ }
349
+
350
+ // 渲染对象的描边
351
+ renderObject3dStroke(obj: Object3D, strockWidth: number, color: string, opacity: number) {
352
+ this.object3dToRendererTarget(obj, this.renderTarget);
353
+ this.rendererTagetAddStroke(this.renderTarget, strockWidth, color, opacity);
354
+ this.copyTextureToRenderTarget(this.renderTarget.texture, null);
355
+ }
356
+
357
+ //给渲染目标加上高斯模糊计算
358
+ renderTargetgaussBlur(rendererTarget: WebGLRenderTarget, radius: number, opacity: number) {
359
+ const originTarget = this.renderer.getRenderTarget();
360
+
361
+ this.clearRendererTargte(this.renderTarget2);
362
+ this.renderer.setRenderTarget(this.renderTarget2);
363
+ this.renderer.getSize(this.tempVector2);
364
+ this.renderTarget2.setSize(this.tempVector2.x, this.tempVector2.y);
365
+
366
+ fullScreenMesh.material = gaussBlurShader;
367
+ gaussBlurShader.uniforms.map.value = rendererTarget.texture;
368
+ gaussBlurShader.uniforms.radius.value = radius;
369
+ gaussBlurShader.uniforms.opacity.value = opacity;
370
+ gaussBlurShader.uniforms.resolution.value.set(this.tempVector2.x, this.tempVector2.y);
371
+ fullScreenMesh.render(this.renderer);
372
+
373
+ this.copyTextureToRenderTarget(this.renderTarget2.texture, rendererTarget, true);
374
+
375
+ this.renderer.setRenderTarget(originTarget);
376
+ }
377
+
378
+ // 渲染目标上的纹理添加辉光效果
379
+ renderTargetAddGlow(renderTarget: WebGLRenderTarget, width: number, color: string) {
380
+
381
+ this.rendererTagetAddStroke(renderTarget, 1 * width, color, 0.3);
382
+ this.rendererTagetAddStroke(renderTarget, 2 * width, color, 0.2);
383
+ this.rendererTagetAddStroke(renderTarget, 3 * width, color, 0.05);
384
+
385
+ this.renderTargetgaussBlur(renderTarget, 1, 1);
386
+ this.renderTargetgaussBlur(renderTarget, 1, 1);
387
+ this.renderTargetgaussBlur(renderTarget, 1, 1);
388
+ }
389
+
390
+ // 渲染 渲染目标
391
+ renderRendererTarget(renderTarget: WebGLRenderTarget, alpha: boolean = false) {
392
+ coptyShader.uniforms.map.value = renderTarget.texture;
393
+ coptyShader.uniforms.opacity.value = 1.0;
394
+ fullScreenMesh.material = coptyShader;
395
+ coptyShader.blending = alpha ? NoBlending : NormalBlending;
396
+ fullScreenMesh.render(this.renderer);
397
+ }
398
+
399
+ }