three-base 2.0.98 → 2.0.100
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/ThreeBase.d.ts +2 -2
- package/ThreeBase.js +111 -48
- package/package.json +1 -1
- package/pass/bool_pass.d.ts +0 -0
- package/pass/bool_pass.js +7 -0
- package/pass/cover_pass.d.ts +2 -0
- package/pass/cover_pass.js +124 -0
- package/pass/glow_pass.d.ts +1 -1
- package/pass/glow_pass.js +2 -2
- package/pass/stroke_pass.d.ts +1 -1
- package/pass/stroke_pass.js +2 -2
- package/shaders/copyShader.d.ts +3 -0
- package/shaders/copyShader.js +33 -0
- package/threeLoader.js +10 -3
package/ThreeBase.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
45
45
|
position: Vector3;
|
|
46
46
|
center: Vector3;
|
|
47
47
|
}): void;
|
|
48
|
-
setLookAt({ position, center, duration }: {
|
|
48
|
+
setLookAt({ position, center, duration, }: {
|
|
49
49
|
position: Vector3;
|
|
50
50
|
center: Vector3;
|
|
51
51
|
duration?: number;
|
|
@@ -55,7 +55,7 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
55
55
|
position: Vector3;
|
|
56
56
|
centerPosition: string;
|
|
57
57
|
};
|
|
58
|
-
lookatObjects({ objects, duration, direction, offset, distance }: {
|
|
58
|
+
lookatObjects({ objects, duration, direction, offset, distance, }: {
|
|
59
59
|
objects: Array<Object3D>;
|
|
60
60
|
duration?: number;
|
|
61
61
|
direction?: Vector3;
|
package/ThreeBase.js
CHANGED
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
* @Author: xiaosihan
|
|
3
3
|
* @Date: 2021-12-20 13:38:22
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time: 2024-
|
|
5
|
+
* @Last Modified time: 2024-09-23 21:20:32
|
|
6
6
|
*/
|
|
7
7
|
import { round } from "lodash";
|
|
8
|
-
import { AxesHelper, Box3, DepthFormat, DepthTexture, EventDispatcher, GridHelper, LinearFilter, MOUSE, Mesh, NoBlending, NormalBlending, OrthographicCamera, PerspectiveCamera, RGBAFormat, Scene, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
8
|
+
import { AxesHelper, Box3, DepthFormat, DepthTexture, EventDispatcher, GridHelper, LinearFilter, MOUSE, Mesh, NoBlending, NormalBlending, OrthographicCamera, PerspectiveCamera, RGBAFormat, SRGBColorSpace, Scene, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer, } from "three";
|
|
9
9
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
10
10
|
import { degToRad, generateUUID } from "three/src/math/MathUtils";
|
|
11
11
|
import ThreeMouse from "./ThreeMouse";
|
|
12
12
|
import Transition from "./Transition";
|
|
13
13
|
import glow_pass from "./pass/glow_pass";
|
|
14
14
|
import stroke_pass from "./pass/stroke_pass";
|
|
15
|
-
import { clearShader, coptyShader, fullScreenMesh, gaussBlurShader, strokeShader } from "./shaders";
|
|
15
|
+
import { clearShader, coptyShader, fullScreenMesh, gaussBlurShader, strokeShader, } from "./shaders";
|
|
16
16
|
import FXAAShaderMaterial from "./shaders/FXAAShaderMaterial";
|
|
17
17
|
import threeLoader from "./threeLoader";
|
|
18
18
|
import threeUtils from "./threeUtils";
|
|
19
|
+
import cover_pass from "./pass/cover_pass";
|
|
19
20
|
// three.js 的基础对象
|
|
20
21
|
export default class ThreeBase extends EventDispatcher {
|
|
21
22
|
constructor() {
|
|
@@ -56,9 +57,17 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
56
57
|
return baseRenderTarget;
|
|
57
58
|
})();
|
|
58
59
|
// 公用渲染目标1
|
|
59
|
-
renderTarget = new WebGLRenderTarget(128, 128, {
|
|
60
|
+
renderTarget = new WebGLRenderTarget(128, 128, {
|
|
61
|
+
minFilter: LinearFilter,
|
|
62
|
+
magFilter: LinearFilter,
|
|
63
|
+
format: RGBAFormat,
|
|
64
|
+
});
|
|
60
65
|
// 渲染目标2
|
|
61
|
-
renderTarget2 = new WebGLRenderTarget(128, 128, {
|
|
66
|
+
renderTarget2 = new WebGLRenderTarget(128, 128, {
|
|
67
|
+
minFilter: LinearFilter,
|
|
68
|
+
magFilter: LinearFilter,
|
|
69
|
+
format: RGBAFormat,
|
|
70
|
+
});
|
|
62
71
|
// 公用二维向量
|
|
63
72
|
tempVector2 = new Vector2();
|
|
64
73
|
// 公用的三维向量
|
|
@@ -79,17 +88,18 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
79
88
|
});
|
|
80
89
|
renderer.domElement.id = generateUUID();
|
|
81
90
|
//监听上下文的销毁事件
|
|
82
|
-
renderer.domElement.addEventListener(
|
|
91
|
+
renderer.domElement.addEventListener("webglcontextlost", (event) => {
|
|
83
92
|
this.rendererLost = true;
|
|
84
93
|
}, false);
|
|
85
94
|
// 监听上下文的恢复事件
|
|
86
|
-
renderer.domElement.addEventListener(
|
|
95
|
+
renderer.domElement.addEventListener("webglcontextrestored", (event) => {
|
|
87
96
|
this.rendererLost = false;
|
|
88
97
|
}, false);
|
|
89
98
|
renderer.localClippingEnabled = true;
|
|
90
99
|
renderer.setPixelRatio(window.devicePixelRatio);
|
|
91
100
|
renderer.autoClear = false;
|
|
92
101
|
renderer.clear();
|
|
102
|
+
renderer.outputColorSpace = SRGBColorSpace;
|
|
93
103
|
threeLoader.setAnisotropy(renderer.capabilities.getMaxAnisotropy());
|
|
94
104
|
return renderer;
|
|
95
105
|
})();
|
|
@@ -262,9 +272,8 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
262
272
|
return axesHelper;
|
|
263
273
|
})();
|
|
264
274
|
//TODO 设置帧频率 默认50帧
|
|
265
|
-
frame =
|
|
266
|
-
init() {
|
|
267
|
-
}
|
|
275
|
+
frame = 30;
|
|
276
|
+
init() { }
|
|
268
277
|
// 重置控制器的位置
|
|
269
278
|
resetLookAt({ position = this.perspectiveCamera.position, center = this.controls.target, }) {
|
|
270
279
|
// 停止控制器的惯性
|
|
@@ -273,13 +282,21 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
273
282
|
this.controls.update();
|
|
274
283
|
this.controls.reset();
|
|
275
284
|
this.controls.enableDamping = originEnableDamping;
|
|
276
|
-
this.controlsDistance.reset({
|
|
277
|
-
|
|
278
|
-
|
|
285
|
+
this.controlsDistance.reset({
|
|
286
|
+
distance: new Vector3(position.x, position.y, position.z).distanceTo(new Vector3(center.x, center.y, center.z)),
|
|
287
|
+
});
|
|
288
|
+
position &&
|
|
289
|
+
this.controlsPosition.reset({
|
|
290
|
+
x: position.x,
|
|
291
|
+
y: position.y,
|
|
292
|
+
z: position.z,
|
|
293
|
+
});
|
|
294
|
+
center &&
|
|
295
|
+
this.controlsCenter.reset({ x: center.x, y: center.y, z: center.z });
|
|
279
296
|
this.needRender = true;
|
|
280
297
|
}
|
|
281
298
|
// 设置控制器的位置 以动画的方式移动控制器
|
|
282
|
-
async setLookAt({ position = this.perspectiveCamera.position, center = this.controls.target, duration = 1000 }) {
|
|
299
|
+
async setLookAt({ position = this.perspectiveCamera.position, center = this.controls.target, duration = 1000, }) {
|
|
283
300
|
// 停止控制器的惯性
|
|
284
301
|
const originEnableDamping = this.controls.enableDamping;
|
|
285
302
|
this.controls.saveState();
|
|
@@ -291,38 +308,60 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
291
308
|
// 等待动画执行完成
|
|
292
309
|
await Promise.all([
|
|
293
310
|
new Promise(async (resolve, reject) => {
|
|
294
|
-
this.controlsDistance.setDuration(duration).reset({
|
|
295
|
-
|
|
311
|
+
this.controlsDistance.setDuration(duration).reset({
|
|
312
|
+
distance: this.perspectiveCamera.position.distanceTo(this.controls.target),
|
|
313
|
+
});
|
|
314
|
+
await this.controlsDistance.set({
|
|
315
|
+
distance: new Vector3(position.x, position.y, position.z).distanceTo(new Vector3(center.x, center.y, center.z)),
|
|
316
|
+
});
|
|
296
317
|
resolve();
|
|
297
318
|
}),
|
|
298
319
|
new Promise(async (resolve, reject) => {
|
|
299
|
-
this.controlsPosition.setDuration(duration).reset({
|
|
300
|
-
|
|
320
|
+
this.controlsPosition.setDuration(duration).reset({
|
|
321
|
+
x: currentPosition.x,
|
|
322
|
+
y: currentPosition.y,
|
|
323
|
+
z: currentPosition.z,
|
|
324
|
+
});
|
|
325
|
+
await this.controlsPosition.set({
|
|
326
|
+
x: position.x,
|
|
327
|
+
y: position.y,
|
|
328
|
+
z: position.z,
|
|
329
|
+
});
|
|
301
330
|
resolve();
|
|
302
331
|
}),
|
|
303
332
|
new Promise(async (resolve, reject) => {
|
|
304
|
-
this.controlsCenter.setDuration(duration).reset({
|
|
305
|
-
|
|
333
|
+
this.controlsCenter.setDuration(duration).reset({
|
|
334
|
+
x: currentCenter.x,
|
|
335
|
+
y: currentCenter.y,
|
|
336
|
+
z: currentCenter.z,
|
|
337
|
+
});
|
|
338
|
+
await this.controlsCenter.set({
|
|
339
|
+
x: center.x,
|
|
340
|
+
y: center.y,
|
|
341
|
+
z: center.z,
|
|
342
|
+
});
|
|
306
343
|
resolve();
|
|
307
|
-
})
|
|
344
|
+
}),
|
|
308
345
|
]);
|
|
309
346
|
}
|
|
310
347
|
// 获取控制的位置和朝向 保留3位小数
|
|
311
348
|
getLookAt() {
|
|
312
349
|
//判断需要使用那个相机
|
|
313
|
-
const position = this.perspectiveCamera.position
|
|
314
|
-
|
|
350
|
+
const position = this.perspectiveCamera.position
|
|
351
|
+
.toArray()
|
|
352
|
+
.map((v) => round(v, 3));
|
|
353
|
+
const center = this.controls.target.toArray().map((v) => round(v, 3));
|
|
315
354
|
return {
|
|
316
355
|
center: new Vector3(...center),
|
|
317
356
|
position: new Vector3(...position),
|
|
318
|
-
centerPosition: `center: new Vector3(${center.join(",")}),position: new Vector3(${position.join(",")})
|
|
357
|
+
centerPosition: `center: new Vector3(${center.join(",")}),position: new Vector3(${position.join(",")})`,
|
|
319
358
|
};
|
|
320
359
|
}
|
|
321
360
|
// 查看对象
|
|
322
|
-
lookatObjects({ objects, duration = 1000, direction = new Vector3(0.3, 0.3, 1), offset = new Vector3(0, 0, 0), distance = 1 }) {
|
|
361
|
+
lookatObjects({ objects, duration = 1000, direction = new Vector3(0.3, 0.3, 1), offset = new Vector3(0, 0, 0), distance = 1, }) {
|
|
323
362
|
const box3 = new Box3();
|
|
324
|
-
objects.map(o => {
|
|
325
|
-
o.
|
|
363
|
+
objects.map((o) => {
|
|
364
|
+
o.traverseVisible((oo) => {
|
|
326
365
|
box3.expandByObject(oo);
|
|
327
366
|
});
|
|
328
367
|
});
|
|
@@ -334,7 +373,7 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
334
373
|
const modelSize = size.length() * distance;
|
|
335
374
|
if (this.cameraType === "perspectiveCamera") {
|
|
336
375
|
const { fov } = this.getCamera();
|
|
337
|
-
const cameraDistance = modelSize / (2 * Math.tan(fov * Math.PI / 360));
|
|
376
|
+
const cameraDistance = modelSize / (2 * Math.tan((fov * Math.PI) / 360));
|
|
338
377
|
const position = direction.setLength(cameraDistance).add(center);
|
|
339
378
|
this.setLookAt({ center, position, duration });
|
|
340
379
|
}
|
|
@@ -355,7 +394,11 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
355
394
|
setControlType(controlType) {
|
|
356
395
|
if (controlType === "OrbitControls") {
|
|
357
396
|
this.controls.screenSpacePanning = this.originScreenSpacePanning;
|
|
358
|
-
this.controls.mouseButtons = {
|
|
397
|
+
this.controls.mouseButtons = {
|
|
398
|
+
LEFT: MOUSE.ROTATE,
|
|
399
|
+
MIDDLE: MOUSE.DOLLY,
|
|
400
|
+
RIGHT: MOUSE.PAN,
|
|
401
|
+
};
|
|
359
402
|
this.controls.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
|
|
360
403
|
}
|
|
361
404
|
else if (controlType === "MapControls") {
|
|
@@ -383,14 +426,18 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
383
426
|
}
|
|
384
427
|
// 判断是否有 发光和描边等对象 以便判断是否需要 渲染深度纹理
|
|
385
428
|
hasPass() {
|
|
386
|
-
let
|
|
387
|
-
this.scene.traverse(obj => {
|
|
388
|
-
const { stroke_enable = false, stroke_width = 1, glow_enable = false, glow_width = 1
|
|
389
|
-
|
|
390
|
-
|
|
429
|
+
let hasPass = false;
|
|
430
|
+
this.scene.traverse((obj) => {
|
|
431
|
+
const { stroke_enable = false, stroke_width = 1, glow_enable = false, glow_width = 1, cover_enable = false, //颜色覆盖
|
|
432
|
+
cover_opacity = 0, //透明度
|
|
433
|
+
} = obj.userData;
|
|
434
|
+
if ((stroke_enable && stroke_width > 0) ||
|
|
435
|
+
(glow_enable && glow_width > 0) ||
|
|
436
|
+
(cover_enable && cover_opacity > 0)) {
|
|
437
|
+
hasPass = true;
|
|
391
438
|
}
|
|
392
439
|
});
|
|
393
|
-
return
|
|
440
|
+
return hasPass;
|
|
394
441
|
}
|
|
395
442
|
// 渲染场景
|
|
396
443
|
render() {
|
|
@@ -403,23 +450,33 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
403
450
|
if (this.cameraType === "perspectiveCamera") {
|
|
404
451
|
const { center } = this.getLookAt();
|
|
405
452
|
const { fov } = this.perspectiveCamera;
|
|
406
|
-
const distaned = this.perspectiveCamera.position
|
|
453
|
+
const distaned = this.perspectiveCamera.position
|
|
454
|
+
.clone()
|
|
455
|
+
.sub(center)
|
|
456
|
+
.length();
|
|
407
457
|
const zoom = 1 / (Math.tan(degToRad(fov) / 2) * distaned);
|
|
408
458
|
this.orthographicCamera.zoom = zoom;
|
|
409
|
-
this.orthographicCamera.position
|
|
459
|
+
this.orthographicCamera.position
|
|
460
|
+
.copy(this.perspectiveCamera.position.clone().sub(center))
|
|
461
|
+
.setLength(2500)
|
|
462
|
+
.add(center);
|
|
410
463
|
}
|
|
411
464
|
else if (this.cameraType === "orthographicCamera") {
|
|
412
465
|
const { center } = this.getLookAt();
|
|
413
466
|
const { fov } = this.perspectiveCamera;
|
|
414
467
|
const { zoom } = this.orthographicCamera;
|
|
415
|
-
const distaned =
|
|
416
|
-
this.perspectiveCamera.position
|
|
468
|
+
const distaned = 1 / zoom / Math.tan(degToRad(fov) / 2);
|
|
469
|
+
this.perspectiveCamera.position
|
|
470
|
+
.copy(this.orthographicCamera.position.clone().sub(center))
|
|
471
|
+
.setLength(distaned)
|
|
472
|
+
.add(center);
|
|
417
473
|
}
|
|
418
474
|
//判断需要使用那个相机
|
|
419
475
|
const camera = this.getCamera();
|
|
420
476
|
//判断尺寸发生改变时重置尺寸
|
|
421
477
|
const parentNode = this.renderer.domElement.parentNode;
|
|
422
|
-
if (parentNode.clientWidth !== this.size.x ||
|
|
478
|
+
if (parentNode.clientWidth !== this.size.x ||
|
|
479
|
+
parentNode.clientHeight !== this.size.y) {
|
|
423
480
|
this.setSize(parentNode.clientWidth, parentNode.clientHeight);
|
|
424
481
|
}
|
|
425
482
|
// 分发鼠标事件
|
|
@@ -447,9 +504,10 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
447
504
|
this.renderer.render(this.scene, camera);
|
|
448
505
|
if (hasPass) {
|
|
449
506
|
// 查找需要绘制描边的对象,并且绘制描边
|
|
450
|
-
this.scene.traverseVisible(obj => {
|
|
507
|
+
this.scene.traverseVisible((obj) => {
|
|
451
508
|
stroke_pass(this.renderer, camera, obj, this.baseDepthTexture);
|
|
452
509
|
glow_pass(this.renderer, camera, obj, this.baseDepthTexture);
|
|
510
|
+
cover_pass(this.renderer, camera, obj, this.baseDepthTexture);
|
|
453
511
|
});
|
|
454
512
|
}
|
|
455
513
|
this.dispatchEvent({ type: "afterRender" });
|
|
@@ -459,7 +517,7 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
459
517
|
async getThumbBlob() {
|
|
460
518
|
this.render();
|
|
461
519
|
const blob = await new Promise((resolve, reject) => {
|
|
462
|
-
this.renderer.domElement.toBlob(blob => {
|
|
520
|
+
this.renderer.domElement.toBlob((blob) => {
|
|
463
521
|
resolve(blob);
|
|
464
522
|
}, "image/png", 1);
|
|
465
523
|
});
|
|
@@ -468,20 +526,20 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
468
526
|
//获取渲染图base64
|
|
469
527
|
getThumbBase64() {
|
|
470
528
|
this.render();
|
|
471
|
-
const base64 = this.renderer.domElement.toDataURL(
|
|
529
|
+
const base64 = this.renderer.domElement.toDataURL("image/png");
|
|
472
530
|
return base64;
|
|
473
531
|
}
|
|
474
532
|
//获取渲染图文件对象
|
|
475
533
|
async getThumbFile() {
|
|
476
534
|
const blob = await this.getThumbBlob();
|
|
477
|
-
const file = new File([blob],
|
|
535
|
+
const file = new File([blob], "thumb.png", { type: blob.type });
|
|
478
536
|
return file;
|
|
479
537
|
}
|
|
480
538
|
// 下载渲染图
|
|
481
539
|
async download(fileName = "download") {
|
|
482
540
|
this.render();
|
|
483
541
|
const blob = await this.getThumbBlob();
|
|
484
|
-
const base64 = this.renderer.domElement.toDataURL(
|
|
542
|
+
const base64 = this.renderer.domElement.toDataURL("image/png");
|
|
485
543
|
let saveLink = document.createElement("a");
|
|
486
544
|
saveLink.download = `${fileName}.png`;
|
|
487
545
|
saveLink.href = URL.createObjectURL(blob);
|
|
@@ -489,12 +547,17 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
489
547
|
saveLink.click();
|
|
490
548
|
}
|
|
491
549
|
_preMesh = new Mesh();
|
|
492
|
-
_preRT = new WebGLRenderTarget(128, 128, {
|
|
550
|
+
_preRT = new WebGLRenderTarget(128, 128, {
|
|
551
|
+
minFilter: LinearFilter,
|
|
552
|
+
magFilter: LinearFilter,
|
|
553
|
+
format: RGBAFormat,
|
|
554
|
+
});
|
|
493
555
|
//预加载纹理图片
|
|
494
556
|
async preloadTexture(src) {
|
|
495
557
|
const texture = threeLoader.getTexture(src);
|
|
496
|
-
while (texture && !texture.image ||
|
|
497
|
-
|
|
558
|
+
while ((texture && !texture.image) ||
|
|
559
|
+
!texture.image.complete) {
|
|
560
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
498
561
|
}
|
|
499
562
|
// 添加到计划任务中去
|
|
500
563
|
threeUtils.addWork(() => {
|
package/package.json
CHANGED
|
File without changes
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2024-09-23 21:07:06
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2024-09-23 21:53:12
|
|
6
|
+
*/
|
|
7
|
+
/*
|
|
8
|
+
* @Author: xiaosihan
|
|
9
|
+
* @Date: 2023-05-09 00:35:17
|
|
10
|
+
* @Last Modified by: xiaosihan
|
|
11
|
+
* @Last Modified time: 2023-05-09 02:33:28
|
|
12
|
+
*/
|
|
13
|
+
import { Color, DepthFormat, DepthTexture, LinearFilter, NoBlending, RGBAFormat, Scene, ShaderChunk, ShaderMaterial, UnsignedShortType, Vector2, WebGLRenderTarget } from "three";
|
|
14
|
+
import copyShader from "../shaders/copyShader";
|
|
15
|
+
import FullScreenQuad from "./FullScreenQuad";
|
|
16
|
+
// 选中对象的深度纹理
|
|
17
|
+
const selectDepthTexture = (() => {
|
|
18
|
+
const baseDepthTexture = new DepthTexture(4096, 4096);
|
|
19
|
+
baseDepthTexture.format = DepthFormat;
|
|
20
|
+
baseDepthTexture.type = UnsignedShortType;
|
|
21
|
+
baseDepthTexture.anisotropy = 16;
|
|
22
|
+
return baseDepthTexture;
|
|
23
|
+
})();
|
|
24
|
+
// 选中对象的纹理
|
|
25
|
+
const selectTextureTarget = new WebGLRenderTarget(512, 512, {
|
|
26
|
+
minFilter: LinearFilter,
|
|
27
|
+
magFilter: LinearFilter,
|
|
28
|
+
format: RGBAFormat,
|
|
29
|
+
depthTexture: selectDepthTexture,
|
|
30
|
+
anisotropy: 16,
|
|
31
|
+
});
|
|
32
|
+
// 深度测试后的选中纹理
|
|
33
|
+
const selectDethpTestTextureTarget = new WebGLRenderTarget(512, 512, {
|
|
34
|
+
minFilter: LinearFilter,
|
|
35
|
+
magFilter: LinearFilter,
|
|
36
|
+
format: RGBAFormat,
|
|
37
|
+
anisotropy: 16,
|
|
38
|
+
});
|
|
39
|
+
const blur1TextureTarget = new WebGLRenderTarget(512, 512, {
|
|
40
|
+
minFilter: LinearFilter,
|
|
41
|
+
magFilter: LinearFilter,
|
|
42
|
+
format: RGBAFormat,
|
|
43
|
+
});
|
|
44
|
+
const size = new Vector2();
|
|
45
|
+
// 创建一个渲染工具 用于处理纹理
|
|
46
|
+
const fsQuad = new FullScreenQuad(); // 渲染辅助器
|
|
47
|
+
//深度比对纹理
|
|
48
|
+
const depthTestShader = new ShaderMaterial({
|
|
49
|
+
uniforms: {
|
|
50
|
+
color: { value: new Color("#000000") },
|
|
51
|
+
baseDepth: { value: null },
|
|
52
|
+
selectDepth: { value: null }, // 选中的对象深度纹理
|
|
53
|
+
},
|
|
54
|
+
vertexShader: `
|
|
55
|
+
${ShaderChunk.common}
|
|
56
|
+
${ShaderChunk.logdepthbuf_pars_vertex}
|
|
57
|
+
varying vec2 vUv;
|
|
58
|
+
void main() {
|
|
59
|
+
vUv = uv;
|
|
60
|
+
// gl_Position = vec4(position, 1.0);
|
|
61
|
+
// gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position, 1.0);
|
|
62
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
63
|
+
${ShaderChunk.logdepthbuf_vertex}
|
|
64
|
+
}
|
|
65
|
+
`,
|
|
66
|
+
fragmentShader: `
|
|
67
|
+
${ShaderChunk.logdepthbuf_pars_fragment}
|
|
68
|
+
uniform vec3 color;
|
|
69
|
+
uniform sampler2D baseDepth;
|
|
70
|
+
uniform sampler2D selectDepth;
|
|
71
|
+
varying vec2 vUv;
|
|
72
|
+
void main() {
|
|
73
|
+
if(texture2D(baseDepth, vUv).r + 0.0001 < texture2D(selectDepth, vUv).r){
|
|
74
|
+
discard;
|
|
75
|
+
}
|
|
76
|
+
gl_FragColor = vec4(color, 1.0);
|
|
77
|
+
${ShaderChunk.logdepthbuf_fragment}
|
|
78
|
+
}
|
|
79
|
+
`,
|
|
80
|
+
blending: NoBlending,
|
|
81
|
+
depthTest: true,
|
|
82
|
+
depthWrite: true,
|
|
83
|
+
transparent: true,
|
|
84
|
+
});
|
|
85
|
+
// 场景对象
|
|
86
|
+
const scene = new Scene();
|
|
87
|
+
// 给模型覆盖一层颜色 后处理通道
|
|
88
|
+
export default function cover_pass(renderer, camera, object3d, baseDepthTexture) {
|
|
89
|
+
const { cover_enable = false, cover_color = "#04fa12", cover_opacity = 1, } = object3d.userData;
|
|
90
|
+
if (!cover_enable || cover_opacity === 0) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// 保存原帧缓冲区
|
|
94
|
+
const originRenderTarget = renderer.getRenderTarget();
|
|
95
|
+
// 设置选中目标的帧缓冲区
|
|
96
|
+
renderer.getSize(size);
|
|
97
|
+
size.multiplyScalar(window.devicePixelRatio);
|
|
98
|
+
selectTextureTarget.setSize(size.x, size.y);
|
|
99
|
+
selectDethpTestTextureTarget.setSize(size.x, size.y);
|
|
100
|
+
blur1TextureTarget.setSize(size.x, size.y);
|
|
101
|
+
renderer.setRenderTarget(selectTextureTarget);
|
|
102
|
+
scene.children = [object3d];
|
|
103
|
+
renderer.clear();
|
|
104
|
+
renderer.render(scene, camera);
|
|
105
|
+
//深度测试
|
|
106
|
+
renderer.setRenderTarget(selectDethpTestTextureTarget);
|
|
107
|
+
renderer.clear();
|
|
108
|
+
depthTestShader.uniforms.color.value.set(cover_color);
|
|
109
|
+
depthTestShader.uniforms.baseDepth.value = baseDepthTexture;
|
|
110
|
+
depthTestShader.uniforms.selectDepth.value = selectDepthTexture;
|
|
111
|
+
fsQuad.render(renderer, depthTestShader);
|
|
112
|
+
// 颜色覆盖绘制到着色器
|
|
113
|
+
renderer.setRenderTarget(originRenderTarget);
|
|
114
|
+
renderer.clearDepth();
|
|
115
|
+
copyShader.uniforms.map.value = selectDethpTestTextureTarget.texture;
|
|
116
|
+
copyShader.uniforms.opacity.value = cover_opacity;
|
|
117
|
+
fsQuad.render(renderer, copyShader);
|
|
118
|
+
// 调试代码
|
|
119
|
+
// renderer.setRenderTarget(null);
|
|
120
|
+
// renderer.clearDepth();
|
|
121
|
+
// copyShader.uniforms.tDiffuse.value = blur2TextureTarget.texture;
|
|
122
|
+
// fsQuad.render(renderer, copyShader);
|
|
123
|
+
// return;
|
|
124
|
+
}
|
package/pass/glow_pass.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Camera, Object3D, WebGLRenderer
|
|
1
|
+
import { Camera, DepthTexture, Object3D, WebGLRenderer } from "three";
|
|
2
2
|
export default function glow_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture): void;
|
package/pass/glow_pass.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* @Author: xiaosihan
|
|
3
3
|
* @Date: 2023-05-09 00:35:17
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time:
|
|
5
|
+
* @Last Modified time: 2024-09-23 22:00:48
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { Color, DepthFormat, DepthTexture, LinearFilter, NoBlending, NormalBlending, RGBAFormat, RawShaderMaterial, Scene, ShaderChunk, ShaderMaterial, UnsignedShortType, Vector2, WebGLRenderTarget } from "three";
|
|
8
8
|
import FullScreenQuad from "./FullScreenQuad";
|
|
9
9
|
// 选中对象的深度纹理
|
|
10
10
|
const selectDepthTexture = (() => {
|
package/pass/stroke_pass.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Camera, Object3D, WebGLRenderer
|
|
1
|
+
import { Camera, DepthTexture, Object3D, WebGLRenderer } from "three";
|
|
2
2
|
export default function stroke_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture): void;
|
package/pass/stroke_pass.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* @Author: xiaosihan
|
|
3
3
|
* @Date: 2023-05-09 00:35:17
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time:
|
|
5
|
+
* @Last Modified time: 2024-09-23 22:00:54
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { Color, DepthFormat, DepthTexture, LinearFilter, NoBlending, NormalBlending, RGBAFormat, RawShaderMaterial, Scene, ShaderChunk, ShaderMaterial, UnsignedShortType, Vector2, WebGLRenderTarget } from "three";
|
|
8
8
|
import FullScreenQuad from "./FullScreenQuad";
|
|
9
9
|
// 选中对象的深度纹理
|
|
10
10
|
const selectDepthTexture = (() => {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ShaderChunk, ShaderMaterial } from "three";
|
|
2
|
+
// 拷贝着色器
|
|
3
|
+
const copyShader = new ShaderMaterial({
|
|
4
|
+
uniforms: {
|
|
5
|
+
map: { value: null },
|
|
6
|
+
opacity: { value: 1 }, // 透明度
|
|
7
|
+
},
|
|
8
|
+
vertexShader: `
|
|
9
|
+
${ShaderChunk.common}
|
|
10
|
+
${ShaderChunk.logdepthbuf_pars_vertex}
|
|
11
|
+
varying vec2 vUv;
|
|
12
|
+
void main() {
|
|
13
|
+
vUv = uv;
|
|
14
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
15
|
+
${ShaderChunk.logdepthbuf_vertex}
|
|
16
|
+
}
|
|
17
|
+
`,
|
|
18
|
+
fragmentShader: `
|
|
19
|
+
${ShaderChunk.logdepthbuf_pars_fragment}
|
|
20
|
+
uniform float opacity;
|
|
21
|
+
uniform sampler2D map;
|
|
22
|
+
varying vec2 vUv;
|
|
23
|
+
void main() {
|
|
24
|
+
gl_FragColor = texture2D(map, vUv);
|
|
25
|
+
gl_FragColor.a *= opacity;
|
|
26
|
+
${ShaderChunk.logdepthbuf_fragment}
|
|
27
|
+
}
|
|
28
|
+
`,
|
|
29
|
+
depthTest: true,
|
|
30
|
+
depthWrite: true,
|
|
31
|
+
transparent: true,
|
|
32
|
+
});
|
|
33
|
+
export default copyShader;
|
package/threeLoader.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
5
|
* @Last Modified time: 2024-09-11 11:43:31
|
|
6
6
|
*/
|
|
7
|
-
import { CanvasTexture, DefaultLoadingManager, EventDispatcher, Mesh, MeshStandardMaterial, RepeatWrapping, TextureLoader, VideoTexture, } from "three";
|
|
7
|
+
import { CanvasTexture, DefaultLoadingManager, EventDispatcher, Mesh, MeshStandardMaterial, RepeatWrapping, SRGBColorSpace, TextureLoader, VideoTexture, } from "three";
|
|
8
8
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
|
9
9
|
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
|
|
10
10
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
@@ -26,6 +26,8 @@ import { isArray, isEmpty, isNull, isString, isUndefined } from "lodash";
|
|
|
26
26
|
import { generateUUID } from "three/src/math/MathUtils";
|
|
27
27
|
import dracoDecoderWASM from "./lib/draco/draco_decoder.wasm?url";
|
|
28
28
|
import threeUtils from "./threeUtils";
|
|
29
|
+
import { TGALoader } from "three/examples/jsm/Addons.js";
|
|
30
|
+
DefaultLoadingManager.addHandler(/tga$/, new TGALoader());
|
|
29
31
|
// 加载器
|
|
30
32
|
class ThreeLoader extends EventDispatcher {
|
|
31
33
|
constructor() {
|
|
@@ -76,7 +78,7 @@ class ThreeLoader extends EventDispatcher {
|
|
|
76
78
|
const canvasTexture = new CanvasTexture(src);
|
|
77
79
|
canvasTexture.wrapS = canvasTexture.wrapT = RepeatWrapping;
|
|
78
80
|
canvasTexture.anisotropy = this.anisotropy;
|
|
79
|
-
|
|
81
|
+
canvasTexture.colorSpace = SRGBColorSpace;
|
|
80
82
|
return canvasTexture;
|
|
81
83
|
}
|
|
82
84
|
let texture = this.textureMap.get(src);
|
|
@@ -110,7 +112,7 @@ class ThreeLoader extends EventDispatcher {
|
|
|
110
112
|
}
|
|
111
113
|
texture.wrapS = texture.wrapT = RepeatWrapping;
|
|
112
114
|
texture.anisotropy = this.anisotropy;
|
|
113
|
-
|
|
115
|
+
texture.colorSpace = SRGBColorSpace;
|
|
114
116
|
return texture;
|
|
115
117
|
}
|
|
116
118
|
// 资源列表
|
|
@@ -344,6 +346,11 @@ class ThreeLoader extends EventDispatcher {
|
|
|
344
346
|
if (stl) {
|
|
345
347
|
return await this.loadModel(stl);
|
|
346
348
|
}
|
|
349
|
+
//如果有zip文件就加载zip文件
|
|
350
|
+
let zipFile = Object.keys(zip.files).find((filename) => /\.stl$/.test(filename));
|
|
351
|
+
if (zipFile) {
|
|
352
|
+
return await this.loadModel(zipFile);
|
|
353
|
+
}
|
|
347
354
|
if ([obj, gltf, dae, fbx, usdz, stl].every((v) => !v)) {
|
|
348
355
|
throw new Error(`${url}压缩包里没有obj.glb.gltf.dae.fbx.usde.stl等模型文件`);
|
|
349
356
|
}
|