three-gpu-pathtracer 0.0.3 → 0.0.4
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/LICENSE +21 -21
- package/README.md +678 -660
- package/build/index.module.js +3190 -2980
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +3193 -2983
- package/build/index.umd.cjs.map +1 -1
- package/package.json +2 -2
- package/src/core/DynamicPathTracingSceneGenerator.js +106 -106
- package/src/core/MaterialReducer.js +256 -256
- package/src/core/PathTracingRenderer.js +237 -233
- package/src/core/PathTracingSceneGenerator.js +52 -52
- package/src/core/PhysicalCamera.js +28 -28
- package/src/index.js +25 -25
- package/src/materials/AlphaDisplayMaterial.js +48 -48
- package/src/materials/AmbientOcclusionMaterial.js +197 -197
- package/src/materials/BlendMaterial.js +67 -67
- package/src/materials/LambertPathTracingMaterial.js +285 -285
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/PhysicalPathTracingMaterial.js +684 -632
- package/src/shader/shaderGGXFunctions.js +108 -107
- package/src/shader/shaderMaterialSampling.js +345 -340
- package/src/shader/shaderStructs.js +46 -7
- package/src/shader/shaderUtils.js +246 -228
- package/src/uniforms/EquirectHdrInfoUniform.js +263 -263
- package/src/uniforms/MaterialsTexture.js +251 -173
- package/src/uniforms/PhysicalCameraUniform.js +36 -36
- package/src/uniforms/RenderTarget2DArray.js +17 -4
- package/src/utils/BlurredEnvMapGenerator.js +113 -113
- package/src/utils/GeometryPreparationUtils.js +194 -194
- package/src/utils/UVUnwrapper.js +101 -101
- package/src/workers/PathTracingSceneWorker.js +40 -40
|
@@ -41,17 +41,42 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
41
41
|
int normalMap;
|
|
42
42
|
vec2 normalScale;
|
|
43
43
|
|
|
44
|
+
int alphaMap;
|
|
45
|
+
|
|
46
|
+
bool castShadow;
|
|
44
47
|
float opacity;
|
|
45
48
|
float alphaTest;
|
|
46
49
|
|
|
47
50
|
float side;
|
|
48
51
|
bool matte;
|
|
49
52
|
|
|
53
|
+
mat3 mapTransform;
|
|
54
|
+
mat3 metalnessMapTransform;
|
|
55
|
+
mat3 roughnessMapTransform;
|
|
56
|
+
mat3 transmissionMapTransform;
|
|
57
|
+
mat3 emissiveMapTransform;
|
|
58
|
+
mat3 normalMapTransform;
|
|
59
|
+
|
|
50
60
|
};
|
|
51
61
|
|
|
62
|
+
mat3 readTextureTransform( sampler2D tex, uint index ) {
|
|
63
|
+
|
|
64
|
+
mat3 textureTransform;
|
|
65
|
+
|
|
66
|
+
vec4 row1 = texelFetch1D( tex, index );
|
|
67
|
+
vec4 row2 = texelFetch1D( tex, index + 1u );
|
|
68
|
+
|
|
69
|
+
textureTransform[0] = vec3(row1.r, row2.r, 0.0);
|
|
70
|
+
textureTransform[1] = vec3(row1.g, row2.g, 0.0);
|
|
71
|
+
textureTransform[2] = vec3(row1.b, row2.b, 1.0);
|
|
72
|
+
|
|
73
|
+
return textureTransform;
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
52
77
|
Material readMaterialInfo( sampler2D tex, uint index ) {
|
|
53
78
|
|
|
54
|
-
uint i = index *
|
|
79
|
+
uint i = index * 19u;
|
|
55
80
|
|
|
56
81
|
vec4 s0 = texelFetch1D( tex, i + 0u );
|
|
57
82
|
vec4 s1 = texelFetch1D( tex, i + 1u );
|
|
@@ -59,32 +84,46 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
59
84
|
vec4 s3 = texelFetch1D( tex, i + 3u );
|
|
60
85
|
vec4 s4 = texelFetch1D( tex, i + 4u );
|
|
61
86
|
vec4 s5 = texelFetch1D( tex, i + 5u );
|
|
87
|
+
vec4 s6 = texelFetch1D( tex, i + 6u );
|
|
62
88
|
|
|
63
89
|
Material m;
|
|
64
90
|
m.color = s0.rgb;
|
|
65
|
-
m.map =
|
|
91
|
+
m.map = int( round( s0.a ) );
|
|
66
92
|
|
|
67
93
|
m.metalness = s1.r;
|
|
68
|
-
m.metalnessMap =
|
|
94
|
+
m.metalnessMap = int( round( s1.g ) );
|
|
69
95
|
m.roughness = s1.b;
|
|
70
|
-
m.roughnessMap =
|
|
96
|
+
m.roughnessMap = int( round( s1.a ) );
|
|
71
97
|
|
|
72
98
|
m.ior = s2.r;
|
|
73
99
|
m.transmission = s2.g;
|
|
74
|
-
m.transmissionMap =
|
|
100
|
+
m.transmissionMap = int( round( s2.b ) );
|
|
75
101
|
m.emissiveIntensity = s2.a;
|
|
76
102
|
|
|
77
103
|
m.emissive = s3.rgb;
|
|
78
|
-
m.emissiveMap =
|
|
104
|
+
m.emissiveMap = int( round( s3.a ) );
|
|
79
105
|
|
|
80
|
-
m.normalMap =
|
|
106
|
+
m.normalMap = int( round( s4.r ) );
|
|
81
107
|
m.normalScale = s4.gb;
|
|
82
108
|
|
|
109
|
+
m.alphaMap = int( round( s4.a ) );
|
|
110
|
+
|
|
83
111
|
m.opacity = s5.r;
|
|
84
112
|
m.alphaTest = s5.g;
|
|
85
113
|
m.side = s5.b;
|
|
86
114
|
m.matte = bool( s5.a );
|
|
87
115
|
|
|
116
|
+
m.castShadow = ! bool( s6.r );
|
|
117
|
+
|
|
118
|
+
uint firstTextureTransformIdx = i + 7u;
|
|
119
|
+
|
|
120
|
+
m.mapTransform = m.map == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx);
|
|
121
|
+
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );
|
|
122
|
+
m.roughnessMapTransform = m.roughnessMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 4u );
|
|
123
|
+
m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );
|
|
124
|
+
m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );
|
|
125
|
+
m.normalMapTransform = m.normalMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );
|
|
126
|
+
|
|
88
127
|
return m;
|
|
89
128
|
|
|
90
129
|
}
|
|
@@ -1,228 +1,246 @@
|
|
|
1
|
-
export const shaderUtils = /* glsl */`
|
|
2
|
-
|
|
3
|
-
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
|
|
4
|
-
float schlickFresnel( float cosine, float f0 ) {
|
|
5
|
-
|
|
6
|
-
return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation
|
|
11
|
-
float schlickFresnelFromIor( float cosine, float iorRatio ) {
|
|
12
|
-
|
|
13
|
-
// Schlick approximation
|
|
14
|
-
float r_0 = pow( ( 1.0 - iorRatio ) / ( 1.0 + iorRatio ), 2.0 );
|
|
15
|
-
return schlickFresnel( cosine, r_0 );
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// forms a basis with the normal vector as Z
|
|
20
|
-
mat3 getBasisFromNormal( vec3 normal ) {
|
|
21
|
-
|
|
22
|
-
vec3 other;
|
|
23
|
-
if ( abs( normal.x ) > 0.5 ) {
|
|
24
|
-
|
|
25
|
-
other = vec3( 0.0, 1.0, 0.0 );
|
|
26
|
-
|
|
27
|
-
} else {
|
|
28
|
-
|
|
29
|
-
other = vec3( 1.0, 0.0, 0.0 );
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
vec3 ortho = normalize( cross( normal, other ) );
|
|
34
|
-
vec3 ortho2 = normalize( cross( normal, ortho ) );
|
|
35
|
-
return mat3( ortho2, ortho, normal );
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
vec3 getHalfVector( vec3 a, vec3 b ) {
|
|
40
|
-
|
|
41
|
-
return normalize( a + b );
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray
|
|
46
|
-
// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If
|
|
47
|
-
// we find a ray like that we ignore it to avoid artifacts.
|
|
48
|
-
// This function returns if the direction is on the same side of both planes.
|
|
49
|
-
bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {
|
|
50
|
-
|
|
51
|
-
bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;
|
|
52
|
-
bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;
|
|
53
|
-
return aboveSurfaceNormal == aboveGeometryNormal;
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
vec3 getHemisphereSample( vec3 n, vec2 uv ) {
|
|
58
|
-
|
|
59
|
-
// https://www.rorydriscoll.com/2009/01/07/better-sampling/
|
|
60
|
-
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
|
|
61
|
-
float sign = n.z == 0.0 ? 1.0 : sign( n.z );
|
|
62
|
-
float a = - 1.0 / ( sign + n.z );
|
|
63
|
-
float b = n.x * n.y * a;
|
|
64
|
-
vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
|
|
65
|
-
vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
|
|
66
|
-
|
|
67
|
-
float r = sqrt( uv.x );
|
|
68
|
-
float theta = 2.0 * PI * uv.y;
|
|
69
|
-
float x = r * cos( theta );
|
|
70
|
-
float y = r * sin( theta );
|
|
71
|
-
return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// https://www.shadertoy.com/view/wltcRS
|
|
76
|
-
uvec4 s0;
|
|
77
|
-
|
|
78
|
-
void rng_initialize(vec2 p, int frame) {
|
|
79
|
-
|
|
80
|
-
// white noise seed
|
|
81
|
-
s0 = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// https://www.pcg-random.org/
|
|
86
|
-
void pcg4d( inout uvec4 v ) {
|
|
87
|
-
|
|
88
|
-
v = v * 1664525u + 1013904223u;
|
|
89
|
-
v.x += v.y * v.w;
|
|
90
|
-
v.y += v.z * v.x;
|
|
91
|
-
v.z += v.x * v.y;
|
|
92
|
-
v.w += v.y * v.z;
|
|
93
|
-
v = v ^ ( v >> 16u );
|
|
94
|
-
v.x += v.y*v.w;
|
|
95
|
-
v.y += v.z*v.x;
|
|
96
|
-
v.z += v.x*v.y;
|
|
97
|
-
v.w += v.y*v.z;
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// returns [ 0, 1 ]
|
|
102
|
-
float rand() {
|
|
103
|
-
|
|
104
|
-
pcg4d(s0);
|
|
105
|
-
return float( s0.x ) / float( 0xffffffffu );
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
vec2 rand2() {
|
|
110
|
-
|
|
111
|
-
pcg4d( s0 );
|
|
112
|
-
return vec2( s0.xy ) / float(0xffffffffu);
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
vec3 rand3() {
|
|
117
|
-
|
|
118
|
-
pcg4d(s0);
|
|
119
|
-
return vec3( s0.xyz ) / float( 0xffffffffu );
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
vec4 rand4() {
|
|
124
|
-
|
|
125
|
-
pcg4d(s0);
|
|
126
|
-
return vec4(s0)/float(0xffffffffu);
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// https://github.com/mrdoob/three.js/blob/dev/src/math/Vector3.js#L724
|
|
131
|
-
vec3 randDirection() {
|
|
132
|
-
|
|
133
|
-
vec2 r = rand2();
|
|
134
|
-
float u = ( r.x - 0.5 ) * 2.0;
|
|
135
|
-
float t = r.y * PI * 2.0;
|
|
136
|
-
float f = sqrt( 1.0 - u * u );
|
|
137
|
-
|
|
138
|
-
return vec3( f * cos( t ), f * sin( t ), u );
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
vec2 triangleSample( vec2 a, vec2 b, vec2 c ) {
|
|
143
|
-
|
|
144
|
-
// get the edges of the triangle and the diagonal across the
|
|
145
|
-
// center of the parallelogram
|
|
146
|
-
vec2 e1 = a - b;
|
|
147
|
-
vec2 e2 = c - b;
|
|
148
|
-
vec2 diag = normalize( e1 + e2 );
|
|
149
|
-
|
|
150
|
-
// pick a random point in the parallelogram
|
|
151
|
-
vec2 r = rand2();
|
|
152
|
-
if ( r.x + r.y > 1.0 ) {
|
|
153
|
-
|
|
154
|
-
r = vec2( 1.0 ) - r;
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return e1 * r.x + e2 * r.y;
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// samples an aperture shape with the given number of sides. 0 means circle
|
|
163
|
-
vec2 sampleAperture( int blades ) {
|
|
164
|
-
|
|
165
|
-
if ( blades == 0 ) {
|
|
166
|
-
|
|
167
|
-
vec2 r = rand2();
|
|
168
|
-
float angle = 2.0 * PI * r.x;
|
|
169
|
-
float radius = sqrt( rand() );
|
|
170
|
-
return vec2( cos( angle ), sin( angle ) ) * radius;
|
|
171
|
-
|
|
172
|
-
} else {
|
|
173
|
-
|
|
174
|
-
blades = max( blades, 3 );
|
|
175
|
-
|
|
176
|
-
vec3 r = rand3();
|
|
177
|
-
float anglePerSegment = 2.0 * PI / float( blades );
|
|
178
|
-
float segment = floor( float( blades ) * r.x );
|
|
179
|
-
|
|
180
|
-
float angle1 = anglePerSegment * segment;
|
|
181
|
-
float angle2 = angle1 + anglePerSegment;
|
|
182
|
-
vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
|
|
183
|
-
vec2 b = vec2( 0.0, 0.0 );
|
|
184
|
-
vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
|
|
185
|
-
|
|
186
|
-
return triangleSample( a, b, c );
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
float colorToLuminance( vec3 color ) {
|
|
193
|
-
|
|
194
|
-
// https://en.wikipedia.org/wiki/Relative_luminance
|
|
195
|
-
return 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ray sampling x and z are swapped to align with expected background view
|
|
200
|
-
vec2 equirectDirectionToUv( vec3 direction ) {
|
|
201
|
-
|
|
202
|
-
// from Spherical.setFromCartesianCoords
|
|
203
|
-
vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );
|
|
204
|
-
uv /= vec2( 2.0 * PI, PI );
|
|
205
|
-
|
|
206
|
-
// apply adjustments to get values in range [0, 1] and y right side up
|
|
207
|
-
uv.x += 0.5;
|
|
208
|
-
uv.y = 1.0 - uv.y;
|
|
209
|
-
return uv;
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
vec3 equirectUvToDirection( vec2 uv ) {
|
|
214
|
-
|
|
215
|
-
// undo above adjustments
|
|
216
|
-
uv.x -= 0.5;
|
|
217
|
-
uv.y = 1.0 - uv.y;
|
|
218
|
-
|
|
219
|
-
// from Vector3.setFromSphericalCoords
|
|
220
|
-
float theta = uv.x * 2.0 * PI;
|
|
221
|
-
float phi = uv.y * PI;
|
|
222
|
-
|
|
223
|
-
float sinPhi = sin( phi );
|
|
224
|
-
|
|
225
|
-
return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
1
|
+
export const shaderUtils = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
|
|
4
|
+
float schlickFresnel( float cosine, float f0 ) {
|
|
5
|
+
|
|
6
|
+
return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );
|
|
7
|
+
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation
|
|
11
|
+
float schlickFresnelFromIor( float cosine, float iorRatio ) {
|
|
12
|
+
|
|
13
|
+
// Schlick approximation
|
|
14
|
+
float r_0 = pow( ( 1.0 - iorRatio ) / ( 1.0 + iorRatio ), 2.0 );
|
|
15
|
+
return schlickFresnel( cosine, r_0 );
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// forms a basis with the normal vector as Z
|
|
20
|
+
mat3 getBasisFromNormal( vec3 normal ) {
|
|
21
|
+
|
|
22
|
+
vec3 other;
|
|
23
|
+
if ( abs( normal.x ) > 0.5 ) {
|
|
24
|
+
|
|
25
|
+
other = vec3( 0.0, 1.0, 0.0 );
|
|
26
|
+
|
|
27
|
+
} else {
|
|
28
|
+
|
|
29
|
+
other = vec3( 1.0, 0.0, 0.0 );
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
vec3 ortho = normalize( cross( normal, other ) );
|
|
34
|
+
vec3 ortho2 = normalize( cross( normal, ortho ) );
|
|
35
|
+
return mat3( ortho2, ortho, normal );
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
vec3 getHalfVector( vec3 a, vec3 b ) {
|
|
40
|
+
|
|
41
|
+
return normalize( a + b );
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray
|
|
46
|
+
// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If
|
|
47
|
+
// we find a ray like that we ignore it to avoid artifacts.
|
|
48
|
+
// This function returns if the direction is on the same side of both planes.
|
|
49
|
+
bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {
|
|
50
|
+
|
|
51
|
+
bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;
|
|
52
|
+
bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;
|
|
53
|
+
return aboveSurfaceNormal == aboveGeometryNormal;
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
vec3 getHemisphereSample( vec3 n, vec2 uv ) {
|
|
58
|
+
|
|
59
|
+
// https://www.rorydriscoll.com/2009/01/07/better-sampling/
|
|
60
|
+
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
|
|
61
|
+
float sign = n.z == 0.0 ? 1.0 : sign( n.z );
|
|
62
|
+
float a = - 1.0 / ( sign + n.z );
|
|
63
|
+
float b = n.x * n.y * a;
|
|
64
|
+
vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
|
|
65
|
+
vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
|
|
66
|
+
|
|
67
|
+
float r = sqrt( uv.x );
|
|
68
|
+
float theta = 2.0 * PI * uv.y;
|
|
69
|
+
float x = r * cos( theta );
|
|
70
|
+
float y = r * sin( theta );
|
|
71
|
+
return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// https://www.shadertoy.com/view/wltcRS
|
|
76
|
+
uvec4 s0;
|
|
77
|
+
|
|
78
|
+
void rng_initialize(vec2 p, int frame) {
|
|
79
|
+
|
|
80
|
+
// white noise seed
|
|
81
|
+
s0 = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// https://www.pcg-random.org/
|
|
86
|
+
void pcg4d( inout uvec4 v ) {
|
|
87
|
+
|
|
88
|
+
v = v * 1664525u + 1013904223u;
|
|
89
|
+
v.x += v.y * v.w;
|
|
90
|
+
v.y += v.z * v.x;
|
|
91
|
+
v.z += v.x * v.y;
|
|
92
|
+
v.w += v.y * v.z;
|
|
93
|
+
v = v ^ ( v >> 16u );
|
|
94
|
+
v.x += v.y*v.w;
|
|
95
|
+
v.y += v.z*v.x;
|
|
96
|
+
v.z += v.x*v.y;
|
|
97
|
+
v.w += v.y*v.z;
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// returns [ 0, 1 ]
|
|
102
|
+
float rand() {
|
|
103
|
+
|
|
104
|
+
pcg4d(s0);
|
|
105
|
+
return float( s0.x ) / float( 0xffffffffu );
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
vec2 rand2() {
|
|
110
|
+
|
|
111
|
+
pcg4d( s0 );
|
|
112
|
+
return vec2( s0.xy ) / float(0xffffffffu);
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
vec3 rand3() {
|
|
117
|
+
|
|
118
|
+
pcg4d(s0);
|
|
119
|
+
return vec3( s0.xyz ) / float( 0xffffffffu );
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
vec4 rand4() {
|
|
124
|
+
|
|
125
|
+
pcg4d(s0);
|
|
126
|
+
return vec4(s0)/float(0xffffffffu);
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// https://github.com/mrdoob/three.js/blob/dev/src/math/Vector3.js#L724
|
|
131
|
+
vec3 randDirection() {
|
|
132
|
+
|
|
133
|
+
vec2 r = rand2();
|
|
134
|
+
float u = ( r.x - 0.5 ) * 2.0;
|
|
135
|
+
float t = r.y * PI * 2.0;
|
|
136
|
+
float f = sqrt( 1.0 - u * u );
|
|
137
|
+
|
|
138
|
+
return vec3( f * cos( t ), f * sin( t ), u );
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
vec2 triangleSample( vec2 a, vec2 b, vec2 c ) {
|
|
143
|
+
|
|
144
|
+
// get the edges of the triangle and the diagonal across the
|
|
145
|
+
// center of the parallelogram
|
|
146
|
+
vec2 e1 = a - b;
|
|
147
|
+
vec2 e2 = c - b;
|
|
148
|
+
vec2 diag = normalize( e1 + e2 );
|
|
149
|
+
|
|
150
|
+
// pick a random point in the parallelogram
|
|
151
|
+
vec2 r = rand2();
|
|
152
|
+
if ( r.x + r.y > 1.0 ) {
|
|
153
|
+
|
|
154
|
+
r = vec2( 1.0 ) - r;
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return e1 * r.x + e2 * r.y;
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// samples an aperture shape with the given number of sides. 0 means circle
|
|
163
|
+
vec2 sampleAperture( int blades ) {
|
|
164
|
+
|
|
165
|
+
if ( blades == 0 ) {
|
|
166
|
+
|
|
167
|
+
vec2 r = rand2();
|
|
168
|
+
float angle = 2.0 * PI * r.x;
|
|
169
|
+
float radius = sqrt( rand() );
|
|
170
|
+
return vec2( cos( angle ), sin( angle ) ) * radius;
|
|
171
|
+
|
|
172
|
+
} else {
|
|
173
|
+
|
|
174
|
+
blades = max( blades, 3 );
|
|
175
|
+
|
|
176
|
+
vec3 r = rand3();
|
|
177
|
+
float anglePerSegment = 2.0 * PI / float( blades );
|
|
178
|
+
float segment = floor( float( blades ) * r.x );
|
|
179
|
+
|
|
180
|
+
float angle1 = anglePerSegment * segment;
|
|
181
|
+
float angle2 = angle1 + anglePerSegment;
|
|
182
|
+
vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
|
|
183
|
+
vec2 b = vec2( 0.0, 0.0 );
|
|
184
|
+
vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
|
|
185
|
+
|
|
186
|
+
return triangleSample( a, b, c );
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
float colorToLuminance( vec3 color ) {
|
|
193
|
+
|
|
194
|
+
// https://en.wikipedia.org/wiki/Relative_luminance
|
|
195
|
+
return 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ray sampling x and z are swapped to align with expected background view
|
|
200
|
+
vec2 equirectDirectionToUv( vec3 direction ) {
|
|
201
|
+
|
|
202
|
+
// from Spherical.setFromCartesianCoords
|
|
203
|
+
vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );
|
|
204
|
+
uv /= vec2( 2.0 * PI, PI );
|
|
205
|
+
|
|
206
|
+
// apply adjustments to get values in range [0, 1] and y right side up
|
|
207
|
+
uv.x += 0.5;
|
|
208
|
+
uv.y = 1.0 - uv.y;
|
|
209
|
+
return uv;
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
vec3 equirectUvToDirection( vec2 uv ) {
|
|
214
|
+
|
|
215
|
+
// undo above adjustments
|
|
216
|
+
uv.x -= 0.5;
|
|
217
|
+
uv.y = 1.0 - uv.y;
|
|
218
|
+
|
|
219
|
+
// from Vector3.setFromSphericalCoords
|
|
220
|
+
float theta = uv.x * 2.0 * PI;
|
|
221
|
+
float phi = uv.y * PI;
|
|
222
|
+
|
|
223
|
+
float sinPhi = sin( phi );
|
|
224
|
+
|
|
225
|
+
return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Fast arccos approximation used to remove banding artifacts caused by numerical errors in acos.
|
|
230
|
+
// This is a cubic Lagrange interpolating polynomial for x = [-1, -1/2, 0, 1/2, 1].
|
|
231
|
+
// For more information see: https://github.com/gkjohnson/three-gpu-pathtracer/pull/171#issuecomment-1152275248
|
|
232
|
+
float acosApprox( float x ) {
|
|
233
|
+
|
|
234
|
+
x = clamp( x, -1.0, 1.0 );
|
|
235
|
+
return ( - 0.69813170079773212 * x * x - 0.87266462599716477 ) * x + 1.5707963267948966;
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// An acos with input values bound to the range [-1, 1].
|
|
240
|
+
float acosSafe( float x ) {
|
|
241
|
+
|
|
242
|
+
return acos( clamp( x, -1.0, 1.0 ) );
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
`;
|