three-base 2.0.22 → 2.0.23

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/Mirror.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2023-08-04 17:17:15
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2023-08-04 20:54:29
5
+ * @Last Modified time: 2024-01-20 05:33:51
6
6
  */
7
7
  import { Color, DoubleSide, HalfFloatType, Matrix4, Mesh, PerspectiveCamera, Plane, PlaneGeometry, ShaderMaterial, Vector3, Vector4, WebGLRenderTarget } from "three";
8
8
  // 镜子模型
@@ -180,7 +180,6 @@ export default class Mirror extends Mesh {
180
180
  //@ts-ignore
181
181
  const viewport = this.camera.viewport;
182
182
  if (viewport !== undefined) {
183
- debugger;
184
183
  renderer.state.viewport(viewport);
185
184
  }
186
185
  this.visible = true;
package/Mirror.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2023-08-04 17:17:15
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2023-08-04 20:54:29
5
+ * @Last Modified time: 2024-01-20 05:33:51
6
6
  */
7
7
 
8
8
  import { BufferGeometry, Camera, Color, DoubleSide, Group, HalfFloatType, Material, Matrix4, Mesh, PerspectiveCamera, Plane, PlaneGeometry, Scene, ShaderMaterial, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer } from "three";
@@ -233,7 +233,6 @@ export default class Mirror extends Mesh {
233
233
  //@ts-ignore
234
234
  const viewport = this.camera.viewport;
235
235
  if (viewport !== undefined) {
236
- debugger;
237
236
  renderer.state.viewport(viewport);
238
237
  }
239
238
 
package/ThreeBase.d.ts CHANGED
@@ -23,6 +23,7 @@ export default class ThreeBase extends EventDispatcher {
23
23
  controlsPosition: Transition;
24
24
  gridHelper: GridHelper;
25
25
  axesHelper: AxesHelper;
26
+ frame: number;
26
27
  init(): void;
27
28
  resetLookAt({ position, center, }: {
28
29
  position: Vector3;
package/ThreeBase.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2021-12-20 13:38:22
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2023-05-23 23:54:13
5
+ * @Last Modified time: 2024-01-20 05:33:28
6
6
  */
7
7
  import { round } from "lodash";
8
- import { AxesHelper, DepthFormat, DepthTexture, EventDispatcher, GridHelper, LinearFilter, Mesh, MOUSE, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, RGBAFormat, Scene, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderer, WebGLRenderTarget } from "three";
8
+ import { AxesHelper, DepthFormat, DepthTexture, EventDispatcher, GridHelper, LinearFilter, LinearSRGBColorSpace, Mesh, MOUSE, NoBlending, NormalBlending, PerspectiveCamera, RGBAFormat, Scene, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderer, WebGLRenderTarget } from "three";
9
9
  import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
10
10
  import { generateUUID } from "three/src/math/MathUtils";
11
11
  import glow_pass from "./pass/glow_pass";
@@ -15,6 +15,7 @@ import threeLoader from "./threeLoader";
15
15
  import ThreeMouse from "./ThreeMouse";
16
16
  import threeUtils from "./threeUtils";
17
17
  import Transition from "./Transition";
18
+ import FXAAShaderMaterial from "./shaders/FXAAShaderMaterial";
18
19
  // three.js 的基础对象
19
20
  export default class ThreeBase extends EventDispatcher {
20
21
  constructor() {
@@ -29,7 +30,6 @@ export default class ThreeBase extends EventDispatcher {
29
30
  baseDepthTexture.anisotropy = 16;
30
31
  return baseDepthTexture;
31
32
  })();
32
- // TODO 渲染目标的颜色空间问题 还没有处理好
33
33
  // 基础纹理渲染对象
34
34
  baseRenderTarget = (() => {
35
35
  const baseRenderTarget = new WebGLRenderTarget(128, 128, {
@@ -64,7 +64,7 @@ export default class ThreeBase extends EventDispatcher {
64
64
  });
65
65
  renderer.domElement.id = generateUUID();
66
66
  renderer.localClippingEnabled = true;
67
- renderer.outputColorSpace = NoColorSpace;
67
+ renderer.outputColorSpace = LinearSRGBColorSpace;
68
68
  renderer.setPixelRatio(window.devicePixelRatio);
69
69
  renderer.autoClear = false;
70
70
  renderer.clear();
@@ -183,6 +183,8 @@ export default class ThreeBase extends EventDispatcher {
183
183
  }
184
184
  return axesHelper;
185
185
  })();
186
+ //TODO 设置帧频率 默认50帧
187
+ frame = 50;
186
188
  init() {
187
189
  // 资源加载进度有更新时, 需要渲染
188
190
  threeLoader.addEventListener("progress", () => {
@@ -238,7 +240,7 @@ export default class ThreeBase extends EventDispatcher {
238
240
  return {
239
241
  center: new Vector3(...center),
240
242
  position: new Vector3(...position),
241
- centerPosition: `position: new Vector3(${position.join(",")}),center: new Vector3(${center.join(",")})`
243
+ centerPosition: `center: new Vector3(${center.join(",")}),position: new Vector3(${position.join(",")})`
242
244
  };
243
245
  }
244
246
  // 三维向量转化成屏幕上的2维向量
@@ -282,7 +284,7 @@ export default class ThreeBase extends EventDispatcher {
282
284
  // 渲染场景
283
285
  render() {
284
286
  // 控制器在移动时鼠标不能操作
285
- // this.controls.enabled = (this.controlsPosition.isDone() || this.controlsCenter.isDone());
287
+ this.renderer.domElement.style.pointerEvents = (!this.controlsPosition.isDone() || !this.controlsCenter.isDone()) ? "none" : "all";
286
288
  // canvas 没有在页面上面的话 就跳过渲染
287
289
  if (!threeUtils.inDocument(this.renderer.domElement)) {
288
290
  this.stopRender();
@@ -445,13 +447,21 @@ export default class ThreeBase extends EventDispatcher {
445
447
  this.renderTargetgaussBlur(renderTarget, 1, 1);
446
448
  this.renderTargetgaussBlur(renderTarget, 1, 1);
447
449
  }
448
- // TODO 需要做康锯齿处理 渲染 渲染目标
450
+ // 需要做康锯齿处理 渲染 渲染目标
449
451
  renderRendererTarget(renderTarget, alpha = false) {
450
- coptyShader.uniforms.map.value = renderTarget.texture;
451
- coptyShader.uniforms.opacity.value = 1.0;
452
- fullScreenMesh.material = coptyShader;
453
- coptyShader.blending = alpha ? NoBlending : NormalBlending;
452
+ FXAAShaderMaterial.uniforms.tDiffuse.value = renderTarget.texture;
453
+ fullScreenMesh.material = FXAAShaderMaterial;
454
454
  fullScreenMesh.render(this.renderer);
455
+ // const FXAAShaderMaterial = new ShaderMaterial({
456
+ // uniforms: {
457
+ // tDiffuse: { value: null }, // 贴图纹理
458
+ // resolution: { value: new Vector2(1 / 1024, 1 / 1024) }
459
+ // },
460
+ // coptyShader.uniforms.map.value = renderTarget.texture;
461
+ // coptyShader.uniforms.opacity.value = 1.0;
462
+ // fullScreenMesh.material = coptyShader;
463
+ // coptyShader.blending = alpha ? NoBlending : NormalBlending;
464
+ // fullScreenMesh.render(this.renderer);
455
465
  }
456
466
  // 渲染纹理
457
467
  renderTexture(texture, alpha = false) {
package/ThreeBase.ts CHANGED
@@ -2,11 +2,11 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2021-12-20 13:38:22
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2023-05-23 23:54:13
5
+ * @Last Modified time: 2024-01-20 05:33:28
6
6
  */
7
7
 
8
8
  import { round } from "lodash";
9
- import { AxesHelper, BufferGeometry, Camera, DepthFormat, DepthTexture, DisplayP3ColorSpace, EventDispatcher, GridHelper, LinearDisplayP3ColorSpace, LinearFilter, LinearSRGBColorSpace, Mesh, MeshBasicMaterial, MOUSE, NoBlending, NoColorSpace, NormalBlending, Object3D, PerspectiveCamera, RGBAFormat, Scene, SRGBColorSpace, Texture, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderer, WebGLRenderTarget } from "three";
9
+ import { AxesHelper, BufferGeometry, Camera, DepthFormat, DepthTexture, EventDispatcher, GridHelper, LinearFilter, LinearSRGBColorSpace, Mesh, MeshBasicMaterial, MOUSE, NoBlending, NormalBlending, Object3D, PerspectiveCamera, RGBAFormat, Scene, Texture, TOUCH, UnsignedShortType, Vector2, Vector3, WebGLRenderer, WebGLRenderTarget } from "three";
10
10
  import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
11
11
  import { generateUUID } from "three/src/math/MathUtils";
12
12
  import glow_pass from "./pass/glow_pass";
@@ -16,6 +16,7 @@ import threeLoader from "./threeLoader";
16
16
  import ThreeMouse from "./ThreeMouse";
17
17
  import threeUtils from "./threeUtils";
18
18
  import Transition from "./Transition";
19
+ import FXAAShaderMaterial from "./shaders/FXAAShaderMaterial";
19
20
 
20
21
  // three.js 的基础对象
21
22
  export default class ThreeBase extends EventDispatcher {
@@ -34,7 +35,6 @@ export default class ThreeBase extends EventDispatcher {
34
35
  return baseDepthTexture;
35
36
  })();
36
37
 
37
- // TODO 渲染目标的颜色空间问题 还没有处理好
38
38
  // 基础纹理渲染对象
39
39
  baseRenderTarget = (() => {
40
40
  const baseRenderTarget = new WebGLRenderTarget(128, 128, {
@@ -69,14 +69,14 @@ export default class ThreeBase extends EventDispatcher {
69
69
  alpha: true,// 透明背景
70
70
  antialias: true, // 阴影抗锯齿
71
71
  precision: "highp", //precision:highp/mediump/lowp着色精度选择
72
- logarithmicDepthBuffer: true, // 对数深度缓冲区 避免当2个面完全重合时闪烁
72
+ logarithmicDepthBuffer: true, // 对数深度缓冲区 避免当2个面挨的很近时闪烁
73
73
  preserveDrawingBuffer: true, // 是否保存绘图缓冲
74
74
  stencil: false, // 模版
75
75
  });
76
76
 
77
77
  renderer.domElement.id = generateUUID();
78
78
  renderer.localClippingEnabled = true;
79
- renderer.outputColorSpace = NoColorSpace;
79
+ renderer.outputColorSpace = LinearSRGBColorSpace;
80
80
  renderer.setPixelRatio(window.devicePixelRatio);
81
81
  renderer.autoClear = false;
82
82
  renderer.clear();
@@ -174,9 +174,9 @@ export default class ThreeBase extends EventDispatcher {
174
174
  controlsPosition.onChange(({ x, y, z }) => {
175
175
  // const distance = this.controlsDistance.get("distance");
176
176
  this.camera.position.set(x + 0.01, y, z + 0.01)
177
- // .sub(this.controls.target)
178
- // .setLength(distance)
179
- // .add(this.controls.target);
177
+ // .sub(this.controls.target)
178
+ // .setLength(distance)
179
+ // .add(this.controls.target);
180
180
 
181
181
  // // 创建初始方向向量
182
182
  // const directionVecA = new THREE.Vector3(1, 0, 0); // 需要旋转的初始方向向量
@@ -222,6 +222,9 @@ export default class ThreeBase extends EventDispatcher {
222
222
  return axesHelper;
223
223
  })();
224
224
 
225
+ //TODO 设置帧频率 默认50帧
226
+ frame = 50;
227
+
225
228
  init() {
226
229
  // 资源加载进度有更新时, 需要渲染
227
230
  threeLoader.addEventListener("progress", () => {
@@ -294,7 +297,7 @@ export default class ThreeBase extends EventDispatcher {
294
297
  return {
295
298
  center: new Vector3(...center),
296
299
  position: new Vector3(...position),
297
- centerPosition: `position: new Vector3(${position.join(",")}),center: new Vector3(${center.join(",")})`
300
+ centerPosition: `center: new Vector3(${center.join(",")}),position: new Vector3(${position.join(",")})`
298
301
  }
299
302
  }
300
303
 
@@ -346,9 +349,8 @@ export default class ThreeBase extends EventDispatcher {
346
349
 
347
350
  // 渲染场景
348
351
  render() {
349
-
350
352
  // 控制器在移动时鼠标不能操作
351
- // this.controls.enabled = (this.controlsPosition.isDone() || this.controlsCenter.isDone());
353
+ this.renderer.domElement.style.pointerEvents = (!this.controlsPosition.isDone() || !this.controlsCenter.isDone()) ? "none" : "all";
352
354
 
353
355
  // canvas 没有在页面上面的话 就跳过渲染
354
356
  if (!threeUtils.inDocument(this.renderer.domElement)) {
@@ -388,7 +390,9 @@ export default class ThreeBase extends EventDispatcher {
388
390
  this.renderer.clear();
389
391
 
390
392
  // this.renderer.setScissorTest(false);
393
+
391
394
  this.renderRendererTarget(this.baseRenderTarget);
395
+
392
396
  // this.renderer.setScissorTest(true);
393
397
  // this.renderer.setScissor(0, 0, 800, 1000);
394
398
  // this.renderer.render(this.scene, this.camera);
@@ -546,13 +550,23 @@ export default class ThreeBase extends EventDispatcher {
546
550
  this.renderTargetgaussBlur(renderTarget, 1, 1);
547
551
  }
548
552
 
549
- // TODO 需要做康锯齿处理 渲染 渲染目标
553
+ // 需要做康锯齿处理 渲染 渲染目标
550
554
  renderRendererTarget(renderTarget: WebGLRenderTarget, alpha: boolean = false) {
551
- coptyShader.uniforms.map.value = renderTarget.texture;
552
- coptyShader.uniforms.opacity.value = 1.0;
553
- fullScreenMesh.material = coptyShader;
554
- coptyShader.blending = alpha ? NoBlending : NormalBlending;
555
+
556
+ FXAAShaderMaterial.uniforms.tDiffuse.value = renderTarget.texture;
557
+ fullScreenMesh.material = FXAAShaderMaterial;
555
558
  fullScreenMesh.render(this.renderer);
559
+
560
+ // const FXAAShaderMaterial = new ShaderMaterial({
561
+ // uniforms: {
562
+ // tDiffuse: { value: null }, // 贴图纹理
563
+ // resolution: { value: new Vector2(1 / 1024, 1 / 1024) }
564
+ // },
565
+ // coptyShader.uniforms.map.value = renderTarget.texture;
566
+ // coptyShader.uniforms.opacity.value = 1.0;
567
+ // fullScreenMesh.material = coptyShader;
568
+ // coptyShader.blending = alpha ? NoBlending : NormalBlending;
569
+ // fullScreenMesh.render(this.renderer);
556
570
  }
557
571
 
558
572
  // 渲染纹理
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-base",
3
- "version": "2.0.22",
3
+ "version": "2.0.23",
4
4
  "description": "three 3d three-base",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
package/pass/glow_pass.js CHANGED
@@ -482,7 +482,7 @@ export default function glow_pass(renderer, camera, object3d, baseDepthTexture)
482
482
  renderer.setRenderTarget(selectTextureTarget);
483
483
  scene.children = [object3d];
484
484
  renderer.clear();
485
- renderer.render(object3d, camera);
485
+ renderer.render(scene, camera);
486
486
  // 设置描边着色器的分辨率
487
487
  blurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
488
488
  // 设置抗锯齿着色器的分辨率
package/pass/glow_pass.ts CHANGED
@@ -504,7 +504,7 @@ export default function glow_pass(renderer: WebGLRenderer, camera: Camera, objec
504
504
  renderer.setRenderTarget(selectTextureTarget);
505
505
  scene.children = [object3d];
506
506
  renderer.clear();
507
- renderer.render(object3d, camera);
507
+ renderer.render(scene, camera);
508
508
 
509
509
  // 设置描边着色器的分辨率
510
510
  blurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
@@ -478,7 +478,7 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
478
478
  renderer.setRenderTarget(selectTextureTarget);
479
479
  scene.children = [object3d];
480
480
  renderer.clear();
481
- renderer.render(object3d, camera);
481
+ renderer.render(scene, camera);
482
482
  // 设置描边着色器的分辨率
483
483
  blurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
484
484
  // 设置抗锯齿着色器的分辨率
@@ -497,7 +497,7 @@ export default function stroke_pass(renderer: WebGLRenderer, camera: Camera, obj
497
497
  renderer.setRenderTarget(selectTextureTarget);
498
498
  scene.children = [object3d];
499
499
  renderer.clear();
500
- renderer.render(object3d, camera);
500
+ renderer.render(scene, camera);
501
501
 
502
502
  // 设置描边着色器的分辨率
503
503
  blurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
@@ -0,0 +1,3 @@
1
+ import { ShaderMaterial } from "three";
2
+ declare const FXAAShaderMaterial: ShaderMaterial;
3
+ export default FXAAShaderMaterial;
@@ -0,0 +1,244 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2024-01-20 05:10:37
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2024-01-20 05:10:57
6
+ */
7
+ import { NoBlending, ShaderChunk, ShaderMaterial, Vector2 } from "three";
8
+ // 抗锯齿着色器
9
+ const FXAAShaderMaterial = new ShaderMaterial({
10
+ uniforms: {
11
+ tDiffuse: { value: null },
12
+ resolution: { value: new Vector2(1 / 1024, 1 / 1024) }
13
+ },
14
+ vertexShader: `
15
+ ${ShaderChunk.common}
16
+ ${ShaderChunk.logdepthbuf_pars_vertex}
17
+ varying vec2 vUv;
18
+ void main() {
19
+ vUv = uv;
20
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
21
+ ${ShaderChunk.logdepthbuf_vertex}
22
+ }
23
+ `,
24
+ fragmentShader: `
25
+ ${ShaderChunk.logdepthbuf_pars_fragment}
26
+ precision highp float;
27
+
28
+ uniform sampler2D tDiffuse;
29
+
30
+ uniform vec2 resolution;
31
+
32
+ varying vec2 vUv;
33
+
34
+ #ifndef FXAA_DISCARD
35
+ //
36
+ // Only valid for PC OpenGL currently.
37
+ // Probably will not work when FXAA_GREEN_AS_LUMA = 1.
38
+ //
39
+ // 1 = Use discard on pixels which don't need AA.
40
+ // For APIs which enable concurrent TEX+ROP from same surface.
41
+ // 0 = Return unchanged color on pixels which don't need AA.
42
+ //
43
+ #define FXAA_DISCARD 0
44
+ #endif
45
+
46
+ /*--------------------------------------------------------------------------*/
47
+ #define FxaaTexTop(t, p) texture2D(t, p, -100.0)
48
+ #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
49
+ /*--------------------------------------------------------------------------*/
50
+
51
+ #define NUM_SAMPLES 5
52
+
53
+ // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha
54
+ float contrast( vec4 a, vec4 b ) {
55
+ vec4 diff = abs( a - b );
56
+ return max( max( max( diff.r, diff.g ), diff.b ), diff.a );
57
+ }
58
+
59
+ /*============================================================================
60
+
61
+ FXAA3 QUALITY - PC
62
+
63
+ ============================================================================*/
64
+
65
+ /*--------------------------------------------------------------------------*/
66
+ vec4 FxaaPixelShader(
67
+ vec2 posM,
68
+ sampler2D tex,
69
+ vec2 fxaaQualityRcpFrame,
70
+ float fxaaQualityEdgeThreshold,
71
+ float fxaaQualityinvEdgeThreshold
72
+ ) {
73
+ vec4 rgbaM = FxaaTexTop(tex, posM);
74
+ vec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);
75
+ vec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);
76
+ vec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);
77
+ vec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);
78
+ // . S .
79
+ // W M E
80
+ // . N .
81
+
82
+ bool earlyExit = max( max( max(
83
+ contrast( rgbaM, rgbaN ),
84
+ contrast( rgbaM, rgbaS ) ),
85
+ contrast( rgbaM, rgbaE ) ),
86
+ contrast( rgbaM, rgbaW ) )
87
+ < fxaaQualityEdgeThreshold;
88
+ // . 0 .
89
+ // 0 0 0
90
+ // . 0 .
91
+
92
+ #if (FXAA_DISCARD == 1)
93
+ if(earlyExit) FxaaDiscard;
94
+ #else
95
+ if(earlyExit) return rgbaM;
96
+ #endif
97
+
98
+ float contrastN = contrast( rgbaM, rgbaN );
99
+ float contrastS = contrast( rgbaM, rgbaS );
100
+ float contrastE = contrast( rgbaM, rgbaE );
101
+ float contrastW = contrast( rgbaM, rgbaW );
102
+
103
+ float relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );
104
+ relativeVContrast *= fxaaQualityinvEdgeThreshold;
105
+
106
+ bool horzSpan = relativeVContrast > 0.;
107
+ // . 1 .
108
+ // 0 0 0
109
+ // . 1 .
110
+
111
+ // 45 deg edge detection and corners of objects, aka V/H contrast is too similar
112
+ if( abs( relativeVContrast ) < .3 ) {
113
+ // locate the edge
114
+ vec2 dirToEdge;
115
+ dirToEdge.x = contrastE > contrastW ? 1. : -1.;
116
+ dirToEdge.y = contrastS > contrastN ? 1. : -1.;
117
+ // . 2 . . 1 .
118
+ // 1 0 2 ~= 0 0 1
119
+ // . 1 . . 0 .
120
+
121
+ // tap 2 pixels and see which ones are "outside" the edge, to
122
+ // determine if the edge is vertical or horizontal
123
+
124
+ vec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);
125
+ float matchAlongH = contrast( rgbaM, rgbaAlongH );
126
+ // . 1 .
127
+ // 0 0 1
128
+ // . 0 H
129
+
130
+ vec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);
131
+ float matchAlongV = contrast( rgbaM, rgbaAlongV );
132
+ // V 1 .
133
+ // 0 0 1
134
+ // . 0 .
135
+
136
+ relativeVContrast = matchAlongV - matchAlongH;
137
+ relativeVContrast *= fxaaQualityinvEdgeThreshold;
138
+
139
+ if( abs( relativeVContrast ) < .3 ) { // 45 deg edge
140
+ // 1 1 .
141
+ // 0 0 1
142
+ // . 0 1
143
+
144
+ // do a simple blur
145
+ return mix(
146
+ rgbaM,
147
+ (rgbaN + rgbaS + rgbaE + rgbaW) * .25,
148
+ .4
149
+ );
150
+ }
151
+
152
+ horzSpan = relativeVContrast > 0.;
153
+ }
154
+
155
+ if(!horzSpan) rgbaN = rgbaW;
156
+ if(!horzSpan) rgbaS = rgbaE;
157
+ // . 0 . 1
158
+ // 1 0 1 -> 0
159
+ // . 0 . 1
160
+
161
+ bool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );
162
+ if(!pairN) rgbaN = rgbaS;
163
+
164
+ vec2 offNP;
165
+ offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
166
+ offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
167
+
168
+ bool doneN = false;
169
+ bool doneP = false;
170
+
171
+ float nDist = 0.;
172
+ float pDist = 0.;
173
+
174
+ vec2 posN = posM;
175
+ vec2 posP = posM;
176
+
177
+ int iterationsUsed = 0;
178
+ int iterationsUsedN = 0;
179
+ int iterationsUsedP = 0;
180
+ for( int i = 0; i < NUM_SAMPLES; i++ ) {
181
+ iterationsUsed = i;
182
+
183
+ float increment = float(i + 1);
184
+
185
+ if(!doneN) {
186
+ nDist += increment;
187
+ posN = posM + offNP * nDist;
188
+ vec4 rgbaEndN = FxaaTexTop(tex, posN.xy);
189
+ doneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );
190
+ iterationsUsedN = i;
191
+ }
192
+
193
+ if(!doneP) {
194
+ pDist += increment;
195
+ posP = posM - offNP * pDist;
196
+ vec4 rgbaEndP = FxaaTexTop(tex, posP.xy);
197
+ doneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );
198
+ iterationsUsedP = i;
199
+ }
200
+
201
+ if(doneN || doneP) break;
202
+ }
203
+
204
+
205
+ if ( !doneP && !doneN ) return rgbaM; // failed to find end of edge
206
+
207
+ float dist = min(
208
+ doneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,
209
+ doneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.
210
+ );
211
+
212
+ // hacky way of reduces blurriness of mostly diagonal edges
213
+ // but reduces AA quality
214
+ dist = pow(dist, .5);
215
+
216
+ dist = 1. - dist;
217
+
218
+ return mix(
219
+ rgbaM,
220
+ rgbaN,
221
+ dist * .5
222
+ );
223
+ }
224
+
225
+ void main() {
226
+ const float edgeDetectionQuality = .2;
227
+ const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
228
+
229
+ gl_FragColor = FxaaPixelShader(
230
+ vUv,
231
+ tDiffuse,
232
+ resolution,
233
+ edgeDetectionQuality, // [0,1] contrast needed, otherwise early discard
234
+ invEdgeDetectionQuality
235
+ );
236
+ ${ShaderChunk.logdepthbuf_fragment}
237
+ }
238
+ `,
239
+ blending: NoBlending,
240
+ depthTest: false,
241
+ depthWrite: false,
242
+ transparent: true
243
+ });
244
+ export default FXAAShaderMaterial;
@@ -0,0 +1,248 @@
1
+ /*
2
+ * @Author: xiaosihan
3
+ * @Date: 2024-01-20 05:10:37
4
+ * @Last Modified by: xiaosihan
5
+ * @Last Modified time: 2024-01-20 05:10:57
6
+ */
7
+ import { NoBlending, ShaderChunk, ShaderMaterial, Vector2 } from "three";
8
+
9
+
10
+
11
+ // 抗锯齿着色器
12
+ const FXAAShaderMaterial = new ShaderMaterial({
13
+ uniforms: {
14
+ tDiffuse: { value: null }, // 贴图纹理
15
+ resolution: { value: new Vector2(1 / 1024, 1 / 1024) }
16
+ },
17
+ vertexShader: `
18
+ ${ShaderChunk.common}
19
+ ${ShaderChunk.logdepthbuf_pars_vertex}
20
+ varying vec2 vUv;
21
+ void main() {
22
+ vUv = uv;
23
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
24
+ ${ShaderChunk.logdepthbuf_vertex}
25
+ }
26
+ `,
27
+ fragmentShader: `
28
+ ${ShaderChunk.logdepthbuf_pars_fragment}
29
+ precision highp float;
30
+
31
+ uniform sampler2D tDiffuse;
32
+
33
+ uniform vec2 resolution;
34
+
35
+ varying vec2 vUv;
36
+
37
+ #ifndef FXAA_DISCARD
38
+ //
39
+ // Only valid for PC OpenGL currently.
40
+ // Probably will not work when FXAA_GREEN_AS_LUMA = 1.
41
+ //
42
+ // 1 = Use discard on pixels which don't need AA.
43
+ // For APIs which enable concurrent TEX+ROP from same surface.
44
+ // 0 = Return unchanged color on pixels which don't need AA.
45
+ //
46
+ #define FXAA_DISCARD 0
47
+ #endif
48
+
49
+ /*--------------------------------------------------------------------------*/
50
+ #define FxaaTexTop(t, p) texture2D(t, p, -100.0)
51
+ #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
52
+ /*--------------------------------------------------------------------------*/
53
+
54
+ #define NUM_SAMPLES 5
55
+
56
+ // assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha
57
+ float contrast( vec4 a, vec4 b ) {
58
+ vec4 diff = abs( a - b );
59
+ return max( max( max( diff.r, diff.g ), diff.b ), diff.a );
60
+ }
61
+
62
+ /*============================================================================
63
+
64
+ FXAA3 QUALITY - PC
65
+
66
+ ============================================================================*/
67
+
68
+ /*--------------------------------------------------------------------------*/
69
+ vec4 FxaaPixelShader(
70
+ vec2 posM,
71
+ sampler2D tex,
72
+ vec2 fxaaQualityRcpFrame,
73
+ float fxaaQualityEdgeThreshold,
74
+ float fxaaQualityinvEdgeThreshold
75
+ ) {
76
+ vec4 rgbaM = FxaaTexTop(tex, posM);
77
+ vec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);
78
+ vec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);
79
+ vec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);
80
+ vec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);
81
+ // . S .
82
+ // W M E
83
+ // . N .
84
+
85
+ bool earlyExit = max( max( max(
86
+ contrast( rgbaM, rgbaN ),
87
+ contrast( rgbaM, rgbaS ) ),
88
+ contrast( rgbaM, rgbaE ) ),
89
+ contrast( rgbaM, rgbaW ) )
90
+ < fxaaQualityEdgeThreshold;
91
+ // . 0 .
92
+ // 0 0 0
93
+ // . 0 .
94
+
95
+ #if (FXAA_DISCARD == 1)
96
+ if(earlyExit) FxaaDiscard;
97
+ #else
98
+ if(earlyExit) return rgbaM;
99
+ #endif
100
+
101
+ float contrastN = contrast( rgbaM, rgbaN );
102
+ float contrastS = contrast( rgbaM, rgbaS );
103
+ float contrastE = contrast( rgbaM, rgbaE );
104
+ float contrastW = contrast( rgbaM, rgbaW );
105
+
106
+ float relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );
107
+ relativeVContrast *= fxaaQualityinvEdgeThreshold;
108
+
109
+ bool horzSpan = relativeVContrast > 0.;
110
+ // . 1 .
111
+ // 0 0 0
112
+ // . 1 .
113
+
114
+ // 45 deg edge detection and corners of objects, aka V/H contrast is too similar
115
+ if( abs( relativeVContrast ) < .3 ) {
116
+ // locate the edge
117
+ vec2 dirToEdge;
118
+ dirToEdge.x = contrastE > contrastW ? 1. : -1.;
119
+ dirToEdge.y = contrastS > contrastN ? 1. : -1.;
120
+ // . 2 . . 1 .
121
+ // 1 0 2 ~= 0 0 1
122
+ // . 1 . . 0 .
123
+
124
+ // tap 2 pixels and see which ones are "outside" the edge, to
125
+ // determine if the edge is vertical or horizontal
126
+
127
+ vec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);
128
+ float matchAlongH = contrast( rgbaM, rgbaAlongH );
129
+ // . 1 .
130
+ // 0 0 1
131
+ // . 0 H
132
+
133
+ vec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);
134
+ float matchAlongV = contrast( rgbaM, rgbaAlongV );
135
+ // V 1 .
136
+ // 0 0 1
137
+ // . 0 .
138
+
139
+ relativeVContrast = matchAlongV - matchAlongH;
140
+ relativeVContrast *= fxaaQualityinvEdgeThreshold;
141
+
142
+ if( abs( relativeVContrast ) < .3 ) { // 45 deg edge
143
+ // 1 1 .
144
+ // 0 0 1
145
+ // . 0 1
146
+
147
+ // do a simple blur
148
+ return mix(
149
+ rgbaM,
150
+ (rgbaN + rgbaS + rgbaE + rgbaW) * .25,
151
+ .4
152
+ );
153
+ }
154
+
155
+ horzSpan = relativeVContrast > 0.;
156
+ }
157
+
158
+ if(!horzSpan) rgbaN = rgbaW;
159
+ if(!horzSpan) rgbaS = rgbaE;
160
+ // . 0 . 1
161
+ // 1 0 1 -> 0
162
+ // . 0 . 1
163
+
164
+ bool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );
165
+ if(!pairN) rgbaN = rgbaS;
166
+
167
+ vec2 offNP;
168
+ offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
169
+ offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
170
+
171
+ bool doneN = false;
172
+ bool doneP = false;
173
+
174
+ float nDist = 0.;
175
+ float pDist = 0.;
176
+
177
+ vec2 posN = posM;
178
+ vec2 posP = posM;
179
+
180
+ int iterationsUsed = 0;
181
+ int iterationsUsedN = 0;
182
+ int iterationsUsedP = 0;
183
+ for( int i = 0; i < NUM_SAMPLES; i++ ) {
184
+ iterationsUsed = i;
185
+
186
+ float increment = float(i + 1);
187
+
188
+ if(!doneN) {
189
+ nDist += increment;
190
+ posN = posM + offNP * nDist;
191
+ vec4 rgbaEndN = FxaaTexTop(tex, posN.xy);
192
+ doneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );
193
+ iterationsUsedN = i;
194
+ }
195
+
196
+ if(!doneP) {
197
+ pDist += increment;
198
+ posP = posM - offNP * pDist;
199
+ vec4 rgbaEndP = FxaaTexTop(tex, posP.xy);
200
+ doneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );
201
+ iterationsUsedP = i;
202
+ }
203
+
204
+ if(doneN || doneP) break;
205
+ }
206
+
207
+
208
+ if ( !doneP && !doneN ) return rgbaM; // failed to find end of edge
209
+
210
+ float dist = min(
211
+ doneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,
212
+ doneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.
213
+ );
214
+
215
+ // hacky way of reduces blurriness of mostly diagonal edges
216
+ // but reduces AA quality
217
+ dist = pow(dist, .5);
218
+
219
+ dist = 1. - dist;
220
+
221
+ return mix(
222
+ rgbaM,
223
+ rgbaN,
224
+ dist * .5
225
+ );
226
+ }
227
+
228
+ void main() {
229
+ const float edgeDetectionQuality = .2;
230
+ const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
231
+
232
+ gl_FragColor = FxaaPixelShader(
233
+ vUv,
234
+ tDiffuse,
235
+ resolution,
236
+ edgeDetectionQuality, // [0,1] contrast needed, otherwise early discard
237
+ invEdgeDetectionQuality
238
+ );
239
+ ${ShaderChunk.logdepthbuf_fragment}
240
+ }
241
+ `,
242
+ blending: NoBlending, // 渲染时不与背景融合计算 直接替换
243
+ depthTest: false,
244
+ depthWrite: false,
245
+ transparent: true
246
+ });
247
+
248
+ export default FXAAShaderMaterial;