@shapediver/viewer.rendering-engine.rendering-engine-threejs 3.3.4 → 3.3.6
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/package.json +19 -20
- package/src/RenderingEngine.ts +0 -1336
- package/src/index.ts +0 -81
- package/src/injectors/Tag3dGeometryCreationInjector.ts +0 -154
- package/src/injectors/TextureUnifierInjector.ts +0 -214
- package/src/interfaces/ILoader.ts +0 -3
- package/src/interfaces/IPostProcessingEffectDefinitions.ts +0 -402
- package/src/interfaces/IRenderingEngine.ts +0 -48
- package/src/loaders/EnvironmentMapLoader.ts +0 -357
- package/src/loaders/GeometryLoader.ts +0 -585
- package/src/loaders/HTMLElementAnchorLoader.ts +0 -107
- package/src/loaders/LightLoader.ts +0 -171
- package/src/loaders/MaterialLoader.ts +0 -1413
- package/src/managers/CameraManager.ts +0 -178
- package/src/managers/EnvironmentGeometryManager.ts +0 -224
- package/src/managers/PostProcessingManager.ts +0 -1181
- package/src/managers/RenderingManager.ts +0 -657
- package/src/managers/SceneTracingManager.ts +0 -127
- package/src/managers/SceneTreeManager.ts +0 -576
- package/src/managers/postprocessing/GodRaysManager.ts +0 -52
- package/src/managers/postprocessing/OutlineManager.ts +0 -58
- package/src/managers/postprocessing/SSAARenderPass.ts +0 -339
- package/src/managers/postprocessing/SelectiveBloomManager.ts +0 -58
- package/src/managers/postprocessing/ao/ao/AOEffect.ts +0 -180
- package/src/managers/postprocessing/ao/ao/AOPass.ts +0 -128
- package/src/managers/postprocessing/ao/ao/shader/ao_compose.glsl +0 -17
- package/src/managers/postprocessing/ao/ao/shader/ao_compose.ts +0 -19
- package/src/managers/postprocessing/ao/hbao/HBAOEffect.ts +0 -41
- package/src/managers/postprocessing/ao/hbao/shader/hbao.glsl +0 -96
- package/src/managers/postprocessing/ao/hbao/shader/hbao.ts +0 -98
- package/src/managers/postprocessing/ao/hbao/shader/hbao_utils.glsl +0 -92
- package/src/managers/postprocessing/ao/hbao/shader/hbao_utils.ts +0 -95
- package/src/managers/postprocessing/ao/poissionDenoise/PoissionDenoisePass.ts +0 -259
- package/src/managers/postprocessing/ao/poissionDenoise/shader/poissionDenoise.glsl +0 -125
- package/src/managers/postprocessing/ao/poissionDenoise/shader/poissionDenoise.ts +0 -127
- package/src/managers/postprocessing/ao/ssao/SSAOEffect.ts +0 -106
- package/src/managers/postprocessing/ao/ssao/shader/ssao.glsl +0 -128
- package/src/managers/postprocessing/ao/ssao/shader/ssao.ts +0 -130
- package/src/managers/postprocessing/ao/utils/shader/basic.glsl +0 -6
- package/src/managers/postprocessing/ao/utils/shader/basic.ts +0 -8
- package/src/managers/postprocessing/ao/utils/shader/sampleBlueNoise.glsl +0 -36
- package/src/managers/postprocessing/ao/utils/shader/sampleBlueNoise.ts +0 -38
- package/src/managers/postprocessing/utils/CopyMaterial.ts +0 -130
- package/src/managers/postprocessing/utils/CopyShader.ts +0 -39
- package/src/managers/postprocessing/utils/FullScreenQuad.ts +0 -47
- package/src/managers/postprocessing/utils/NormalPass.ts +0 -222
- package/src/managers/postprocessing/utils/RenderPass.ts +0 -366
- package/src/materials/GemMaterial.ts +0 -268
- package/src/materials/MeshUnlitMaterialParameters.ts +0 -4
- package/src/materials/MultiPointsMaterial.ts +0 -646
- package/src/materials/SpecularGlossinessMaterial.ts +0 -182
- package/src/objects/SDBone.ts +0 -51
- package/src/objects/SDColor.ts +0 -54
- package/src/objects/SDData.ts +0 -44
- package/src/objects/SDObject.ts +0 -58
- package/src/shaders/PCSS.ts +0 -124
- package/src/shaders/gem.ts +0 -579
- package/src/shaders/gem_frag.glsl +0 -522
- package/src/shaders/gem_vert.glsl +0 -53
- package/src/shaders/multi_points.ts +0 -291
- package/src/shaders/multi_points_frag.glsl +0 -166
- package/src/shaders/multi_points_vert.glsl +0 -120
- package/src/styling/viewport-css.ts +0 -113
- package/src/styling/viewport.css +0 -111
- package/src/three/font.ts +0 -2
- package/src/three/geometries/TextGeometry.ts +0 -58
- package/src/three/loaders/FontLoader.ts +0 -205
- package/src/three/loaders/RGBELoader.ts +0 -496
- package/src/types/IThreejsData.ts +0 -16
- package/src/types/ThreejsData.ts +0 -43
- package/tsconfig.json +0 -20
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { basic as vertexShader } from '../utils/shader/basic';
|
|
2
|
-
import {
|
|
3
|
-
Camera,
|
|
4
|
-
HalfFloatType,
|
|
5
|
-
Matrix4,
|
|
6
|
-
NearestFilter,
|
|
7
|
-
NoColorSpace,
|
|
8
|
-
RepeatWrapping,
|
|
9
|
-
ShaderMaterial,
|
|
10
|
-
Texture,
|
|
11
|
-
TextureLoader,
|
|
12
|
-
Vector2,
|
|
13
|
-
WebGLRenderer,
|
|
14
|
-
WebGLRenderTarget
|
|
15
|
-
} from 'three';
|
|
16
|
-
import { HttpClient, Logger } from '@shapediver/viewer.shared.services';
|
|
17
|
-
import { Pass } from 'postprocessing';
|
|
18
|
-
import { poissionDenoise as fragmentShader } from './shader/poissionDenoise';
|
|
19
|
-
import { sampleBlueNoise } from '../utils/shader/sampleBlueNoise';
|
|
20
|
-
|
|
21
|
-
const finalFragmentShader = fragmentShader.replace('#include <sampleBlueNoise>', sampleBlueNoise);
|
|
22
|
-
|
|
23
|
-
const defaultPoissonBlurOptions = {
|
|
24
|
-
iterations: 1,
|
|
25
|
-
radius: 8,
|
|
26
|
-
rings: 5.625,
|
|
27
|
-
lumaPhi: 10,
|
|
28
|
-
depthPhi: 2,
|
|
29
|
-
normalPhi: 3.25,
|
|
30
|
-
samples: 16,
|
|
31
|
-
distance: 1,
|
|
32
|
-
normalTexture: null
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export class PoissionDenoisePass extends Pass {
|
|
36
|
-
// #region Properties (11)
|
|
37
|
-
|
|
38
|
-
public static DefaultOptions = defaultPoissonBlurOptions;
|
|
39
|
-
public static blueNoiseTexture?: Texture;
|
|
40
|
-
|
|
41
|
-
public index = 0;
|
|
42
|
-
public inputTexture: Texture;
|
|
43
|
-
public iterations = defaultPoissonBlurOptions.iterations;
|
|
44
|
-
public radius = 8;
|
|
45
|
-
public renderTargetA: WebGLRenderTarget;
|
|
46
|
-
public renderTargetB: WebGLRenderTarget;
|
|
47
|
-
public rings = 5.625;
|
|
48
|
-
public samples = 16;
|
|
49
|
-
|
|
50
|
-
// #endregion Properties (11)
|
|
51
|
-
|
|
52
|
-
// #region Constructors (1)
|
|
53
|
-
|
|
54
|
-
constructor(camera: Camera, inputTexture: Texture, depthTexture: Texture, options: { [key: string]: unknown } = defaultPoissonBlurOptions) {
|
|
55
|
-
super('PoissionBlurPass');
|
|
56
|
-
|
|
57
|
-
if (PoissionDenoisePass.blueNoiseTexture === undefined)
|
|
58
|
-
this.loadBlueNoiseTexture();
|
|
59
|
-
|
|
60
|
-
options = { ...defaultPoissonBlurOptions, ...options };
|
|
61
|
-
|
|
62
|
-
this.inputTexture = inputTexture;
|
|
63
|
-
|
|
64
|
-
this.fullscreenMaterial = new ShaderMaterial({
|
|
65
|
-
fragmentShader: finalFragmentShader,
|
|
66
|
-
vertexShader,
|
|
67
|
-
uniforms: {
|
|
68
|
-
depthTexture: { value: null },
|
|
69
|
-
inputTexture: { value: null },
|
|
70
|
-
projectionMatrixInverse: { value: new Matrix4() },
|
|
71
|
-
cameraMatrixWorld: { value: new Matrix4() },
|
|
72
|
-
lumaPhi: { value: 5.0 },
|
|
73
|
-
depthPhi: { value: 5.0 },
|
|
74
|
-
normalPhi: { value: 5.0 },
|
|
75
|
-
distance: { value: 1.0 },
|
|
76
|
-
resolution: { value: new Vector2() },
|
|
77
|
-
blueNoiseTexture: { value: null },
|
|
78
|
-
index: { value: 0 },
|
|
79
|
-
blueNoiseRepeat: { value: new Vector2() }
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const renderTargetOptions = {
|
|
84
|
-
type: HalfFloatType,
|
|
85
|
-
depthBuffer: false
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
this.renderTargetA = new WebGLRenderTarget(1, 1, renderTargetOptions);
|
|
89
|
-
this.renderTargetB = new WebGLRenderTarget(1, 1, renderTargetOptions);
|
|
90
|
-
|
|
91
|
-
const { uniforms } = (this.fullscreenMaterial as ShaderMaterial);
|
|
92
|
-
|
|
93
|
-
uniforms['inputTexture'].value = this.inputTexture;
|
|
94
|
-
uniforms['depthTexture'].value = depthTexture;
|
|
95
|
-
uniforms['projectionMatrixInverse'].value = camera.projectionMatrixInverse;
|
|
96
|
-
uniforms['cameraMatrixWorld'].value = camera.matrixWorld;
|
|
97
|
-
uniforms['depthPhi'].value = options.depthPhi;
|
|
98
|
-
uniforms['normalPhi'].value = options.normalPhi;
|
|
99
|
-
uniforms['distance'].value = options.distance;
|
|
100
|
-
|
|
101
|
-
if (options.normalTexture) {
|
|
102
|
-
uniforms['normalTexture'] = { value: options.normalTexture };
|
|
103
|
-
} else {
|
|
104
|
-
(this.fullscreenMaterial as ShaderMaterial).defines.NORMAL_IN_RGB = '';
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// these properties need the shader to be recompiled
|
|
108
|
-
for (const prop of ['radius', 'rings', 'samples']) {
|
|
109
|
-
Object.defineProperty(this, prop, {
|
|
110
|
-
get: () => options[prop],
|
|
111
|
-
set: value => {
|
|
112
|
-
options[prop] = value;
|
|
113
|
-
|
|
114
|
-
this.setSize(this.renderTargetA.width, this.renderTargetA.height);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
private async loadBlueNoiseTexture() {
|
|
121
|
-
const result = await HttpClient.instance.loadTexture('https://viewer.shapediver.com/v3/graphics/LDR_RGBA_0.png');
|
|
122
|
-
|
|
123
|
-
if (result) {
|
|
124
|
-
const url = URL.createObjectURL(result.data.blob);
|
|
125
|
-
new TextureLoader().load(url, texture => {
|
|
126
|
-
URL.revokeObjectURL(url);
|
|
127
|
-
PoissionDenoisePass.blueNoiseTexture = texture;
|
|
128
|
-
PoissionDenoisePass.blueNoiseTexture.minFilter = NearestFilter;
|
|
129
|
-
PoissionDenoisePass.blueNoiseTexture.magFilter = NearestFilter;
|
|
130
|
-
PoissionDenoisePass.blueNoiseTexture.wrapS = RepeatWrapping;
|
|
131
|
-
PoissionDenoisePass.blueNoiseTexture.wrapT = RepeatWrapping;
|
|
132
|
-
PoissionDenoisePass.blueNoiseTexture.colorSpace = NoColorSpace;
|
|
133
|
-
PoissionDenoisePass.blueNoiseTexture.needsUpdate = true;
|
|
134
|
-
|
|
135
|
-
(this.fullscreenMaterial as ShaderMaterial).uniforms.blueNoiseTexture.value = PoissionDenoisePass.blueNoiseTexture;
|
|
136
|
-
});
|
|
137
|
-
} else {
|
|
138
|
-
Logger.instance.warn('The blue noise texture could not be loaded. This may result in a suboptimal denoising quality. Retrying in 1 second...');
|
|
139
|
-
|
|
140
|
-
// if there was an issue loading the texture
|
|
141
|
-
// set a timeout with 1 second to try again
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
this.loadBlueNoiseTexture();
|
|
144
|
-
}, 1000);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// #endregion Constructors (1)
|
|
149
|
-
|
|
150
|
-
// #region Public Getters And Setters (1)
|
|
151
|
-
|
|
152
|
-
public get texture() {
|
|
153
|
-
return this.renderTargetB.texture;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// #endregion Public Getters And Setters (1)
|
|
157
|
-
|
|
158
|
-
// #region Public Methods (4)
|
|
159
|
-
|
|
160
|
-
public generateDenoiseSamples(numSamples: number, numRings: number, r: number, texelSize: Vector2) {
|
|
161
|
-
const angleStep = (2 * Math.PI * numRings) / numSamples;
|
|
162
|
-
const invNumSamples = 1.0 / numSamples;
|
|
163
|
-
const radiusStep = invNumSamples;
|
|
164
|
-
const samples = [];
|
|
165
|
-
let radius = invNumSamples;
|
|
166
|
-
let angle = 0;
|
|
167
|
-
|
|
168
|
-
for (let i = 0; i < numSamples; i++) {
|
|
169
|
-
const v = new Vector2(Math.cos(angle), Math.sin(angle))
|
|
170
|
-
.multiplyScalar(Math.pow(radius, 0.75))
|
|
171
|
-
.multiply(texelSize)
|
|
172
|
-
.multiplyScalar(r);
|
|
173
|
-
|
|
174
|
-
if (isNaN(v.x) || v.x === Infinity || v.x === -Infinity)
|
|
175
|
-
v.x = 0;
|
|
176
|
-
|
|
177
|
-
if (isNaN(v.y) || v.y === Infinity || v.y === -Infinity)
|
|
178
|
-
v.y = 0;
|
|
179
|
-
|
|
180
|
-
samples.push(v);
|
|
181
|
-
radius += radiusStep;
|
|
182
|
-
angle += angleStep;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return samples;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
public generatePoissonDiskConstant(poissonDisk: Vector2[]) {
|
|
189
|
-
const samples = poissonDisk.length;
|
|
190
|
-
|
|
191
|
-
let glslCode = 'const vec2 poissonDisk[samples] = vec2[samples](\n';
|
|
192
|
-
|
|
193
|
-
for (let i = 0; i < samples; i++) {
|
|
194
|
-
const sample = poissonDisk[i];
|
|
195
|
-
glslCode += ` vec2(${sample.x}, ${sample.y})`;
|
|
196
|
-
|
|
197
|
-
if (i < samples - 1) {
|
|
198
|
-
glslCode += ',';
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
glslCode += '\n';
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
glslCode += ');';
|
|
205
|
-
|
|
206
|
-
return glslCode;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
public render(renderer: WebGLRenderer) {
|
|
210
|
-
(this.fullscreenMaterial as ShaderMaterial).uniforms.index.value = 0;
|
|
211
|
-
|
|
212
|
-
const noiseTexture = (this.fullscreenMaterial as ShaderMaterial).uniforms.blueNoiseTexture.value;
|
|
213
|
-
if (noiseTexture !== undefined && noiseTexture !== null && noiseTexture instanceof Texture) {
|
|
214
|
-
const { width, height } = (noiseTexture as Texture).source.data;
|
|
215
|
-
|
|
216
|
-
(this.fullscreenMaterial as ShaderMaterial).uniforms.blueNoiseRepeat.value.set(
|
|
217
|
-
this.renderTargetA.width / width,
|
|
218
|
-
this.renderTargetA.height / height
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
for (let i = 0; i < 2 * this.iterations; i++) {
|
|
223
|
-
const horizontal = i % 2 === 0;
|
|
224
|
-
|
|
225
|
-
const inputRenderTarget = horizontal ? this.renderTargetB : this.renderTargetA;
|
|
226
|
-
(this.fullscreenMaterial as ShaderMaterial).uniforms['inputTexture'].value = i === 0 ? this.inputTexture : inputRenderTarget.texture;
|
|
227
|
-
|
|
228
|
-
const renderTarget = horizontal ? this.renderTargetA : this.renderTargetB;
|
|
229
|
-
|
|
230
|
-
renderer.setRenderTarget(renderTarget);
|
|
231
|
-
renderer.render(this.scene, this.camera);
|
|
232
|
-
|
|
233
|
-
(this.fullscreenMaterial as ShaderMaterial).uniforms.index.value = ((this.fullscreenMaterial as ShaderMaterial).uniforms.index.value + 1) % 4;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
public setSize(width: number, height: number) {
|
|
238
|
-
this.renderTargetA.setSize(width, height);
|
|
239
|
-
this.renderTargetB.setSize(width, height);
|
|
240
|
-
|
|
241
|
-
(this.fullscreenMaterial as ShaderMaterial).uniforms.resolution.value.set(width, height);
|
|
242
|
-
|
|
243
|
-
const poissonDisk = this.generateDenoiseSamples(
|
|
244
|
-
this.samples,
|
|
245
|
-
this.rings,
|
|
246
|
-
this.radius,
|
|
247
|
-
new Vector2(1 / width, 1 / height)
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
const sampleDefine = `const int samples = ${this.samples};\n`;
|
|
251
|
-
|
|
252
|
-
const poissonDiskConstant = this.generatePoissonDiskConstant(poissonDisk);
|
|
253
|
-
|
|
254
|
-
(this.fullscreenMaterial as ShaderMaterial).fragmentShader = sampleDefine + poissonDiskConstant + '\n' + finalFragmentShader;
|
|
255
|
-
(this.fullscreenMaterial as ShaderMaterial).needsUpdate = true;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// #endregion Public Methods (4)
|
|
259
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
varying vec2 vUv;
|
|
2
|
-
|
|
3
|
-
uniform sampler2D inputTexture;
|
|
4
|
-
uniform sampler2D depthTexture;
|
|
5
|
-
uniform sampler2D normalTexture;
|
|
6
|
-
uniform mat4 projectionMatrixInverse;
|
|
7
|
-
uniform mat4 cameraMatrixWorld;
|
|
8
|
-
uniform float lumaPhi;
|
|
9
|
-
uniform float depthPhi;
|
|
10
|
-
uniform float normalPhi;
|
|
11
|
-
uniform float distance;
|
|
12
|
-
uniform sampler2D blueNoiseTexture;
|
|
13
|
-
uniform vec2 blueNoiseRepeat;
|
|
14
|
-
uniform int index;
|
|
15
|
-
uniform vec2 resolution;
|
|
16
|
-
|
|
17
|
-
#include <common>
|
|
18
|
-
#include <sampleBlueNoise>
|
|
19
|
-
|
|
20
|
-
vec3 getWorldPos(float depth, vec2 coord) {
|
|
21
|
-
float z = depth * 2.0 - 1.0;
|
|
22
|
-
vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
|
|
23
|
-
vec4 viewSpacePosition = projectionMatrixInverse * clipSpacePosition;
|
|
24
|
-
|
|
25
|
-
// Perspective division
|
|
26
|
-
vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition;
|
|
27
|
-
worldSpacePosition.xyz /= worldSpacePosition.w;
|
|
28
|
-
return worldSpacePosition.xyz;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#define luminance(a) dot(vec3(0.2125, 0.7154, 0.0721), a)
|
|
32
|
-
|
|
33
|
-
vec3 getNormal(vec2 uv, vec4 texel) {
|
|
34
|
-
#ifdef NORMAL_IN_RGB
|
|
35
|
-
// in case the normal is stored in the RGB channels of the texture
|
|
36
|
-
return texel.rgb;
|
|
37
|
-
#else
|
|
38
|
-
return normalize(textureLod(normalTexture, uv, 0.).xyz * 2.0 - 1.0);
|
|
39
|
-
#endif
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
float distToPlane(const vec3 worldPos, const vec3 neighborWorldPos, const vec3 worldNormal) {
|
|
43
|
-
vec3 toCurrent = worldPos - neighborWorldPos;
|
|
44
|
-
float distToPlane = abs(dot(toCurrent, worldNormal));
|
|
45
|
-
|
|
46
|
-
return distToPlane;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
void main() {
|
|
50
|
-
vec4 depthTexel = textureLod(depthTexture, vUv, 0.);
|
|
51
|
-
|
|
52
|
-
if (depthTexel.r == 1.0 || dot(depthTexel.rgb, depthTexel.rgb) == 0.) {
|
|
53
|
-
discard;
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
vec4 texel = textureLod(inputTexture, vUv, 0.0);
|
|
58
|
-
|
|
59
|
-
vec3 normal = getNormal(vUv, texel);
|
|
60
|
-
|
|
61
|
-
#ifdef NORMAL_IN_RGB
|
|
62
|
-
float denoised = texel.a;
|
|
63
|
-
float center = texel.a;
|
|
64
|
-
#else
|
|
65
|
-
vec3 denoised = texel.rgb;
|
|
66
|
-
vec3 center = texel.rgb;
|
|
67
|
-
#endif
|
|
68
|
-
|
|
69
|
-
float depth = depthTexel.x;
|
|
70
|
-
vec3 worldPos = getWorldPos(depth, vUv);
|
|
71
|
-
|
|
72
|
-
float totalWeight = 1.0;
|
|
73
|
-
|
|
74
|
-
vec4 blueNoise = sampleBlueNoise(blueNoiseTexture, 0, blueNoiseRepeat, resolution);
|
|
75
|
-
float angle = blueNoise[index];
|
|
76
|
-
|
|
77
|
-
float s = sin(angle), c = cos(angle);
|
|
78
|
-
|
|
79
|
-
mat2 rotationMatrix = mat2(c, -s, s, c);
|
|
80
|
-
|
|
81
|
-
for (int i = 0; i < samples; i++) {
|
|
82
|
-
vec2 offset = rotationMatrix * poissonDisk[i];
|
|
83
|
-
vec2 neighborUv = vUv + offset;
|
|
84
|
-
|
|
85
|
-
vec4 neighborTexel = textureLod(inputTexture, neighborUv, 0.0);
|
|
86
|
-
|
|
87
|
-
vec3 neighborNormal = getNormal(neighborUv, neighborTexel);
|
|
88
|
-
#ifdef NORMAL_IN_RGB
|
|
89
|
-
float neighborColor = neighborTexel.a;
|
|
90
|
-
#else
|
|
91
|
-
vec3 neighborColor = neighborTexel.rgb;
|
|
92
|
-
#endif
|
|
93
|
-
|
|
94
|
-
float sampleDepth = textureLod(depthTexture, neighborUv, 0.0).x;
|
|
95
|
-
|
|
96
|
-
vec3 worldPosSample = getWorldPos(sampleDepth, neighborUv);
|
|
97
|
-
float tangentPlaneDist = abs(dot(worldPos - worldPosSample, normal));
|
|
98
|
-
|
|
99
|
-
float normalDiff = dot(normal, neighborNormal);
|
|
100
|
-
float normalSimilarity = pow(max(normalDiff, 0.), normalPhi);
|
|
101
|
-
|
|
102
|
-
#ifdef NORMAL_IN_RGB
|
|
103
|
-
float lumaDiff = abs(neighborColor - center);
|
|
104
|
-
#else
|
|
105
|
-
float lumaDiff = abs(luminance(neighborColor) - luminance(center));
|
|
106
|
-
#endif
|
|
107
|
-
float lumaSimilarity = max(1.0 - lumaDiff / lumaPhi, 0.0);
|
|
108
|
-
|
|
109
|
-
float depthDiff = 1. - (distToPlane(worldPos, worldPosSample, normal) / distance);
|
|
110
|
-
float depthSimilarity = max(depthDiff / depthPhi, 0.);
|
|
111
|
-
|
|
112
|
-
float w = lumaSimilarity * depthSimilarity * normalSimilarity;
|
|
113
|
-
|
|
114
|
-
denoised += w * neighborColor;
|
|
115
|
-
totalWeight += w;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (totalWeight > 0.) denoised /= totalWeight;
|
|
119
|
-
|
|
120
|
-
#ifdef NORMAL_IN_RGB
|
|
121
|
-
gl_FragColor = vec4(normal, denoised);
|
|
122
|
-
#else
|
|
123
|
-
gl_FragColor = vec4(denoised, 1.);
|
|
124
|
-
#endif
|
|
125
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
export const poissionDenoise = `
|
|
2
|
-
varying vec2 vUv;
|
|
3
|
-
|
|
4
|
-
uniform sampler2D inputTexture;
|
|
5
|
-
uniform highp sampler2D depthTexture;
|
|
6
|
-
uniform sampler2D normalTexture;
|
|
7
|
-
uniform mat4 projectionMatrixInverse;
|
|
8
|
-
uniform mat4 cameraMatrixWorld;
|
|
9
|
-
uniform float lumaPhi;
|
|
10
|
-
uniform float depthPhi;
|
|
11
|
-
uniform float normalPhi;
|
|
12
|
-
uniform float distance;
|
|
13
|
-
uniform sampler2D blueNoiseTexture;
|
|
14
|
-
uniform vec2 blueNoiseRepeat;
|
|
15
|
-
uniform int index;
|
|
16
|
-
uniform vec2 resolution;
|
|
17
|
-
|
|
18
|
-
#include <common>
|
|
19
|
-
#include <sampleBlueNoise>
|
|
20
|
-
|
|
21
|
-
vec3 getWorldPos(float depth, vec2 coord) {
|
|
22
|
-
float z = depth * 2.0 - 1.0;
|
|
23
|
-
vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
|
|
24
|
-
vec4 viewSpacePosition = projectionMatrixInverse * clipSpacePosition;
|
|
25
|
-
|
|
26
|
-
// Perspective division
|
|
27
|
-
vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition;
|
|
28
|
-
worldSpacePosition.xyz /= worldSpacePosition.w;
|
|
29
|
-
return worldSpacePosition.xyz;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
#define luminance(a) dot(vec3(0.2125, 0.7154, 0.0721), a)
|
|
33
|
-
|
|
34
|
-
vec3 getNormal(vec2 uv, vec4 texel) {
|
|
35
|
-
#ifdef NORMAL_IN_RGB
|
|
36
|
-
// in case the normal is stored in the RGB channels of the texture
|
|
37
|
-
return texel.rgb;
|
|
38
|
-
#else
|
|
39
|
-
return normalize(textureLod(normalTexture, uv, 0.).xyz * 2.0 - 1.0);
|
|
40
|
-
#endif
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
float distToPlane(const vec3 worldPos, const vec3 neighborWorldPos, const vec3 worldNormal) {
|
|
44
|
-
vec3 toCurrent = worldPos - neighborWorldPos;
|
|
45
|
-
float distToPlane = abs(dot(toCurrent, worldNormal));
|
|
46
|
-
|
|
47
|
-
return distToPlane;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
void main() {
|
|
51
|
-
vec4 depthTexel = textureLod(depthTexture, vUv, 0.);
|
|
52
|
-
|
|
53
|
-
if (depthTexel.r == 1.0 || dot(depthTexel.rgb, depthTexel.rgb) == 0.) {
|
|
54
|
-
discard;
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
vec4 texel = textureLod(inputTexture, vUv, 0.0);
|
|
59
|
-
|
|
60
|
-
vec3 normal = getNormal(vUv, texel);
|
|
61
|
-
|
|
62
|
-
#ifdef NORMAL_IN_RGB
|
|
63
|
-
float denoised = texel.a;
|
|
64
|
-
float center = texel.a;
|
|
65
|
-
#else
|
|
66
|
-
vec3 denoised = texel.rgb;
|
|
67
|
-
vec3 center = texel.rgb;
|
|
68
|
-
#endif
|
|
69
|
-
|
|
70
|
-
float depth = depthTexel.x;
|
|
71
|
-
vec3 worldPos = getWorldPos(depth, vUv);
|
|
72
|
-
|
|
73
|
-
float totalWeight = 1.0;
|
|
74
|
-
|
|
75
|
-
vec4 blueNoise = sampleBlueNoise(blueNoiseTexture, 0, blueNoiseRepeat, resolution);
|
|
76
|
-
float angle = blueNoise[index];
|
|
77
|
-
|
|
78
|
-
float s = sin(angle), c = cos(angle);
|
|
79
|
-
|
|
80
|
-
mat2 rotationMatrix = mat2(c, -s, s, c);
|
|
81
|
-
|
|
82
|
-
for (int i = 0; i < samples; i++) {
|
|
83
|
-
vec2 offset = rotationMatrix * poissonDisk[i];
|
|
84
|
-
vec2 neighborUv = vUv + offset;
|
|
85
|
-
|
|
86
|
-
vec4 neighborTexel = textureLod(inputTexture, neighborUv, 0.0);
|
|
87
|
-
|
|
88
|
-
vec3 neighborNormal = getNormal(neighborUv, neighborTexel);
|
|
89
|
-
#ifdef NORMAL_IN_RGB
|
|
90
|
-
float neighborColor = neighborTexel.a;
|
|
91
|
-
#else
|
|
92
|
-
vec3 neighborColor = neighborTexel.rgb;
|
|
93
|
-
#endif
|
|
94
|
-
|
|
95
|
-
float sampleDepth = textureLod(depthTexture, neighborUv, 0.0).x;
|
|
96
|
-
|
|
97
|
-
vec3 worldPosSample = getWorldPos(sampleDepth, neighborUv);
|
|
98
|
-
float tangentPlaneDist = abs(dot(worldPos - worldPosSample, normal));
|
|
99
|
-
|
|
100
|
-
float normalDiff = dot(normal, neighborNormal);
|
|
101
|
-
float normalSimilarity = pow(max(normalDiff, 0.), normalPhi);
|
|
102
|
-
|
|
103
|
-
#ifdef NORMAL_IN_RGB
|
|
104
|
-
float lumaDiff = abs(neighborColor - center);
|
|
105
|
-
#else
|
|
106
|
-
float lumaDiff = abs(luminance(neighborColor) - luminance(center));
|
|
107
|
-
#endif
|
|
108
|
-
float lumaSimilarity = max(1.0 - lumaDiff / lumaPhi, 0.0);
|
|
109
|
-
|
|
110
|
-
float depthDiff = 1. - (distToPlane(worldPos, worldPosSample, normal) / distance);
|
|
111
|
-
float depthSimilarity = max(depthDiff / depthPhi, 0.);
|
|
112
|
-
|
|
113
|
-
float w = lumaSimilarity * depthSimilarity * normalSimilarity;
|
|
114
|
-
|
|
115
|
-
denoised += w * neighborColor;
|
|
116
|
-
totalWeight += w;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (totalWeight > 0.) denoised /= totalWeight;
|
|
120
|
-
|
|
121
|
-
#ifdef NORMAL_IN_RGB
|
|
122
|
-
gl_FragColor = vec4(normal, denoised);
|
|
123
|
-
#else
|
|
124
|
-
gl_FragColor = vec4(denoised, 1.);
|
|
125
|
-
#endif
|
|
126
|
-
}
|
|
127
|
-
`
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { EffectComposer } from 'postprocessing';
|
|
2
|
-
import { Camera, Scene, Vector3 } from 'three';
|
|
3
|
-
import { AOEffect } from '../ao/AOEffect';
|
|
4
|
-
import { AOPass } from '../ao/AOPass';
|
|
5
|
-
import { ssao as fragmentShader } from './shader/ssao';
|
|
6
|
-
|
|
7
|
-
class SSAOPass extends AOPass {
|
|
8
|
-
// #region Constructors (1)
|
|
9
|
-
|
|
10
|
-
constructor(camera: Camera, scene: Scene) {
|
|
11
|
-
super(camera, scene, fragmentShader);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// #endregion Constructors (1)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class SSAOEffect extends AOEffect {
|
|
18
|
-
// #region Properties (1)
|
|
19
|
-
|
|
20
|
-
public spp = 16;
|
|
21
|
-
|
|
22
|
-
// #endregion Properties (1)
|
|
23
|
-
|
|
24
|
-
// #region Constructors (1)
|
|
25
|
-
|
|
26
|
-
constructor(composer: EffectComposer, camera: Camera, scene: Scene, options?: { [key: string]: unknown }) {
|
|
27
|
-
super(composer, camera, scene, new SSAOPass(camera, scene), options);
|
|
28
|
-
|
|
29
|
-
SSAOEffect.DefaultOptions = {
|
|
30
|
-
...AOEffect.DefaultOptions,
|
|
31
|
-
...{
|
|
32
|
-
spp: 16,
|
|
33
|
-
distance: 1,
|
|
34
|
-
distancePower: 0.25,
|
|
35
|
-
power: 2
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
options = {
|
|
40
|
-
...SSAOEffect.DefaultOptions,
|
|
41
|
-
...options
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// #endregion Constructors (1)
|
|
46
|
-
|
|
47
|
-
// #region Public Methods (2)
|
|
48
|
-
|
|
49
|
-
public getPointsOnSphere(n: number) {
|
|
50
|
-
const points = [];
|
|
51
|
-
const inc = Math.PI * (3 - Math.sqrt(5));
|
|
52
|
-
const off = 2 / n;
|
|
53
|
-
|
|
54
|
-
for (let k = 0; k < n; k++) {
|
|
55
|
-
const y = k * off - 1 + off / 2;
|
|
56
|
-
const r = Math.sqrt(1 - y * y);
|
|
57
|
-
const phi = k * inc;
|
|
58
|
-
points.push(new Vector3(Math.cos(phi) * r, y, Math.sin(phi) * r));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return points;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public makeOptionsReactive(options: { [key: string]: unknown }) {
|
|
65
|
-
super.makeOptionsReactive(options);
|
|
66
|
-
|
|
67
|
-
for (const key of ['spp']) {
|
|
68
|
-
Object.defineProperty(this, key, {
|
|
69
|
-
get() {
|
|
70
|
-
return options[key];
|
|
71
|
-
},
|
|
72
|
-
set(value) {
|
|
73
|
-
if (value === null || value === undefined) return;
|
|
74
|
-
|
|
75
|
-
options[key] = value;
|
|
76
|
-
|
|
77
|
-
switch (key) {
|
|
78
|
-
case 'spp': {
|
|
79
|
-
this.aoPass.fullscreenMaterial.defines.spp = value.toFixed(0);
|
|
80
|
-
|
|
81
|
-
const samples = this.getPointsOnSphere(value);
|
|
82
|
-
|
|
83
|
-
const samplesR = [];
|
|
84
|
-
for (let i = 0; i < value; i++) {
|
|
85
|
-
samplesR.push((i + 1) / value);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.aoPass.fullscreenMaterial.uniforms.samples = { value: samples };
|
|
89
|
-
this.aoPass.fullscreenMaterial.uniforms.samplesR = { value: samplesR };
|
|
90
|
-
|
|
91
|
-
this.aoPass.fullscreenMaterial.needsUpdate = true;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
configurable: true
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
this.spp = options['spp'] as number;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// #endregion Public Methods (2)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export { SSAOEffect };
|