three-base 2.0.117 → 2.0.119

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/FPScontrol.js CHANGED
@@ -124,7 +124,6 @@ export default class FPScontrol extends EventDispatcher {
124
124
  this.playerCollider.translate(deltaPosition);
125
125
  this.playerCollisions();
126
126
  this.camera.position.copy(this.playerCollider.end);
127
- this.camera.position.y += 1;
128
127
  this.camera.rotation.x = clamp(this.camera.rotation.x, degToRad(-20), degToRad(20));
129
128
  };
130
129
  // 玩家的碰撞检测
@@ -25,8 +25,6 @@ declare class PathGeometry extends BufferGeometry {
25
25
  * @param {Boolean} [generateUv2=false]
26
26
  */
27
27
  constructor(initData: PathGeometryParam, generateUv2?: boolean);
28
- computeBoundsTree: any;
29
- disposeBoundsTree: any;
30
28
  _initByMaxVertex(maxVertex: number, generateUv2: boolean): void;
31
29
  _initByData(pathPointList: PathPointList, options: Options, usage: Usage, generateUv2: boolean): void;
32
30
  /**
@@ -3,7 +3,6 @@ import { PathPoint } from './PathPoint.js';
3
3
  import { BufferGeometry } from 'three/src/core/BufferGeometry.js';
4
4
  import { BufferAttribute } from 'three/src/core/BufferAttribute.js';
5
5
  import { Vector3 } from 'three/src/math/Vector3.js';
6
- import { computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh';
7
6
  /**
8
7
  * PathGeometry
9
8
  */
@@ -16,8 +15,6 @@ class PathGeometry extends BufferGeometry {
16
15
  super();
17
16
  this._initByData(initData.pathPointList, initData.options, initData.usage, generateUv2);
18
17
  }
19
- computeBoundsTree = computeBoundsTree.bind(this);
20
- disposeBoundsTree = disposeBoundsTree.bind(this);
21
18
  _initByMaxVertex(maxVertex, generateUv2) {
22
19
  this.setAttribute('position', new BufferAttribute(new Float32Array(maxVertex * 3), 3).setUsage(DynamicDrawUsage));
23
20
  this.setAttribute('normal', new BufferAttribute(new Float32Array(maxVertex * 3), 3).setUsage(DynamicDrawUsage));
package/ThreeBase.d.ts CHANGED
@@ -4,6 +4,7 @@ import ThreeMouse from "./ThreeMouse";
4
4
  import Transition from "./Transition";
5
5
  export default class ThreeBase extends EventDispatcher {
6
6
  constructor();
7
+ devicePixelRatio: number;
7
8
  baseDepthTexture: DepthTexture;
8
9
  baseRenderTarget: WebGLRenderTarget<Texture>;
9
10
  renderTarget: WebGLRenderTarget<Texture>;
@@ -69,7 +70,6 @@ export default class ThreeBase extends EventDispatcher {
69
70
  autoRender: boolean;
70
71
  needRender: boolean;
71
72
  stopRender(): void;
72
- hasPass(): boolean;
73
73
  render(): void;
74
74
  private renderBindThis;
75
75
  getThumbBlob(): Promise<Blob>;
package/ThreeBase.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2021-12-20 13:38:22
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2025-01-17 11:07:38
5
+ * @Last Modified time: 2025-01-28 04:26:41
6
6
  */
7
7
  import { round } from "lodash";
8
8
  import { AxesHelper, Box3, DepthFormat, DepthTexture, EventDispatcher, GridHelper, LinearFilter, MOUSE, NoBlending, NormalBlending, OrthographicCamera, PerspectiveCamera, RGBAFormat, ReinhardToneMapping, SRGBColorSpace, Scene, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer, } from "three";
@@ -14,10 +14,11 @@ import bloom_pass from "./pass/bloom_pass";
14
14
  import cover_pass from "./pass/cover_pass";
15
15
  import glow_pass from "./pass/glow_pass";
16
16
  import stroke_pass from "./pass/stroke_pass";
17
- import { copyShader, fullScreenMesh } from "./shaders";
17
+ import { copyShader } from "./shaders";
18
18
  import { baseTextureToRenderShader } from "./shaders/baseTextureToRenderShader";
19
19
  import threeLoader from "./threeLoader";
20
20
  import threeUtils from "./threeUtils";
21
+ import fsQuad from "./pass/fsQuad";
21
22
  // three.js 的基础对象
22
23
  export default class ThreeBase extends EventDispatcher {
23
24
  constructor() {
@@ -37,6 +38,8 @@ export default class ThreeBase extends EventDispatcher {
37
38
  });
38
39
  this.init();
39
40
  }
41
+ // 设置分辨率
42
+ devicePixelRatio = Math.max(window.devicePixelRatio, 2);
40
43
  // 基础深度纹理
41
44
  baseDepthTexture = (() => {
42
45
  const baseDepthTexture = new DepthTexture(4096, 4096);
@@ -98,7 +101,7 @@ export default class ThreeBase extends EventDispatcher {
98
101
  this.rendererLost = false;
99
102
  }, false);
100
103
  renderer.localClippingEnabled = true;
101
- renderer.setPixelRatio(window.devicePixelRatio);
104
+ renderer.setPixelRatio(this.devicePixelRatio);
102
105
  renderer.autoClear = false;
103
106
  renderer.clear();
104
107
  renderer.outputColorSpace = SRGBColorSpace;
@@ -191,13 +194,13 @@ export default class ThreeBase extends EventDispatcher {
191
194
  // this.orthographicCamera.bottom = -height / width;
192
195
  this.orthographicCamera.left = -width / height;
193
196
  this.orthographicCamera.right = width / height;
194
- this.renderer.setPixelRatio(window.devicePixelRatio);
197
+ this.renderer.setPixelRatio(this.devicePixelRatio);
195
198
  this.renderer.setSize(width, height);
196
199
  // 设置帧缓存区的尺寸
197
- this.baseRenderTarget.setSize(width * window.devicePixelRatio, height * window.devicePixelRatio);
200
+ this.baseRenderTarget.setSize(width * this.devicePixelRatio, height * this.devicePixelRatio);
198
201
  // 设置深度纹理的尺寸
199
- this.baseDepthTexture.image.width = width * window.devicePixelRatio;
200
- this.baseDepthTexture.image.height = height * window.devicePixelRatio;
202
+ this.baseDepthTexture.image.width = width * this.devicePixelRatio;
203
+ this.baseDepthTexture.image.height = height * this.devicePixelRatio;
201
204
  this.size.set(width, height);
202
205
  setTimeout(() => {
203
206
  this.needRender = true;
@@ -428,23 +431,6 @@ export default class ThreeBase extends EventDispatcher {
428
431
  this.renderer.domElement.style.opacity = "0";
429
432
  }
430
433
  }
431
- //判断是否有特效
432
- hasPass() {
433
- let hasPass = false;
434
- this.scene.traverseVisible((obj) => {
435
- const { stroke_enable = false, stroke_width = 1, glow_enable = false, glow_width = 1, cover_enable = false, cover_opacity = 1, } = obj.userData;
436
- if (stroke_enable && stroke_width > 0) {
437
- hasPass = true;
438
- }
439
- if (glow_enable && glow_width > 0) {
440
- hasPass = true;
441
- }
442
- if (cover_enable && cover_opacity > 0) {
443
- hasPass = true;
444
- }
445
- });
446
- return hasPass;
447
- }
448
434
  // 渲染场景
449
435
  render() {
450
436
  // canvas 没有在页面上面的话 就停止渲染
@@ -497,31 +483,22 @@ export default class ThreeBase extends EventDispatcher {
497
483
  }
498
484
  // 渲染场景
499
485
  this.dispatchEvent({ type: "beforeRender" });
500
- const hasPass = this.hasPass();
501
486
  // 把基础场景渲染到 帧缓冲区 在后期通道中会用到
502
- if (hasPass) {
503
- this.renderer.setRenderTarget(this.baseRenderTarget);
504
- this.renderer.clear();
505
- this.renderer.render(this.scene, camera);
506
- // 后处理特效渲染(描边,发光,颜色覆盖,磨砂玻璃,bloom)
507
- this.scene.traverseVisible((obj) => {
508
- stroke_pass(this.renderer, camera, obj, this.baseDepthTexture);
509
- glow_pass(this.renderer, camera, obj, this.baseDepthTexture);
510
- });
511
- this.renderer.setRenderTarget(null);
512
- this.renderer.clear();
513
- this.renderRendererTarget(this.baseRenderTarget);
514
- this.scene.traverseVisible((obj) => {
515
- cover_pass(this.renderer, camera, obj, this.baseDepthTexture);
516
- });
517
- //后处理发光特效
518
- bloom_pass(this.renderer, camera, this.scene, this.baseDepthTexture);
519
- }
520
- else {
521
- this.renderer.setRenderTarget(null);
522
- this.renderer.clear();
523
- this.renderer.render(this.scene, camera);
524
- }
487
+ this.renderer.setRenderTarget(this.baseRenderTarget);
488
+ this.renderer.clear();
489
+ this.renderer.render(this.scene, camera);
490
+ // 后处理特效渲染(描边,发光,颜色覆盖,bloom,磨砂玻璃)
491
+ this.scene.traverseVisible((obj) => {
492
+ stroke_pass(this.renderer, camera, obj, this.baseDepthTexture, this.devicePixelRatio);
493
+ glow_pass(this.renderer, camera, obj, this.baseDepthTexture, this.devicePixelRatio);
494
+ bloom_pass(this.renderer, camera, obj, this.baseRenderTarget, this.baseDepthTexture, this.devicePixelRatio);
495
+ });
496
+ this.renderer.setRenderTarget(null);
497
+ this.renderer.clear();
498
+ this.renderRendererTarget(this.baseRenderTarget);
499
+ this.scene.traverseVisible((obj) => {
500
+ cover_pass(this.renderer, camera, obj, this.baseDepthTexture, this.devicePixelRatio);
501
+ });
525
502
  this.dispatchEvent({ type: "afterRender" });
526
503
  }
527
504
  renderBindThis = this.render.bind(this);
@@ -570,13 +547,13 @@ export default class ThreeBase extends EventDispatcher {
570
547
  renderRendererTarget(renderTarget) {
571
548
  baseTextureToRenderShader.uniforms.resolution.value.set(1 / this.size.x, 1 / this.size.y);
572
549
  baseTextureToRenderShader.uniforms.tDiffuse.value = renderTarget.texture;
573
- fullScreenMesh.render(this.renderer, baseTextureToRenderShader);
550
+ fsQuad.render(this.renderer, baseTextureToRenderShader);
574
551
  }
575
552
  // 渲染纹理
576
553
  renderTexture(texture, alpha = false) {
577
554
  copyShader.uniforms.map.value = texture;
578
555
  copyShader.uniforms.opacity.value = 1.0;
579
556
  copyShader.blending = alpha ? NoBlending : NormalBlending;
580
- fullScreenMesh.render(this.renderer, copyShader);
557
+ fsQuad.render(this.renderer, copyShader);
581
558
  }
582
559
  }
package/ThreeMouse.js CHANGED
@@ -7,7 +7,7 @@
7
7
  import { Raycaster, Vector2 } from "three";
8
8
  import { Mesh } from "three";
9
9
  import { debounce } from "lodash";
10
- import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast, } from "three-mesh-bvh";
10
+ import { computeBoundsTree, acceleratedRaycast, } from "three-mesh-bvh";
11
11
  // Add the extension functions
12
12
  Mesh.prototype.raycast = acceleratedRaycast;
13
13
  /**
@@ -115,9 +115,12 @@ export default class ThreeMouse {
115
115
  "mousedown",
116
116
  "mouseup",
117
117
  ])) {
118
- if (mesh.isMesh && !mesh.geometry.boundsTree) {
118
+ if (mesh.isMesh &&
119
+ !mesh.geometry.boundsTree &&
120
+ mesh.geometry.attributes.position &&
121
+ mesh.geometry.attributes.position.count > 0) {
119
122
  computeBoundsTree.apply(mesh.geometry);
120
- disposeBoundsTree.apply(mesh.geometry);
123
+ // disposeBoundsTree.apply((mesh as Mesh).geometry);
121
124
  }
122
125
  meshs.push(mesh);
123
126
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-base",
3
- "version": "2.0.117",
3
+ "version": "2.0.119",
4
4
  "description": "three 3d three-base",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -1,2 +1,2 @@
1
- import { WebGLRenderer, Camera, DepthTexture, Scene } from "three";
2
- export default function bloom_pass(renderer: WebGLRenderer, camera: Camera, scene: Scene, baseDepthTexture: DepthTexture): void;
1
+ import { WebGLRenderer, Camera, Object3D, DepthTexture, WebGLRenderTarget } from "three";
2
+ export default function bloom_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseRenderTarget: WebGLRenderTarget, baseDepthTexture: DepthTexture, devicePixelRatio: number): void;
@@ -1,10 +1,13 @@
1
1
  /*
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2024-09-23 21:51:29
4
- * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2024-09-23 21:51:29
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2025-01-28 05:05:49
6
6
  */
7
- import { DepthTexture, DepthFormat, LinearFilter, RGBAFormat, UnsignedShortType, WebGLRenderTarget, } from "three";
7
+ import { DepthTexture, DepthFormat, LinearFilter, RGBAFormat, UnsignedShortType, WebGLRenderTarget, Scene, Vector2, ShaderChunk, NoBlending, ShaderMaterial, AdditiveBlending, } from "three";
8
+ import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
9
+ import copyShader from "../shaders/copyShader";
10
+ import fsQuad from "./fsQuad";
8
11
  // 选中对象的深度纹理
9
12
  const selectDepthTexture = (() => {
10
13
  const baseDepthTexture = new DepthTexture(4096, 4096);
@@ -28,6 +31,95 @@ const selectDethpTestTextureTarget = new WebGLRenderTarget(512, 512, {
28
31
  format: RGBAFormat,
29
32
  anisotropy: 16,
30
33
  });
34
+ //深度比对纹理
35
+ const depthTestShader = new ShaderMaterial({
36
+ uniforms: {
37
+ map: { value: null },
38
+ baseDepth: { value: null },
39
+ selectDepth: { value: null }, // 选中的对象深度纹理
40
+ },
41
+ vertexShader: `
42
+ ${ShaderChunk.common}
43
+ ${ShaderChunk.logdepthbuf_pars_vertex}
44
+ varying vec2 vUv;
45
+ void main() {
46
+ vUv = uv;
47
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
48
+ ${ShaderChunk.logdepthbuf_vertex}
49
+ }
50
+ `,
51
+ fragmentShader: `
52
+ ${ShaderChunk.logdepthbuf_pars_fragment}
53
+ uniform sampler2D map;
54
+ uniform sampler2D baseDepth;
55
+ uniform sampler2D selectDepth;
56
+ varying vec2 vUv;
57
+ void main() {
58
+ if(texture2D(baseDepth, vUv).r < texture2D(selectDepth, vUv).r){
59
+ discard;
60
+ }
61
+ if(texture2D(baseDepth, vUv).r == 1.0){
62
+ discard;
63
+ }
64
+ gl_FragColor = texture2D(map, vUv);
65
+ ${ShaderChunk.logdepthbuf_fragment}
66
+ }
67
+ `,
68
+ blending: NoBlending,
69
+ depthTest: true,
70
+ depthWrite: true,
71
+ transparent: true,
72
+ });
73
+ const blendMaterial = copyShader.clone();
74
+ blendMaterial.blending = AdditiveBlending;
75
+ const size = new Vector2();
76
+ // 场景对象
77
+ const scene = new Scene();
78
+ const bloomPass = new UnrealBloomPass(new Vector2(1024, 1024), 1.5, 0.4, 0.85);
79
+ // bloomPass.threshold = params.threshold;
80
+ // bloomPass.strength = params.strength;
81
+ // bloomPass.radius = params.radius;
31
82
  // 发光后期通道
32
- export default function bloom_pass(renderer, camera, scene, baseDepthTexture) {
83
+ export default function bloom_pass(renderer, camera, object3d, baseRenderTarget, baseDepthTexture, devicePixelRatio) {
84
+ const { bloom_enable = false, bloom_threshold = 1.5, bloom_strength = 0.4, bloom_radius = 0.85, } = object3d.userData;
85
+ // 不满足条件就不渲染发光效果
86
+ if (!bloom_enable || (bloom_strength === 0) || (bloom_radius === 0)) {
87
+ return;
88
+ }
89
+ bloomPass.threshold = bloom_threshold;
90
+ bloomPass.strength = bloom_strength;
91
+ bloomPass.radius = bloom_radius;
92
+ debugger;
93
+ // 保存原帧缓冲区
94
+ const originRenderTarget = renderer.getRenderTarget();
95
+ // 设置选中目标的帧缓冲区
96
+ renderer.getSize(size);
97
+ size.multiplyScalar(devicePixelRatio);
98
+ bloomPass.setSize(size.x, size.y);
99
+ selectTextureTarget.setSize(size.x, size.y);
100
+ selectDethpTestTextureTarget.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.map.value = baseRenderTarget.texture;
109
+ depthTestShader.uniforms.baseDepth.value = baseDepthTexture;
110
+ depthTestShader.uniforms.selectDepth.value = selectDepthTexture;
111
+ fsQuad.render(renderer, depthTestShader);
112
+ // 渲染辉光
113
+ bloomPass.render(renderer, selectDethpTestTextureTarget, selectDethpTestTextureTarget, 0, false);
114
+ // 将发光效果与原始帧缓冲区混合
115
+ renderer.setRenderTarget(originRenderTarget);
116
+ renderer.clearDepth();
117
+ blendMaterial.uniforms.map.value = selectDethpTestTextureTarget.texture;
118
+ fsQuad.render(renderer, blendMaterial);
119
+ // 调试代码
120
+ // renderer.setRenderTarget(null);
121
+ // renderer.clearDepth();
122
+ // copyShader.uniforms.map.value = blur2TextureTarget.texture;
123
+ // fsQuad.render(renderer, copyShader);
124
+ // return;
33
125
  }
@@ -1,2 +1,2 @@
1
1
  import { Camera, DepthTexture, Object3D, WebGLRenderer } from "three";
2
- export default function cover_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture): void;
2
+ export default function cover_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture, devicePixelRatio: number): void;
@@ -2,7 +2,7 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2024-09-23 21:07:06
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2024-09-23 21:53:12
5
+ * @Last Modified time: 2025-01-28 04:01:58
6
6
  */
7
7
  /*
8
8
  * @Author: xiaosihan
@@ -11,7 +11,7 @@
11
11
  * @Last Modified time: 2023-05-09 02:33:28
12
12
  */
13
13
  import { Color, DepthFormat, DepthTexture, LinearFilter, RGBAFormat, Scene, ShaderChunk, ShaderMaterial, UnsignedShortType, Vector2, WebGLRenderTarget, } from "three";
14
- import FullScreenQuad from "./FullScreenQuad";
14
+ import fsQuad from "./fsQuad";
15
15
  // 选中对象的深度纹理
16
16
  const selectDepthTexture = (() => {
17
17
  const baseDepthTexture = new DepthTexture(1024, 1024);
@@ -41,8 +41,6 @@ const blur1TextureTarget = new WebGLRenderTarget(512, 512, {
41
41
  format: RGBAFormat,
42
42
  });
43
43
  const size = new Vector2();
44
- // 创建一个渲染工具 用于处理纹理
45
- const fsQuad = new FullScreenQuad(); // 渲染辅助器
46
44
  //深度比对纹理
47
45
  const depthTestShader = new ShaderMaterial({
48
46
  uniforms: {
@@ -99,7 +97,7 @@ const depthTestShader = new ShaderMaterial({
99
97
  // 场景对象
100
98
  const scene = new Scene();
101
99
  // 给模型覆盖一层颜色 后处理通道
102
- export default function cover_pass(renderer, camera, object3d, baseDepthTexture) {
100
+ export default function cover_pass(renderer, camera, object3d, baseDepthTexture, devicePixelRatio) {
103
101
  const { cover_enable = false, cover_color = "#04fa12", cover_opacity = 1, cover_depth_test = true, // 颜色叠加是否开启深度测试
104
102
  } = object3d.userData;
105
103
  if (!cover_enable || cover_opacity === 0) {
@@ -109,7 +107,7 @@ export default function cover_pass(renderer, camera, object3d, baseDepthTexture)
109
107
  const originRenderTarget = renderer.getRenderTarget();
110
108
  // 设置选中目标的帧缓冲区
111
109
  renderer.getSize(size);
112
- size.multiplyScalar(window.devicePixelRatio);
110
+ size.multiplyScalar(devicePixelRatio);
113
111
  selectTextureTarget.setSize(size.x, size.y);
114
112
  selectDethpTestTextureTarget.setSize(size.x, size.y);
115
113
  blur1TextureTarget.setSize(size.x, size.y);
@@ -1,7 +1,9 @@
1
1
  import { BufferGeometry, Material, Mesh, OrthographicCamera, Scene, WebGLRenderer } from "three";
2
- export default class FullScreenQuad extends Scene {
2
+ declare class FullScreenQuad extends Scene {
3
3
  constructor();
4
4
  mesh: Mesh<BufferGeometry<import("three").NormalBufferAttributes>, Material, import("three").Object3DEventMap>;
5
5
  orthographicCamera: OrthographicCamera;
6
6
  render(renderer: WebGLRenderer, material: Material): void;
7
7
  }
8
+ declare const fsQuad: FullScreenQuad;
9
+ export default fsQuad;
@@ -2,10 +2,10 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2023-05-09 01:36:35
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2023-05-09 01:47:07
5
+ * @Last Modified time: 2025-01-28 04:04:33
6
6
  */
7
7
  import { BufferGeometry, Float32BufferAttribute, Mesh, MeshBasicMaterial, OrthographicCamera, Scene } from "three";
8
- export default class FullScreenQuad extends Scene {
8
+ class FullScreenQuad extends Scene {
9
9
  constructor() {
10
10
  super();
11
11
  }
@@ -23,3 +23,6 @@ export default class FullScreenQuad extends Scene {
23
23
  renderer.render(this, this.orthographicCamera);
24
24
  }
25
25
  }
26
+ // 创建一个渲染工具 用于处理纹理
27
+ const fsQuad = new FullScreenQuad(); // 渲染辅助器
28
+ export default fsQuad;
@@ -1,2 +1,2 @@
1
1
  import { Camera, DepthTexture, Object3D, WebGLRenderer } from "three";
2
- export default function glow_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture): void;
2
+ export default function glow_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture, devicePixelRatio: number): void;
package/pass/glow_pass.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2023-05-09 00:35:17
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2024-09-23 22:00:48
5
+ * @Last Modified time: 2025-01-28 04:13:16
6
6
  */
7
7
  import { Color, DepthFormat, DepthTexture, LinearFilter, NoBlending, NormalBlending, RGBAFormat, RawShaderMaterial, Scene, ShaderChunk, ShaderMaterial, UnsignedShortType, Vector2, WebGLRenderTarget, } from "three";
8
- import FullScreenQuad from "./FullScreenQuad";
8
+ import fsQuad from "./fsQuad";
9
9
  // 选中对象的深度纹理
10
10
  const selectDepthTexture = (() => {
11
11
  const baseDepthTexture = new DepthTexture(4096, 4096);
@@ -42,8 +42,6 @@ const blur2TextureTarget = new WebGLRenderTarget(512, 512, {
42
42
  format: RGBAFormat,
43
43
  });
44
44
  const size = new Vector2();
45
- // 创建一个渲染工具 用于处理纹理
46
- const fsQuad = new FullScreenQuad(); // 渲染辅助器
47
45
  //深度比对纹理
48
46
  const depthTestShader = new ShaderMaterial({
49
47
  uniforms: {
@@ -83,242 +81,6 @@ const depthTestShader = new ShaderMaterial({
83
81
  depthWrite: true,
84
82
  transparent: true,
85
83
  });
86
- // 抗锯齿着色器
87
- const FXAAShaderMaterial = new ShaderMaterial({
88
- uniforms: {
89
- tDiffuse: { value: null },
90
- resolution: { value: new Vector2(1 / 1024, 1 / 1024) },
91
- },
92
- vertexShader: `
93
- ${ShaderChunk.common}
94
- ${ShaderChunk.logdepthbuf_pars_vertex}
95
- varying vec2 vUv;
96
- void main() {
97
- vUv = uv;
98
- gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
99
- ${ShaderChunk.logdepthbuf_vertex}
100
- }
101
- `,
102
- fragmentShader: `
103
- ${ShaderChunk.logdepthbuf_pars_fragment}
104
- precision highp float;
105
-
106
- uniform sampler2D tDiffuse;
107
-
108
- uniform vec2 resolution;
109
-
110
- varying vec2 vUv;
111
-
112
- #ifndef FXAA_DISCARD
113
- //
114
- // Only valid for PC OpenGL currently.
115
- // Probably will not work when FXAA_GREEN_AS_LUMA = 1.
116
- //
117
- // 1 = Use discard on pixels which don't need AA.
118
- // For APIs which enable concurrent TEX+ROP from same surface.
119
- // 0 = Return unchanged color on pixels which don't need AA.
120
- //
121
- #define FXAA_DISCARD 0
122
- #endif
123
-
124
- /*--------------------------------------------------------------------------*/
125
- #define FxaaTexTop(t, p) texture2D(t, p, -100.0)
126
- #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
127
- /*--------------------------------------------------------------------------*/
128
-
129
- #define NUM_SAMPLES 5
130
-
131
- // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha
132
- float contrast( vec4 a, vec4 b ) {
133
- vec4 diff = abs( a - b );
134
- return max( max( max( diff.r, diff.g ), diff.b ), diff.a );
135
- }
136
-
137
- /*============================================================================
138
-
139
- FXAA3 QUALITY - PC
140
-
141
- ============================================================================*/
142
-
143
- /*--------------------------------------------------------------------------*/
144
- vec4 FxaaPixelShader(
145
- vec2 posM,
146
- sampler2D tex,
147
- vec2 fxaaQualityRcpFrame,
148
- float fxaaQualityEdgeThreshold,
149
- float fxaaQualityinvEdgeThreshold
150
- ) {
151
- vec4 rgbaM = FxaaTexTop(tex, posM);
152
- vec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);
153
- vec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);
154
- vec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);
155
- vec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);
156
- // . S .
157
- // W M E
158
- // . N .
159
-
160
- bool earlyExit = max( max( max(
161
- contrast( rgbaM, rgbaN ),
162
- contrast( rgbaM, rgbaS ) ),
163
- contrast( rgbaM, rgbaE ) ),
164
- contrast( rgbaM, rgbaW ) )
165
- < fxaaQualityEdgeThreshold;
166
- // . 0 .
167
- // 0 0 0
168
- // . 0 .
169
-
170
- #if (FXAA_DISCARD == 1)
171
- if(earlyExit) FxaaDiscard;
172
- #else
173
- if(earlyExit) return rgbaM;
174
- #endif
175
-
176
- float contrastN = contrast( rgbaM, rgbaN );
177
- float contrastS = contrast( rgbaM, rgbaS );
178
- float contrastE = contrast( rgbaM, rgbaE );
179
- float contrastW = contrast( rgbaM, rgbaW );
180
-
181
- float relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );
182
- relativeVContrast *= fxaaQualityinvEdgeThreshold;
183
-
184
- bool horzSpan = relativeVContrast > 0.;
185
- // . 1 .
186
- // 0 0 0
187
- // . 1 .
188
-
189
- // 45 deg edge detection and corners of objects, aka V/H contrast is too similar
190
- if( abs( relativeVContrast ) < .3 ) {
191
- // locate the edge
192
- vec2 dirToEdge;
193
- dirToEdge.x = contrastE > contrastW ? 1. : -1.;
194
- dirToEdge.y = contrastS > contrastN ? 1. : -1.;
195
- // . 2 . . 1 .
196
- // 1 0 2 ~= 0 0 1
197
- // . 1 . . 0 .
198
-
199
- // tap 2 pixels and see which ones are "outside" the edge, to
200
- // determine if the edge is vertical or horizontal
201
-
202
- vec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);
203
- float matchAlongH = contrast( rgbaM, rgbaAlongH );
204
- // . 1 .
205
- // 0 0 1
206
- // . 0 H
207
-
208
- vec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);
209
- float matchAlongV = contrast( rgbaM, rgbaAlongV );
210
- // V 1 .
211
- // 0 0 1
212
- // . 0 .
213
-
214
- relativeVContrast = matchAlongV - matchAlongH;
215
- relativeVContrast *= fxaaQualityinvEdgeThreshold;
216
-
217
- if( abs( relativeVContrast ) < .3 ) { // 45 deg edge
218
- // 1 1 .
219
- // 0 0 1
220
- // . 0 1
221
-
222
- // do a simple blur
223
- return mix(
224
- rgbaM,
225
- (rgbaN + rgbaS + rgbaE + rgbaW) * .25,
226
- .4
227
- );
228
- }
229
-
230
- horzSpan = relativeVContrast > 0.;
231
- }
232
-
233
- if(!horzSpan) rgbaN = rgbaW;
234
- if(!horzSpan) rgbaS = rgbaE;
235
- // . 0 . 1
236
- // 1 0 1 -> 0
237
- // . 0 . 1
238
-
239
- bool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );
240
- if(!pairN) rgbaN = rgbaS;
241
-
242
- vec2 offNP;
243
- offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
244
- offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
245
-
246
- bool doneN = false;
247
- bool doneP = false;
248
-
249
- float nDist = 0.;
250
- float pDist = 0.;
251
-
252
- vec2 posN = posM;
253
- vec2 posP = posM;
254
-
255
- int iterationsUsed = 0;
256
- int iterationsUsedN = 0;
257
- int iterationsUsedP = 0;
258
- for( int i = 0; i < NUM_SAMPLES; i++ ) {
259
- iterationsUsed = i;
260
-
261
- float increment = float(i + 1);
262
-
263
- if(!doneN) {
264
- nDist += increment;
265
- posN = posM + offNP * nDist;
266
- vec4 rgbaEndN = FxaaTexTop(tex, posN.xy);
267
- doneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );
268
- iterationsUsedN = i;
269
- }
270
-
271
- if(!doneP) {
272
- pDist += increment;
273
- posP = posM - offNP * pDist;
274
- vec4 rgbaEndP = FxaaTexTop(tex, posP.xy);
275
- doneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );
276
- iterationsUsedP = i;
277
- }
278
-
279
- if(doneN || doneP) break;
280
- }
281
-
282
-
283
- if ( !doneP && !doneN ) return rgbaM; // failed to find end of edge
284
-
285
- float dist = min(
286
- doneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,
287
- doneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.
288
- );
289
-
290
- // hacky way of reduces blurriness of mostly diagonal edges
291
- // but reduces AA quality
292
- dist = pow(dist, .5);
293
-
294
- dist = 1. - dist;
295
-
296
- return mix(
297
- rgbaM,
298
- rgbaN,
299
- dist * .5
300
- );
301
- }
302
-
303
- void main() {
304
- const float edgeDetectionQuality = .2;
305
- const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
306
-
307
- gl_FragColor = FxaaPixelShader(
308
- vUv,
309
- tDiffuse,
310
- resolution,
311
- edgeDetectionQuality, // [0,1] contrast needed, otherwise early discard
312
- invEdgeDetectionQuality
313
- );
314
- ${ShaderChunk.logdepthbuf_fragment}
315
- }
316
- `,
317
- blending: NoBlending,
318
- depthTest: false,
319
- depthWrite: false,
320
- transparent: true,
321
- });
322
84
  // 描边着色器
323
85
  const blurShader = new RawShaderMaterial({
324
86
  uniforms: {
@@ -474,7 +236,7 @@ const copyShader = new ShaderMaterial({
474
236
  // 场景对象
475
237
  const scene = new Scene();
476
238
  // 对象发光
477
- export default function glow_pass(renderer, camera, object3d, baseDepthTexture) {
239
+ export default function glow_pass(renderer, camera, object3d, baseDepthTexture, devicePixelRatio) {
478
240
  const { glow_enable = false, glow_color = "#04fa12", glow_width = 1, glow_opacity = 1, } = object3d.userData;
479
241
  if (!glow_enable || glow_width === 0) {
480
242
  return;
@@ -483,7 +245,7 @@ export default function glow_pass(renderer, camera, object3d, baseDepthTexture)
483
245
  const originRenderTarget = renderer.getRenderTarget();
484
246
  // 设置选中目标的帧缓冲区
485
247
  renderer.getSize(size);
486
- size.multiplyScalar(window.devicePixelRatio);
248
+ size.multiplyScalar(devicePixelRatio);
487
249
  selectTextureTarget.setSize(size.x, size.y);
488
250
  selectDethpTestTextureTarget.setSize(size.x, size.y);
489
251
  blur1TextureTarget.setSize(size.x, size.y);
@@ -494,12 +256,10 @@ export default function glow_pass(renderer, camera, object3d, baseDepthTexture)
494
256
  renderer.render(scene, camera);
495
257
  // 设置描边着色器的分辨率
496
258
  blurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
497
- // 设置抗锯齿着色器的分辨率
498
- FXAAShaderMaterial.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
499
259
  //描边颜色
500
260
  blurShader.uniforms.color.value.set(glow_color);
501
261
  blurShader.uniforms.width.value = glow_width / 10;
502
- //深度测试
262
+ //使用深度纹理提取选中的对象未被遮挡的像素点
503
263
  renderer.setRenderTarget(selectDethpTestTextureTarget);
504
264
  renderer.clear();
505
265
  depthTestShader.uniforms.map.value = selectTextureTarget.texture;
@@ -1,2 +1,2 @@
1
1
  import { Camera, DepthTexture, Object3D, WebGLRenderer } from "three";
2
- export default function stroke_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture): void;
2
+ export default function stroke_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseDepthTexture: DepthTexture, devicePixelRatio: number): void;
@@ -2,13 +2,13 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2023-05-09 00:35:17
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2024-09-23 22:00:54
5
+ * @Last Modified time: 2025-01-28 04:02:16
6
6
  */
7
7
  import { Color, DepthFormat, DepthTexture, LinearFilter, NoBlending, NormalBlending, RGBAFormat, RawShaderMaterial, Scene, ShaderChunk, ShaderMaterial, UnsignedShortType, Vector2, WebGLRenderTarget } from "three";
8
- import FullScreenQuad from "./FullScreenQuad";
8
+ import fsQuad from "./fsQuad";
9
9
  // 选中对象的深度纹理
10
10
  const selectDepthTexture = (() => {
11
- const baseDepthTexture = new DepthTexture(4096, 4096);
11
+ const baseDepthTexture = new DepthTexture(1024, 1024);
12
12
  baseDepthTexture.format = DepthFormat;
13
13
  baseDepthTexture.type = UnsignedShortType;
14
14
  baseDepthTexture.anisotropy = 16;
@@ -34,8 +34,6 @@ const blur1TextureTarget = new WebGLRenderTarget(512, 512, { minFilter: LinearFi
34
34
  // 所以需要用2个模糊纹理相互读写
35
35
  const blur2TextureTarget = new WebGLRenderTarget(512, 512, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
36
36
  const size = new Vector2();
37
- // 创建一个渲染工具 用于处理纹理
38
- const fsQuad = new FullScreenQuad(); // 渲染辅助器
39
37
  //深度比对纹理
40
38
  const depthTestShader = new ShaderMaterial({
41
39
  uniforms: {
@@ -464,7 +462,7 @@ const copyShader = new ShaderMaterial({
464
462
  // 场景对象
465
463
  const scene = new Scene();
466
464
  // 对象描边
467
- export default function stroke_pass(renderer, camera, object3d, baseDepthTexture) {
465
+ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture, devicePixelRatio) {
468
466
  const { stroke_enable = false, stroke_color = "#04fa12", stroke_width = 1 } = object3d.userData;
469
467
  if (!stroke_enable || stroke_width === 0) {
470
468
  return;
@@ -473,7 +471,7 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
473
471
  const originRenderTarget = renderer.getRenderTarget();
474
472
  // 设置选中目标的帧缓冲区
475
473
  renderer.getSize(size);
476
- size.multiplyScalar(window.devicePixelRatio);
474
+ size.multiplyScalar(devicePixelRatio);
477
475
  selectTextureTarget.setSize(size.x, size.y);
478
476
  selectDethpTestTextureTarget.setSize(size.x, size.y);
479
477
  blur1TextureTarget.setSize(size.x, size.y);
package/shaders.d.ts CHANGED
@@ -1,6 +1,4 @@
1
1
  import { OrthographicCamera, ShaderMaterial } from "three";
2
- import FullScreenQuad from "./pass/FullScreenQuad";
3
- export declare const fullScreenMesh: FullScreenQuad;
4
2
  export declare const orthographicCamera: OrthographicCamera;
5
3
  export declare const clearShader: ShaderMaterial;
6
4
  export declare const intersectionShader: ShaderMaterial;
package/shaders.js CHANGED
@@ -2,13 +2,9 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2022-03-24 16:38:35
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2022-04-02 18:28:38
5
+ * @Last Modified time: 2025-01-28 04:03:20
6
6
  */
7
7
  import { NoBlending, OrthographicCamera, ShaderChunk, ShaderMaterial } from "three";
8
- import FullScreenQuad from "./pass/FullScreenQuad";
9
- // 常用着色器及工具
10
- // 全屏渲染模型
11
- export const fullScreenMesh = new FullScreenQuad();
12
8
  export const orthographicCamera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
13
9
  // 清理着色器
14
10
  export const clearShader = new ShaderMaterial({