three-gpu-pathtracer 0.0.14 → 0.0.16
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 +1004 -981
- package/build/index.module.js +7413 -6902
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +7446 -6933
- package/build/index.umd.cjs.map +1 -1
- package/package.json +73 -73
- package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
- package/src/core/MaterialReducer.js +256 -256
- package/src/core/PathTracingRenderer.js +346 -346
- package/src/core/PathTracingSceneGenerator.js +69 -69
- package/src/core/QuiltPathTracingRenderer.js +223 -223
- package/src/detectors/CompatibilityDetector.js +38 -0
- package/src/detectors/MaterialCompileDetector.js +50 -0
- package/src/detectors/PrecisionDetector.js +85 -0
- package/src/detectors/PrecisionMaterial.js +160 -0
- package/src/index.js +40 -36
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/debug/GraphMaterial.js +243 -243
- package/src/materials/fullscreen/AlphaDisplayMaterial.js +50 -48
- package/src/materials/fullscreen/BlendMaterial.js +67 -67
- package/src/materials/fullscreen/DenoiseMaterial.js +142 -142
- package/src/materials/fullscreen/GradientMapMaterial.js +82 -0
- package/src/materials/pathtracing/LambertPathTracingMaterial.js +296 -296
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +118 -196
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +177 -179
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +84 -81
- package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +93 -0
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +323 -317
- package/src/materials/pathtracing/glsl/renderStructs.glsl.js +50 -0
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +52 -54
- package/src/materials/surface/AmbientOcclusionMaterial.js +207 -207
- package/src/materials/surface/FogVolumeMaterial.js +23 -23
- package/src/objects/EquirectCamera.js +13 -13
- package/src/objects/PhysicalCamera.js +42 -28
- package/src/objects/PhysicalSpotLight.js +25 -14
- package/src/objects/ShapedAreaLight.js +22 -12
- package/src/shader/bsdf/bsdfSampling.glsl.js +499 -490
- package/src/shader/bsdf/fog.glsl.js +22 -23
- package/src/shader/bsdf/ggx.glsl.js +102 -102
- package/src/shader/bsdf/iridescence.glsl.js +135 -135
- package/src/shader/bsdf/sheen.glsl.js +98 -98
- package/src/shader/common/arraySamplerTexelFetch.glsl.js +25 -25
- package/src/shader/common/bvhAnyHit.glsl.js +76 -76
- package/src/shader/common/fresnel.glsl.js +98 -98
- package/src/shader/common/intersectShapes.glsl.js +62 -62
- package/src/shader/common/math.glsl.js +81 -81
- package/src/shader/common/utils.glsl.js +116 -116
- package/src/shader/rand/pcg.glsl.js +57 -57
- package/src/shader/rand/sobol.glsl.js +256 -256
- package/src/shader/sampling/equirectSampling.glsl.js +62 -62
- package/src/shader/sampling/lightSampling.glsl.js +223 -223
- package/src/shader/sampling/shapeSampling.glsl.js +86 -86
- package/src/shader/structs/cameraStruct.glsl.js +13 -13
- package/src/shader/structs/equirectStruct.glsl.js +13 -14
- package/src/shader/structs/fogMaterialBvh.glsl.js +62 -62
- package/src/shader/structs/lightsStruct.glsl.js +78 -78
- package/src/shader/structs/materialStruct.glsl.js +207 -207
- package/src/textures/GradientEquirectTexture.js +35 -35
- package/src/textures/ProceduralEquirectTexture.js +75 -75
- package/src/uniforms/AttributesTextureArray.js +35 -35
- package/src/uniforms/EquirectHdrInfoUniform.js +269 -277
- package/src/uniforms/FloatAttributeTextureArray.js +169 -169
- package/src/uniforms/IESProfilesTexture.js +100 -100
- package/src/uniforms/LightsInfoUniformStruct.js +212 -212
- package/src/uniforms/MaterialsTexture.js +503 -503
- package/src/uniforms/PhysicalCameraUniform.js +36 -36
- package/src/uniforms/RenderTarget2DArray.js +97 -97
- package/src/uniforms/utils.js +30 -30
- package/src/utils/BlurredEnvMapGenerator.js +116 -116
- package/src/utils/GeometryPreparationUtils.js +214 -214
- package/src/utils/IESLoader.js +325 -325
- package/src/utils/SobolNumberMapGenerator.js +80 -80
- package/src/utils/UVUnwrapper.js +101 -101
- package/src/utils/macroify.js +9 -9
- package/src/workers/PathTracingSceneWorker.js +42 -42
|
@@ -1,223 +1,223 @@
|
|
|
1
|
-
export const lightSamplingGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {
|
|
4
|
-
|
|
5
|
-
return smoothstep( coneCosine, penumbraCosine, angleCosine );
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {
|
|
10
|
-
|
|
11
|
-
// based upon Frostbite 3 Moving to Physically-based Rendering
|
|
12
|
-
// page 32, equation 26: E[window1]
|
|
13
|
-
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
|
14
|
-
float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), EPSILON );
|
|
15
|
-
|
|
16
|
-
if ( cutoffDistance > 0.0 ) {
|
|
17
|
-
|
|
18
|
-
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return distanceFalloff;
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
float getPhotometricAttenuation( sampler2DArray iesProfiles, int iesProfile, vec3 posToLight, vec3 lightDir, vec3 u, vec3 v ) {
|
|
27
|
-
|
|
28
|
-
float cosTheta = dot( posToLight, lightDir );
|
|
29
|
-
float angle = acos( cosTheta ) * ( 1.0 / PI );
|
|
30
|
-
|
|
31
|
-
return texture2D( iesProfiles, vec3( 0.0, angle, iesProfile ) ).r;
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
struct
|
|
36
|
-
|
|
37
|
-
float dist;
|
|
38
|
-
vec3 direction;
|
|
39
|
-
float pdf;
|
|
40
|
-
vec3 emission;
|
|
41
|
-
int type;
|
|
42
|
-
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
bool lightsClosestHit( sampler2D lights, uint lightCount, vec3 rayOrigin, vec3 rayDirection, out
|
|
46
|
-
|
|
47
|
-
bool didHit = false;
|
|
48
|
-
uint l;
|
|
49
|
-
for ( l = 0u; l < lightCount; l ++ ) {
|
|
50
|
-
|
|
51
|
-
Light light = readLightInfo( lights, l );
|
|
52
|
-
|
|
53
|
-
vec3 u = light.u;
|
|
54
|
-
vec3 v = light.v;
|
|
55
|
-
|
|
56
|
-
// check for backface
|
|
57
|
-
vec3 normal = normalize( cross( u, v ) );
|
|
58
|
-
if ( dot( normal, rayDirection ) < 0.0 ) {
|
|
59
|
-
|
|
60
|
-
continue;
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
u *= 1.0 / dot( u, u );
|
|
65
|
-
v *= 1.0 / dot( v, v );
|
|
66
|
-
|
|
67
|
-
float dist;
|
|
68
|
-
|
|
69
|
-
// MIS / light intersection is not supported for punctual lights.
|
|
70
|
-
if(
|
|
71
|
-
( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||
|
|
72
|
-
( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
|
|
73
|
-
) {
|
|
74
|
-
|
|
75
|
-
if ( ! didHit || dist <
|
|
76
|
-
|
|
77
|
-
float cosTheta = dot( rayDirection, normal );
|
|
78
|
-
didHit = true;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return didHit;
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
vec3 randomPos;
|
|
103
|
-
if( light.type == RECT_AREA_LIGHT_TYPE ) {
|
|
104
|
-
|
|
105
|
-
// rectangular area light
|
|
106
|
-
randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );
|
|
107
|
-
|
|
108
|
-
} else if( light.type == CIRC_AREA_LIGHT_TYPE ) {
|
|
109
|
-
|
|
110
|
-
// circular area light
|
|
111
|
-
float r = 0.5 * sqrt( ruv.x );
|
|
112
|
-
float theta = ruv.y * 2.0 * PI;
|
|
113
|
-
float x = r * cos( theta );
|
|
114
|
-
float y = r * sin( theta );
|
|
115
|
-
|
|
116
|
-
randomPos = light.position + light.u * x + light.v * y;
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
vec3 toLight = randomPos - rayOrigin;
|
|
121
|
-
float lightDistSq = dot( toLight, toLight );
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
vec3 direction = toLight /
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
float radius = light.radius * sqrt( ruv.x );
|
|
137
|
-
float theta = ruv.y * 2.0 * PI;
|
|
138
|
-
float x = radius * cos( theta );
|
|
139
|
-
float y = radius * sin( theta );
|
|
140
|
-
|
|
141
|
-
vec3 u = light.u;
|
|
142
|
-
vec3 v = light.v;
|
|
143
|
-
vec3 normal = normalize( cross( u, v ) );
|
|
144
|
-
|
|
145
|
-
float angle = acos( light.coneCos );
|
|
146
|
-
float angleTan = tan( angle );
|
|
147
|
-
float startDistance = light.radius / max( angleTan, EPSILON );
|
|
148
|
-
|
|
149
|
-
vec3 randomPos = light.position - normal * startDistance + u * x + v * y;
|
|
150
|
-
vec3 toLight = randomPos - rayOrigin;
|
|
151
|
-
float lightDistSq = dot( toLight, toLight );
|
|
152
|
-
float dist = sqrt( lightDistSq );
|
|
153
|
-
|
|
154
|
-
vec3 direction = toLight / max( dist, EPSILON );
|
|
155
|
-
float cosTheta = dot( direction, normal );
|
|
156
|
-
|
|
157
|
-
float spotAttenuation = light.iesProfile != - 1 ?
|
|
158
|
-
getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :
|
|
159
|
-
getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );
|
|
160
|
-
|
|
161
|
-
float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// pick a random light
|
|
176
|
-
uint l = uint( ruv.x * float( lightCount ) );
|
|
177
|
-
Light light = readLightInfo( lights, l );
|
|
178
|
-
|
|
179
|
-
if ( light.type == SPOT_LIGHT_TYPE ) {
|
|
180
|
-
|
|
181
|
-
return randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
|
|
182
|
-
|
|
183
|
-
} else if ( light.type == POINT_LIGHT_TYPE ) {
|
|
184
|
-
|
|
185
|
-
vec3 lightRay = light.u - rayOrigin;
|
|
186
|
-
float lightDist = length( lightRay );
|
|
187
|
-
float cutoffDistance = light.distance;
|
|
188
|
-
float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );
|
|
189
|
-
if ( cutoffDistance > 0.0 ) {
|
|
190
|
-
|
|
191
|
-
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
rec.direction = normalize( lightRay );
|
|
197
|
-
rec.dist = length( lightRay );
|
|
198
|
-
rec.pdf = 1.0;
|
|
199
|
-
rec.emission = light.color * light.intensity * distanceFalloff;
|
|
200
|
-
rec.type = light.type;
|
|
201
|
-
return rec;
|
|
202
|
-
|
|
203
|
-
} else if ( light.type == DIR_LIGHT_TYPE ) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
rec.dist = 1e10;
|
|
207
|
-
rec.direction = light.u;
|
|
208
|
-
rec.pdf = 1.0;
|
|
209
|
-
rec.emission = light.color * light.intensity;
|
|
210
|
-
rec.type = light.type;
|
|
211
|
-
|
|
212
|
-
return rec;
|
|
213
|
-
|
|
214
|
-
} else {
|
|
215
|
-
|
|
216
|
-
// sample the light
|
|
217
|
-
return randomAreaLightSample( light, rayOrigin, ruv.yz );
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
`;
|
|
1
|
+
export const lightSamplingGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {
|
|
4
|
+
|
|
5
|
+
return smoothstep( coneCosine, penumbraCosine, angleCosine );
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {
|
|
10
|
+
|
|
11
|
+
// based upon Frostbite 3 Moving to Physically-based Rendering
|
|
12
|
+
// page 32, equation 26: E[window1]
|
|
13
|
+
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
|
14
|
+
float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), EPSILON );
|
|
15
|
+
|
|
16
|
+
if ( cutoffDistance > 0.0 ) {
|
|
17
|
+
|
|
18
|
+
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return distanceFalloff;
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
float getPhotometricAttenuation( sampler2DArray iesProfiles, int iesProfile, vec3 posToLight, vec3 lightDir, vec3 u, vec3 v ) {
|
|
27
|
+
|
|
28
|
+
float cosTheta = dot( posToLight, lightDir );
|
|
29
|
+
float angle = acos( cosTheta ) * ( 1.0 / PI );
|
|
30
|
+
|
|
31
|
+
return texture2D( iesProfiles, vec3( 0.0, angle, iesProfile ) ).r;
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
struct LightRecord {
|
|
36
|
+
|
|
37
|
+
float dist;
|
|
38
|
+
vec3 direction;
|
|
39
|
+
float pdf;
|
|
40
|
+
vec3 emission;
|
|
41
|
+
int type;
|
|
42
|
+
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
bool lightsClosestHit( sampler2D lights, uint lightCount, vec3 rayOrigin, vec3 rayDirection, out LightRecord lightRec ) {
|
|
46
|
+
|
|
47
|
+
bool didHit = false;
|
|
48
|
+
uint l;
|
|
49
|
+
for ( l = 0u; l < lightCount; l ++ ) {
|
|
50
|
+
|
|
51
|
+
Light light = readLightInfo( lights, l );
|
|
52
|
+
|
|
53
|
+
vec3 u = light.u;
|
|
54
|
+
vec3 v = light.v;
|
|
55
|
+
|
|
56
|
+
// check for backface
|
|
57
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
58
|
+
if ( dot( normal, rayDirection ) < 0.0 ) {
|
|
59
|
+
|
|
60
|
+
continue;
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
u *= 1.0 / dot( u, u );
|
|
65
|
+
v *= 1.0 / dot( v, v );
|
|
66
|
+
|
|
67
|
+
float dist;
|
|
68
|
+
|
|
69
|
+
// MIS / light intersection is not supported for punctual lights.
|
|
70
|
+
if(
|
|
71
|
+
( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||
|
|
72
|
+
( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
|
|
73
|
+
) {
|
|
74
|
+
|
|
75
|
+
if ( ! didHit || dist < lightRec.dist ) {
|
|
76
|
+
|
|
77
|
+
float cosTheta = dot( rayDirection, normal );
|
|
78
|
+
didHit = true;
|
|
79
|
+
lightRec.dist = dist;
|
|
80
|
+
lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
|
|
81
|
+
lightRec.emission = light.color * light.intensity;
|
|
82
|
+
lightRec.direction = rayDirection;
|
|
83
|
+
lightRec.type = light.type;
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return didHit;
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
|
|
96
|
+
|
|
97
|
+
LightRecord lightRec;
|
|
98
|
+
lightRec.type = light.type;
|
|
99
|
+
|
|
100
|
+
lightRec.emission = light.color * light.intensity;
|
|
101
|
+
|
|
102
|
+
vec3 randomPos;
|
|
103
|
+
if( light.type == RECT_AREA_LIGHT_TYPE ) {
|
|
104
|
+
|
|
105
|
+
// rectangular area light
|
|
106
|
+
randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );
|
|
107
|
+
|
|
108
|
+
} else if( light.type == CIRC_AREA_LIGHT_TYPE ) {
|
|
109
|
+
|
|
110
|
+
// circular area light
|
|
111
|
+
float r = 0.5 * sqrt( ruv.x );
|
|
112
|
+
float theta = ruv.y * 2.0 * PI;
|
|
113
|
+
float x = r * cos( theta );
|
|
114
|
+
float y = r * sin( theta );
|
|
115
|
+
|
|
116
|
+
randomPos = light.position + light.u * x + light.v * y;
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
vec3 toLight = randomPos - rayOrigin;
|
|
121
|
+
float lightDistSq = dot( toLight, toLight );
|
|
122
|
+
lightRec.dist = sqrt( lightDistSq );
|
|
123
|
+
|
|
124
|
+
vec3 direction = toLight / lightRec.dist;
|
|
125
|
+
lightRec.direction = direction;
|
|
126
|
+
|
|
127
|
+
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
128
|
+
lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
|
|
129
|
+
|
|
130
|
+
return lightRec;
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
LightRecord randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {
|
|
135
|
+
|
|
136
|
+
float radius = light.radius * sqrt( ruv.x );
|
|
137
|
+
float theta = ruv.y * 2.0 * PI;
|
|
138
|
+
float x = radius * cos( theta );
|
|
139
|
+
float y = radius * sin( theta );
|
|
140
|
+
|
|
141
|
+
vec3 u = light.u;
|
|
142
|
+
vec3 v = light.v;
|
|
143
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
144
|
+
|
|
145
|
+
float angle = acos( light.coneCos );
|
|
146
|
+
float angleTan = tan( angle );
|
|
147
|
+
float startDistance = light.radius / max( angleTan, EPSILON );
|
|
148
|
+
|
|
149
|
+
vec3 randomPos = light.position - normal * startDistance + u * x + v * y;
|
|
150
|
+
vec3 toLight = randomPos - rayOrigin;
|
|
151
|
+
float lightDistSq = dot( toLight, toLight );
|
|
152
|
+
float dist = sqrt( lightDistSq );
|
|
153
|
+
|
|
154
|
+
vec3 direction = toLight / max( dist, EPSILON );
|
|
155
|
+
float cosTheta = dot( direction, normal );
|
|
156
|
+
|
|
157
|
+
float spotAttenuation = light.iesProfile != - 1 ?
|
|
158
|
+
getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :
|
|
159
|
+
getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );
|
|
160
|
+
|
|
161
|
+
float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );
|
|
162
|
+
LightRecord lightRec;
|
|
163
|
+
lightRec.type = light.type;
|
|
164
|
+
lightRec.dist = dist;
|
|
165
|
+
lightRec.direction = direction;
|
|
166
|
+
lightRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;
|
|
167
|
+
lightRec.pdf = 1.0;
|
|
168
|
+
|
|
169
|
+
return lightRec;
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
|
|
174
|
+
|
|
175
|
+
// pick a random light
|
|
176
|
+
uint l = uint( ruv.x * float( lightCount ) );
|
|
177
|
+
Light light = readLightInfo( lights, l );
|
|
178
|
+
|
|
179
|
+
if ( light.type == SPOT_LIGHT_TYPE ) {
|
|
180
|
+
|
|
181
|
+
return randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
|
|
182
|
+
|
|
183
|
+
} else if ( light.type == POINT_LIGHT_TYPE ) {
|
|
184
|
+
|
|
185
|
+
vec3 lightRay = light.u - rayOrigin;
|
|
186
|
+
float lightDist = length( lightRay );
|
|
187
|
+
float cutoffDistance = light.distance;
|
|
188
|
+
float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );
|
|
189
|
+
if ( cutoffDistance > 0.0 ) {
|
|
190
|
+
|
|
191
|
+
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
LightRecord rec;
|
|
196
|
+
rec.direction = normalize( lightRay );
|
|
197
|
+
rec.dist = length( lightRay );
|
|
198
|
+
rec.pdf = 1.0;
|
|
199
|
+
rec.emission = light.color * light.intensity * distanceFalloff;
|
|
200
|
+
rec.type = light.type;
|
|
201
|
+
return rec;
|
|
202
|
+
|
|
203
|
+
} else if ( light.type == DIR_LIGHT_TYPE ) {
|
|
204
|
+
|
|
205
|
+
LightRecord rec;
|
|
206
|
+
rec.dist = 1e10;
|
|
207
|
+
rec.direction = light.u;
|
|
208
|
+
rec.pdf = 1.0;
|
|
209
|
+
rec.emission = light.color * light.intensity;
|
|
210
|
+
rec.type = light.type;
|
|
211
|
+
|
|
212
|
+
return rec;
|
|
213
|
+
|
|
214
|
+
} else {
|
|
215
|
+
|
|
216
|
+
// sample the light
|
|
217
|
+
return randomAreaLightSample( light, rayOrigin, ruv.yz );
|
|
218
|
+
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
`;
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
export const shapeSamplingGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
vec3 sampleHemisphere( vec3 n, vec2 uv ) {
|
|
4
|
-
|
|
5
|
-
// https://www.rorydriscoll.com/2009/01/07/better-sampling/
|
|
6
|
-
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
|
|
7
|
-
float sign = n.z == 0.0 ? 1.0 : sign( n.z );
|
|
8
|
-
float a = - 1.0 / ( sign + n.z );
|
|
9
|
-
float b = n.x * n.y * a;
|
|
10
|
-
vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
|
|
11
|
-
vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
|
|
12
|
-
|
|
13
|
-
float r = sqrt( uv.x );
|
|
14
|
-
float theta = 2.0 * PI * uv.y;
|
|
15
|
-
float x = r * cos( theta );
|
|
16
|
-
float y = r * sin( theta );
|
|
17
|
-
return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {
|
|
22
|
-
|
|
23
|
-
// get the edges of the triangle and the diagonal across the
|
|
24
|
-
// center of the parallelogram
|
|
25
|
-
vec2 e1 = a - b;
|
|
26
|
-
vec2 e2 = c - b;
|
|
27
|
-
vec2 diag = normalize( e1 + e2 );
|
|
28
|
-
|
|
29
|
-
// pick the point in the parallelogram
|
|
30
|
-
if ( r.x + r.y > 1.0 ) {
|
|
31
|
-
|
|
32
|
-
r = vec2( 1.0 ) - r;
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return e1 * r.x + e2 * r.y;
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
vec2 sampleCircle( vec2 uv ) {
|
|
41
|
-
|
|
42
|
-
float angle = 2.0 * PI * uv.x;
|
|
43
|
-
float radius = sqrt( uv.y );
|
|
44
|
-
return vec2( cos( angle ), sin( angle ) ) * radius;
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
vec3 sampleSphere( vec2 uv ) {
|
|
49
|
-
|
|
50
|
-
float u = ( uv.x - 0.5 ) * 2.0;
|
|
51
|
-
float t = uv.y * PI * 2.0;
|
|
52
|
-
float f = sqrt( 1.0 - u * u );
|
|
53
|
-
|
|
54
|
-
return vec3( f * cos( t ), f * sin( t ), u );
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
vec2 sampleRegularPolygon( int sides, vec3 uvw ) {
|
|
59
|
-
|
|
60
|
-
sides = max( sides, 3 );
|
|
61
|
-
|
|
62
|
-
vec3 r = uvw;
|
|
63
|
-
float anglePerSegment = 2.0 * PI / float( sides );
|
|
64
|
-
float segment = floor( float( sides ) * r.x );
|
|
65
|
-
|
|
66
|
-
float angle1 = anglePerSegment * segment;
|
|
67
|
-
float angle2 = angle1 + anglePerSegment;
|
|
68
|
-
vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
|
|
69
|
-
vec2 b = vec2( 0.0, 0.0 );
|
|
70
|
-
vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
|
|
71
|
-
|
|
72
|
-
return sampleTriangle( a, b, c, r.yz );
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// samples an aperture shape with the given number of sides. 0 means circle
|
|
77
|
-
vec2 sampleAperture( int blades, vec3 uvw ) {
|
|
78
|
-
|
|
79
|
-
return blades == 0 ?
|
|
80
|
-
sampleCircle( uvw.xy ) :
|
|
81
|
-
sampleRegularPolygon( blades, uvw );
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`;
|
|
1
|
+
export const shapeSamplingGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
vec3 sampleHemisphere( vec3 n, vec2 uv ) {
|
|
4
|
+
|
|
5
|
+
// https://www.rorydriscoll.com/2009/01/07/better-sampling/
|
|
6
|
+
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
|
|
7
|
+
float sign = n.z == 0.0 ? 1.0 : sign( n.z );
|
|
8
|
+
float a = - 1.0 / ( sign + n.z );
|
|
9
|
+
float b = n.x * n.y * a;
|
|
10
|
+
vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
|
|
11
|
+
vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
|
|
12
|
+
|
|
13
|
+
float r = sqrt( uv.x );
|
|
14
|
+
float theta = 2.0 * PI * uv.y;
|
|
15
|
+
float x = r * cos( theta );
|
|
16
|
+
float y = r * sin( theta );
|
|
17
|
+
return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {
|
|
22
|
+
|
|
23
|
+
// get the edges of the triangle and the diagonal across the
|
|
24
|
+
// center of the parallelogram
|
|
25
|
+
vec2 e1 = a - b;
|
|
26
|
+
vec2 e2 = c - b;
|
|
27
|
+
vec2 diag = normalize( e1 + e2 );
|
|
28
|
+
|
|
29
|
+
// pick the point in the parallelogram
|
|
30
|
+
if ( r.x + r.y > 1.0 ) {
|
|
31
|
+
|
|
32
|
+
r = vec2( 1.0 ) - r;
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return e1 * r.x + e2 * r.y;
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
vec2 sampleCircle( vec2 uv ) {
|
|
41
|
+
|
|
42
|
+
float angle = 2.0 * PI * uv.x;
|
|
43
|
+
float radius = sqrt( uv.y );
|
|
44
|
+
return vec2( cos( angle ), sin( angle ) ) * radius;
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
vec3 sampleSphere( vec2 uv ) {
|
|
49
|
+
|
|
50
|
+
float u = ( uv.x - 0.5 ) * 2.0;
|
|
51
|
+
float t = uv.y * PI * 2.0;
|
|
52
|
+
float f = sqrt( 1.0 - u * u );
|
|
53
|
+
|
|
54
|
+
return vec3( f * cos( t ), f * sin( t ), u );
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
vec2 sampleRegularPolygon( int sides, vec3 uvw ) {
|
|
59
|
+
|
|
60
|
+
sides = max( sides, 3 );
|
|
61
|
+
|
|
62
|
+
vec3 r = uvw;
|
|
63
|
+
float anglePerSegment = 2.0 * PI / float( sides );
|
|
64
|
+
float segment = floor( float( sides ) * r.x );
|
|
65
|
+
|
|
66
|
+
float angle1 = anglePerSegment * segment;
|
|
67
|
+
float angle2 = angle1 + anglePerSegment;
|
|
68
|
+
vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
|
|
69
|
+
vec2 b = vec2( 0.0, 0.0 );
|
|
70
|
+
vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
|
|
71
|
+
|
|
72
|
+
return sampleTriangle( a, b, c, r.yz );
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// samples an aperture shape with the given number of sides. 0 means circle
|
|
77
|
+
vec2 sampleAperture( int blades, vec3 uvw ) {
|
|
78
|
+
|
|
79
|
+
return blades == 0 ?
|
|
80
|
+
sampleCircle( uvw.xy ) :
|
|
81
|
+
sampleRegularPolygon( blades, uvw );
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
`;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export const cameraStructGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
struct PhysicalCamera {
|
|
4
|
-
|
|
5
|
-
float focusDistance;
|
|
6
|
-
float anamorphicRatio;
|
|
7
|
-
float bokehSize;
|
|
8
|
-
int apertureBlades;
|
|
9
|
-
float apertureRotation;
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
`;
|
|
1
|
+
export const cameraStructGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
struct PhysicalCamera {
|
|
4
|
+
|
|
5
|
+
float focusDistance;
|
|
6
|
+
float anamorphicRatio;
|
|
7
|
+
float bokehSize;
|
|
8
|
+
int apertureBlades;
|
|
9
|
+
float apertureRotation;
|
|
10
|
+
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
`;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export const equirectStructGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
struct EquirectHdrInfo {
|
|
4
|
-
|
|
5
|
-
sampler2D marginalWeights;
|
|
6
|
-
sampler2D conditionalWeights;
|
|
7
|
-
sampler2D map;
|
|
8
|
-
|
|
9
|
-
float
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`;
|
|
1
|
+
export const equirectStructGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
struct EquirectHdrInfo {
|
|
4
|
+
|
|
5
|
+
sampler2D marginalWeights;
|
|
6
|
+
sampler2D conditionalWeights;
|
|
7
|
+
sampler2D map;
|
|
8
|
+
|
|
9
|
+
float totalSum;
|
|
10
|
+
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
`;
|