three-gpu-pathtracer 0.0.16 → 0.0.17
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/README.md +3 -1
- package/build/index.module.js +248 -198
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +245 -195
- package/build/index.umd.cjs.map +1 -1
- package/package.json +5 -6
- package/src/core/DynamicPathTracingSceneGenerator.js +8 -3
- package/src/core/PathTracingRenderer.js +8 -4
- package/src/core/PathTracingSceneGenerator.js +6 -1
- package/src/materials/debug/GraphMaterial.js +1 -1
- package/src/materials/fullscreen/AlphaDisplayMaterial.js +1 -1
- package/src/materials/fullscreen/DenoiseMaterial.js +1 -1
- package/src/materials/fullscreen/GradientMapMaterial.js +1 -1
- package/src/materials/pathtracing/LambertPathTracingMaterial.js +4 -3
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +61 -46
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +2 -11
- package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +10 -6
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +1 -1
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +10 -12
- package/src/materials/surface/AmbientOcclusionMaterial.js +4 -3
- package/src/shader/bsdf/bsdfSampling.glsl.js +7 -7
- package/src/shader/common/bvhAnyHit.glsl.js +2 -2
- package/src/shader/common/intersectShapes.glsl.js +2 -2
- package/src/shader/rand/sobol.glsl.js +3 -3
- package/src/shader/sampling/equirectSampling.glsl.js +10 -10
- package/src/shader/sampling/lightSampling.glsl.js +30 -37
- package/src/shader/structs/fogMaterialBvh.glsl.js +2 -2
- package/src/shader/structs/lightsStruct.glsl.js +12 -1
- package/src/shader/structs/materialStruct.glsl.js +16 -15
- package/src/textures/ProceduralEquirectTexture.js +9 -8
- package/src/uniforms/EquirectHdrInfoUniform.js +18 -17
- package/src/uniforms/IESProfilesTexture.js +2 -2
- package/src/uniforms/LightsInfoUniformStruct.js +4 -2
- package/src/uniforms/MaterialsTexture.js +3 -1
- package/src/utils/BlurredEnvMapGenerator.js +4 -4
- package/src/utils/GeometryPreparationUtils.js +8 -2
- package/src/utils/IESLoader.js +7 -5
- package/src/utils/TextureUtils.js +15 -0
|
@@ -24,14 +24,14 @@ export const equirectSamplingGLSL = /* glsl */`
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// samples the color given env map with CDF and returns the pdf of the direction
|
|
27
|
-
float sampleEquirect(
|
|
27
|
+
float sampleEquirect( vec3 direction, inout vec3 color ) {
|
|
28
28
|
|
|
29
29
|
vec2 uv = equirectDirectionToUv( direction );
|
|
30
|
-
color = texture2D(
|
|
30
|
+
color = texture2D( envMapInfo.map, uv ).rgb;
|
|
31
31
|
|
|
32
|
-
float totalSum =
|
|
32
|
+
float totalSum = envMapInfo.totalSum;
|
|
33
33
|
float lum = luminance( color );
|
|
34
|
-
ivec2 resolution = textureSize(
|
|
34
|
+
ivec2 resolution = textureSize( envMapInfo.map, 0 );
|
|
35
35
|
float pdf = lum / totalSum;
|
|
36
36
|
|
|
37
37
|
return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );
|
|
@@ -39,20 +39,20 @@ export const equirectSamplingGLSL = /* glsl */`
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// samples a direction of the envmap with color and retrieves pdf
|
|
42
|
-
float sampleEquirectProbability(
|
|
42
|
+
float sampleEquirectProbability( vec2 r, inout vec3 color, inout vec3 direction ) {
|
|
43
43
|
|
|
44
44
|
// sample env map cdf
|
|
45
|
-
float v = texture2D(
|
|
46
|
-
float u = texture2D(
|
|
45
|
+
float v = texture2D( envMapInfo.marginalWeights, vec2( r.x, 0.0 ) ).x;
|
|
46
|
+
float u = texture2D( envMapInfo.conditionalWeights, vec2( r.y, v ) ).x;
|
|
47
47
|
vec2 uv = vec2( u, v );
|
|
48
48
|
|
|
49
49
|
vec3 derivedDirection = equirectUvToDirection( uv );
|
|
50
50
|
direction = derivedDirection;
|
|
51
|
-
color = texture2D(
|
|
51
|
+
color = texture2D( envMapInfo.map, uv ).rgb;
|
|
52
52
|
|
|
53
|
-
float totalSum =
|
|
53
|
+
float totalSum = envMapInfo.totalSum;
|
|
54
54
|
float lum = luminance( color );
|
|
55
|
-
ivec2 resolution = textureSize(
|
|
55
|
+
ivec2 resolution = textureSize( envMapInfo.map, 0 );
|
|
56
56
|
float pdf = lum / totalSum;
|
|
57
57
|
|
|
58
58
|
return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );
|
|
@@ -42,24 +42,17 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
42
42
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
bool
|
|
45
|
+
bool intersectLightAtIndex( sampler2D lights, vec3 rayOrigin, vec3 rayDirection, uint l, inout LightRecord lightRec ) {
|
|
46
46
|
|
|
47
47
|
bool didHit = false;
|
|
48
|
-
|
|
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 ) {
|
|
48
|
+
Light light = readLightInfo( lights, l );
|
|
59
49
|
|
|
60
|
-
|
|
50
|
+
vec3 u = light.u;
|
|
51
|
+
vec3 v = light.v;
|
|
61
52
|
|
|
62
|
-
|
|
53
|
+
// check for backface
|
|
54
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
55
|
+
if ( dot( normal, rayDirection ) > 0.0 ) {
|
|
63
56
|
|
|
64
57
|
u *= 1.0 / dot( u, u );
|
|
65
58
|
v *= 1.0 / dot( v, v );
|
|
@@ -72,17 +65,13 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
72
65
|
( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
|
|
73
66
|
) {
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
lightRec.direction = rayDirection;
|
|
83
|
-
lightRec.type = light.type;
|
|
84
|
-
|
|
85
|
-
}
|
|
68
|
+
float cosTheta = dot( rayDirection, normal );
|
|
69
|
+
didHit = true;
|
|
70
|
+
lightRec.dist = dist;
|
|
71
|
+
lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
|
|
72
|
+
lightRec.emission = light.color * light.intensity;
|
|
73
|
+
lightRec.direction = rayDirection;
|
|
74
|
+
lightRec.type = light.type;
|
|
86
75
|
|
|
87
76
|
}
|
|
88
77
|
|
|
@@ -94,11 +83,6 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
94
83
|
|
|
95
84
|
LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
|
|
96
85
|
|
|
97
|
-
LightRecord lightRec;
|
|
98
|
-
lightRec.type = light.type;
|
|
99
|
-
|
|
100
|
-
lightRec.emission = light.color * light.intensity;
|
|
101
|
-
|
|
102
86
|
vec3 randomPos;
|
|
103
87
|
if( light.type == RECT_AREA_LIGHT_TYPE ) {
|
|
104
88
|
|
|
@@ -119,12 +103,17 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
119
103
|
|
|
120
104
|
vec3 toLight = randomPos - rayOrigin;
|
|
121
105
|
float lightDistSq = dot( toLight, toLight );
|
|
122
|
-
|
|
106
|
+
float dist = sqrt( lightDistSq );
|
|
107
|
+
vec3 direction = toLight / dist;
|
|
108
|
+
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
123
109
|
|
|
124
|
-
|
|
110
|
+
LightRecord lightRec;
|
|
111
|
+
lightRec.type = light.type;
|
|
112
|
+
lightRec.emission = light.color * light.intensity;
|
|
113
|
+
lightRec.dist = dist;
|
|
125
114
|
lightRec.direction = direction;
|
|
126
115
|
|
|
127
|
-
|
|
116
|
+
// TODO: the denominator is potentially zero
|
|
128
117
|
lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
|
|
129
118
|
|
|
130
119
|
return lightRec;
|
|
@@ -172,13 +161,15 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
172
161
|
|
|
173
162
|
LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
|
|
174
163
|
|
|
164
|
+
LightRecord result;
|
|
165
|
+
|
|
175
166
|
// pick a random light
|
|
176
167
|
uint l = uint( ruv.x * float( lightCount ) );
|
|
177
168
|
Light light = readLightInfo( lights, l );
|
|
178
169
|
|
|
179
170
|
if ( light.type == SPOT_LIGHT_TYPE ) {
|
|
180
171
|
|
|
181
|
-
|
|
172
|
+
result = randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
|
|
182
173
|
|
|
183
174
|
} else if ( light.type == POINT_LIGHT_TYPE ) {
|
|
184
175
|
|
|
@@ -198,7 +189,7 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
198
189
|
rec.pdf = 1.0;
|
|
199
190
|
rec.emission = light.color * light.intensity * distanceFalloff;
|
|
200
191
|
rec.type = light.type;
|
|
201
|
-
|
|
192
|
+
result = rec;
|
|
202
193
|
|
|
203
194
|
} else if ( light.type == DIR_LIGHT_TYPE ) {
|
|
204
195
|
|
|
@@ -209,15 +200,17 @@ export const lightSamplingGLSL = /* glsl */`
|
|
|
209
200
|
rec.emission = light.color * light.intensity;
|
|
210
201
|
rec.type = light.type;
|
|
211
202
|
|
|
212
|
-
|
|
203
|
+
result = rec;
|
|
213
204
|
|
|
214
205
|
} else {
|
|
215
206
|
|
|
216
207
|
// sample the light
|
|
217
|
-
|
|
208
|
+
result = randomAreaLightSample( light, rayOrigin, ruv.yz );
|
|
218
209
|
|
|
219
210
|
}
|
|
220
211
|
|
|
212
|
+
return result;
|
|
213
|
+
|
|
221
214
|
}
|
|
222
215
|
|
|
223
216
|
`;
|
|
@@ -15,9 +15,9 @@ bool isMaterialFogVolume( sampler2D materials, uint materialIndex ) {
|
|
|
15
15
|
|
|
16
16
|
// returns true if we're within the first fog volume we hit
|
|
17
17
|
bool bvhIntersectFogVolumeHit(
|
|
18
|
-
|
|
18
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
19
19
|
usampler2D materialIndexAttribute, sampler2D materials,
|
|
20
|
-
|
|
20
|
+
inout Material material
|
|
21
21
|
) {
|
|
22
22
|
|
|
23
23
|
material.fogVolume = false;
|
|
@@ -67,7 +67,18 @@ export const lightsStructGLSL = /* glsl */`
|
|
|
67
67
|
|
|
68
68
|
l.coneCos = s5.r;
|
|
69
69
|
l.penumbraCos = s5.g;
|
|
70
|
-
l.iesProfile = int( round
|
|
70
|
+
l.iesProfile = int( round( s5.b ) );
|
|
71
|
+
|
|
72
|
+
} else {
|
|
73
|
+
|
|
74
|
+
l.radius = 0.0;
|
|
75
|
+
l.near = 0.0;
|
|
76
|
+
l.decay = 0.0;
|
|
77
|
+
l.distance = 0.0;
|
|
78
|
+
|
|
79
|
+
l.coneCos = 0.0;
|
|
80
|
+
l.penumbraCos = 0.0;
|
|
81
|
+
l.iesProfile = - 1;
|
|
71
82
|
|
|
72
83
|
}
|
|
73
84
|
|
|
@@ -184,21 +184,22 @@ export const materialStructGLSL = /* glsl */ `
|
|
|
184
184
|
|
|
185
185
|
uint firstTextureTransformIdx = i + 15u;
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
m.
|
|
189
|
-
m.
|
|
190
|
-
m.
|
|
191
|
-
m.
|
|
192
|
-
m.
|
|
193
|
-
m.
|
|
194
|
-
m.
|
|
195
|
-
m.
|
|
196
|
-
m.
|
|
197
|
-
m.
|
|
198
|
-
m.
|
|
199
|
-
m.
|
|
200
|
-
m.
|
|
201
|
-
m.
|
|
187
|
+
// mat3( 1.0 ) is an identity matrix
|
|
188
|
+
m.mapTransform = m.map == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx );
|
|
189
|
+
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );
|
|
190
|
+
m.roughnessMapTransform = m.roughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 4u );
|
|
191
|
+
m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );
|
|
192
|
+
m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );
|
|
193
|
+
m.normalMapTransform = m.normalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );
|
|
194
|
+
m.clearcoatMapTransform = m.clearcoatMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 12u );
|
|
195
|
+
m.clearcoatNormalMapTransform = m.clearcoatNormalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 14u );
|
|
196
|
+
m.clearcoatRoughnessMapTransform = m.clearcoatRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 16u );
|
|
197
|
+
m.sheenColorMapTransform = m.sheenColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 18u );
|
|
198
|
+
m.sheenRoughnessMapTransform = m.sheenRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 20u );
|
|
199
|
+
m.iridescenceMapTransform = m.iridescenceMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 22u );
|
|
200
|
+
m.iridescenceThicknessMapTransform = m.iridescenceThicknessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 24u );
|
|
201
|
+
m.specularColorMapTransform = m.specularColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 26u );
|
|
202
|
+
m.specularIntensityMapTransform = m.specularIntensityMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 28u );
|
|
202
203
|
|
|
203
204
|
return m;
|
|
204
205
|
|
|
@@ -2,8 +2,9 @@ import {
|
|
|
2
2
|
ClampToEdgeWrapping,
|
|
3
3
|
Color,
|
|
4
4
|
DataTexture,
|
|
5
|
+
DataUtils,
|
|
5
6
|
EquirectangularReflectionMapping,
|
|
6
|
-
|
|
7
|
+
HalfFloatType,
|
|
7
8
|
LinearFilter,
|
|
8
9
|
RepeatWrapping,
|
|
9
10
|
RGBAFormat,
|
|
@@ -17,11 +18,11 @@ const _polar = new Spherical();
|
|
|
17
18
|
const _color = new Color();
|
|
18
19
|
export class ProceduralEquirectTexture extends DataTexture {
|
|
19
20
|
|
|
20
|
-
constructor( width, height ) {
|
|
21
|
+
constructor( width = 512, height = 512 ) {
|
|
21
22
|
|
|
22
23
|
super(
|
|
23
|
-
new
|
|
24
|
-
width, height, RGBAFormat,
|
|
24
|
+
new Uint16Array( width * height * 4 ),
|
|
25
|
+
width, height, RGBAFormat, HalfFloatType, EquirectangularReflectionMapping,
|
|
25
26
|
RepeatWrapping, ClampToEdgeWrapping, LinearFilter, LinearFilter,
|
|
26
27
|
);
|
|
27
28
|
|
|
@@ -53,10 +54,10 @@ export class ProceduralEquirectTexture extends DataTexture {
|
|
|
53
54
|
|
|
54
55
|
const i = y * width + x;
|
|
55
56
|
const i4 = 4 * i;
|
|
56
|
-
data[ i4 + 0 ] = _color.r;
|
|
57
|
-
data[ i4 + 1 ] = _color.g;
|
|
58
|
-
data[ i4 + 2 ] = _color.b;
|
|
59
|
-
data[ i4 + 3 ] = 1.0;
|
|
57
|
+
data[ i4 + 0 ] = DataUtils.toHalfFloat( _color.r );
|
|
58
|
+
data[ i4 + 1 ] = DataUtils.toHalfFloat( _color.g );
|
|
59
|
+
data[ i4 + 2 ] = DataUtils.toHalfFloat( _color.b );
|
|
60
|
+
data[ i4 + 3 ] = DataUtils.toHalfFloat( 1.0 );
|
|
60
61
|
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { DataTexture,
|
|
1
|
+
import { DataTexture, RedFormat, LinearFilter, DataUtils, HalfFloatType, Source, RepeatWrapping, RGBAFormat } from 'three';
|
|
2
|
+
import { toHalfFloatArray } from '../utils/TextureUtils.js';
|
|
2
3
|
|
|
3
4
|
function binarySearchFindClosestIndexOf( array, targetValue, offset = 0, count = array.length ) {
|
|
4
5
|
|
|
@@ -49,15 +50,15 @@ function preprocessEnvMap( envMap ) {
|
|
|
49
50
|
let newData = data;
|
|
50
51
|
if ( map.type === HalfFloatType ) {
|
|
51
52
|
|
|
52
|
-
newData = new
|
|
53
|
+
newData = new Uint16Array( data.length );
|
|
53
54
|
for ( const i in data ) {
|
|
54
55
|
|
|
55
|
-
newData[ i ] =
|
|
56
|
+
newData[ i ] = data[ i ];
|
|
56
57
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
map.image.data = newData;
|
|
60
|
-
map.type =
|
|
61
|
+
map.type = HalfFloatType;
|
|
61
62
|
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -98,8 +99,8 @@ export class EquirectHdrInfoUniform {
|
|
|
98
99
|
|
|
99
100
|
// Default to a white texture and associated weights so we don't
|
|
100
101
|
// just render black initially.
|
|
101
|
-
const whiteTex = new DataTexture( new Float32Array( [ 1, 1, 1, 1 ] ), 1, 1 );
|
|
102
|
-
whiteTex.type =
|
|
102
|
+
const whiteTex = new DataTexture( toHalfFloatArray( new Float32Array( [ 1, 1, 1, 1 ] ) ), 1, 1 );
|
|
103
|
+
whiteTex.type = HalfFloatType;
|
|
103
104
|
whiteTex.format = RGBAFormat;
|
|
104
105
|
whiteTex.minFilter = LinearFilter;
|
|
105
106
|
whiteTex.magFilter = LinearFilter;
|
|
@@ -110,8 +111,8 @@ export class EquirectHdrInfoUniform {
|
|
|
110
111
|
|
|
111
112
|
// Stores a map of [0, 1] value -> cumulative importance row & pdf
|
|
112
113
|
// used to sampling a random value to a relevant row to sample from
|
|
113
|
-
const marginalWeights = new DataTexture( new Float32Array( [ 0, 1 ] ), 1, 2 );
|
|
114
|
-
marginalWeights.type =
|
|
114
|
+
const marginalWeights = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 1 ] ) ), 1, 2 );
|
|
115
|
+
marginalWeights.type = HalfFloatType;
|
|
115
116
|
marginalWeights.format = RedFormat;
|
|
116
117
|
marginalWeights.minFilter = LinearFilter;
|
|
117
118
|
marginalWeights.magFilter = LinearFilter;
|
|
@@ -120,8 +121,8 @@ export class EquirectHdrInfoUniform {
|
|
|
120
121
|
|
|
121
122
|
// Stores a map of [0, 1] value -> cumulative importance column & pdf
|
|
122
123
|
// used to sampling a random value to a relevant pixel to sample from
|
|
123
|
-
const conditionalWeights = new DataTexture( new Float32Array( [ 0, 0, 1, 1 ] ), 2, 2 );
|
|
124
|
-
conditionalWeights.type =
|
|
124
|
+
const conditionalWeights = new DataTexture( toHalfFloatArray( new Float32Array( [ 0, 0, 1, 1 ] ) ), 2, 2 );
|
|
125
|
+
conditionalWeights.type = HalfFloatType;
|
|
125
126
|
conditionalWeights.format = RedFormat;
|
|
126
127
|
conditionalWeights.minFilter = LinearFilter;
|
|
127
128
|
conditionalWeights.magFilter = LinearFilter;
|
|
@@ -171,9 +172,9 @@ export class EquirectHdrInfoUniform {
|
|
|
171
172
|
for ( let x = 0; x < width; x ++ ) {
|
|
172
173
|
|
|
173
174
|
const i = y * width + x;
|
|
174
|
-
const r = data[ 4 * i + 0 ];
|
|
175
|
-
const g = data[ 4 * i + 1 ];
|
|
176
|
-
const b = data[ 4 * i + 2 ];
|
|
175
|
+
const r = DataUtils.fromHalfFloat( data[ 4 * i + 0 ] );
|
|
176
|
+
const g = DataUtils.fromHalfFloat( data[ 4 * i + 1 ] );
|
|
177
|
+
const b = DataUtils.fromHalfFloat( data[ 4 * i + 2 ] );
|
|
177
178
|
|
|
178
179
|
// the probability of the pixel being selected in this row is the
|
|
179
180
|
// scale of the luminance relative to the rest of the pixels.
|
|
@@ -225,8 +226,8 @@ export class EquirectHdrInfoUniform {
|
|
|
225
226
|
// the marginal and conditional data. These will be used to sample with a random number
|
|
226
227
|
// to retrieve a uv value to sample in the environment map.
|
|
227
228
|
// These values continually increase so it's okay to interpolate between them.
|
|
228
|
-
const marginalDataArray = new
|
|
229
|
-
const conditionalDataArray = new
|
|
229
|
+
const marginalDataArray = new Uint16Array( height );
|
|
230
|
+
const conditionalDataArray = new Uint16Array( width * height );
|
|
230
231
|
|
|
231
232
|
// we add a half texel offset so we're sampling the center of the pixel
|
|
232
233
|
for ( let i = 0; i < height; i ++ ) {
|
|
@@ -234,7 +235,7 @@ export class EquirectHdrInfoUniform {
|
|
|
234
235
|
const dist = ( i + 1 ) / height;
|
|
235
236
|
const row = binarySearchFindClosestIndexOf( cdfMarginal, dist );
|
|
236
237
|
|
|
237
|
-
marginalDataArray[ i ] = ( row + 0.5 ) / height;
|
|
238
|
+
marginalDataArray[ i ] = DataUtils.toHalfFloat( ( row + 0.5 ) / height );
|
|
238
239
|
|
|
239
240
|
}
|
|
240
241
|
|
|
@@ -246,7 +247,7 @@ export class EquirectHdrInfoUniform {
|
|
|
246
247
|
const dist = ( x + 1 ) / width;
|
|
247
248
|
const col = binarySearchFindClosestIndexOf( cdfConditional, dist, y * width, width );
|
|
248
249
|
|
|
249
|
-
conditionalDataArray[ i ] = ( col + 0.5 ) / width;
|
|
250
|
+
conditionalDataArray[ i ] = DataUtils.toHalfFloat( ( col + 0.5 ) / width );
|
|
250
251
|
|
|
251
252
|
}
|
|
252
253
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClampToEdgeWrapping,
|
|
3
3
|
Color,
|
|
4
|
-
|
|
4
|
+
HalfFloatType,
|
|
5
5
|
LinearFilter,
|
|
6
6
|
MeshBasicMaterial,
|
|
7
7
|
NoToneMapping,
|
|
@@ -20,7 +20,7 @@ export class IESProfilesTexture extends WebGLArrayRenderTarget {
|
|
|
20
20
|
|
|
21
21
|
const tex = this.texture;
|
|
22
22
|
tex.format = RGBAFormat;
|
|
23
|
-
tex.type =
|
|
23
|
+
tex.type = HalfFloatType;
|
|
24
24
|
tex.minFilter = LinearFilter;
|
|
25
25
|
tex.magFilter = LinearFilter;
|
|
26
26
|
tex.wrapS = ClampToEdgeWrapping;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, Vector3, Quaternion, Matrix4 } from 'three';
|
|
1
|
+
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, Vector3, Quaternion, Matrix4, NearestFilter } from 'three';
|
|
2
2
|
|
|
3
3
|
const LIGHT_PIXELS = 6;
|
|
4
4
|
const RECT_AREA_LIGHT = 0;
|
|
@@ -16,6 +16,8 @@ export class LightsInfoUniformStruct {
|
|
|
16
16
|
tex.wrapS = ClampToEdgeWrapping;
|
|
17
17
|
tex.wrapT = ClampToEdgeWrapping;
|
|
18
18
|
tex.generateMipmaps = false;
|
|
19
|
+
tex.minFilter = NearestFilter;
|
|
20
|
+
tex.magFilter = NearestFilter;
|
|
19
21
|
|
|
20
22
|
this.tex = tex;
|
|
21
23
|
this.count = 0;
|
|
@@ -46,7 +48,7 @@ export class LightsInfoUniformStruct {
|
|
|
46
48
|
const worldQuaternion = new Quaternion();
|
|
47
49
|
const eye = new Vector3();
|
|
48
50
|
const target = new Vector3();
|
|
49
|
-
const up = new Vector3();
|
|
51
|
+
const up = new Vector3( 0, 1, 0 );
|
|
50
52
|
|
|
51
53
|
for ( let i = 0, l = lights.length; i < l; i ++ ) {
|
|
52
54
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, FrontSide, BackSide, DoubleSide } from 'three';
|
|
1
|
+
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, FrontSide, BackSide, DoubleSide, NearestFilter } from 'three';
|
|
2
2
|
import { reduceTexturesToUniqueSources, getTextureHash } from './utils.js';
|
|
3
3
|
|
|
4
4
|
const MATERIAL_PIXELS = 45;
|
|
@@ -53,6 +53,8 @@ export class MaterialsTexture extends DataTexture {
|
|
|
53
53
|
this.type = FloatType;
|
|
54
54
|
this.wrapS = ClampToEdgeWrapping;
|
|
55
55
|
this.wrapT = ClampToEdgeWrapping;
|
|
56
|
+
this.minFilter = NearestFilter;
|
|
57
|
+
this.magFilter = NearestFilter;
|
|
56
58
|
this.generateMipmaps = false;
|
|
57
59
|
this.threeCompatibilityTransforms = false;
|
|
58
60
|
this.features = new MaterialFeatures();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WebGLRenderTarget, RGBAFormat,
|
|
1
|
+
import { WebGLRenderTarget, RGBAFormat, HalfFloatType, PMREMGenerator, DataTexture, EquirectangularReflectionMapping } from 'three';
|
|
2
2
|
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
|
|
3
3
|
import { MaterialBase } from '../materials/MaterialBase.js';
|
|
4
4
|
import { utilsGLSL } from '../shader/common/utils.glsl.js';
|
|
@@ -58,7 +58,7 @@ export class BlurredEnvMapGenerator {
|
|
|
58
58
|
this.renderer = renderer;
|
|
59
59
|
this.pmremGenerator = new PMREMGenerator( renderer );
|
|
60
60
|
this.copyQuad = new FullScreenQuad( new PMREMCopyMaterial() );
|
|
61
|
-
this.renderTarget = new WebGLRenderTarget( 1, 1, { type:
|
|
61
|
+
this.renderTarget = new WebGLRenderTarget( 1, 1, { type: HalfFloatType, format: RGBAFormat } );
|
|
62
62
|
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -95,10 +95,10 @@ export class BlurredEnvMapGenerator {
|
|
|
95
95
|
renderer.autoClear = prevClear;
|
|
96
96
|
|
|
97
97
|
// read the data back
|
|
98
|
-
const buffer = new
|
|
98
|
+
const buffer = new Uint16Array( width * height * 4 );
|
|
99
99
|
renderer.readRenderTargetPixels( renderTarget, 0, 0, width, height, buffer );
|
|
100
100
|
|
|
101
|
-
const result = new DataTexture( buffer, width, height, RGBAFormat,
|
|
101
|
+
const result = new DataTexture( buffer, width, height, RGBAFormat, HalfFloatType );
|
|
102
102
|
result.minFilter = texture.minFilter;
|
|
103
103
|
result.magFilter = texture.magFilter;
|
|
104
104
|
result.wrapS = texture.wrapS;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BufferAttribute } from 'three';
|
|
2
|
-
import {
|
|
2
|
+
import { mergeGeometries, mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
3
3
|
export function getGroupMaterialIndicesAttribute( geometry, materials, allMaterials ) {
|
|
4
4
|
|
|
5
5
|
const indexAttr = geometry.index;
|
|
@@ -176,6 +176,12 @@ export function mergeMeshes( meshes, options = {} ) {
|
|
|
176
176
|
const geometry = options.cloneGeometry ? originalGeometry.clone() : originalGeometry;
|
|
177
177
|
geometry.applyMatrix4( mesh.matrixWorld );
|
|
178
178
|
|
|
179
|
+
if ( mesh.matrixWorld.determinant() < 0 ) {
|
|
180
|
+
|
|
181
|
+
geometry.index.array.reverse();
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
179
185
|
// ensure our geometry has common attributes
|
|
180
186
|
setCommonAttributes( geometry, {
|
|
181
187
|
attributes: options.attributes,
|
|
@@ -207,7 +213,7 @@ export function mergeMeshes( meshes, options = {} ) {
|
|
|
207
213
|
|
|
208
214
|
} );
|
|
209
215
|
|
|
210
|
-
const geometry =
|
|
216
|
+
const geometry = mergeGeometries( transformedGeometry, false );
|
|
211
217
|
const textures = Array.from( textureSet );
|
|
212
218
|
return { geometry, materials, textures };
|
|
213
219
|
|
package/src/utils/IESLoader.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DataTexture,
|
|
3
3
|
FileLoader,
|
|
4
|
-
|
|
4
|
+
HalfFloatType,
|
|
5
5
|
LinearFilter,
|
|
6
6
|
RedFormat,
|
|
7
7
|
MathUtils,
|
|
8
8
|
Loader,
|
|
9
9
|
} from 'three';
|
|
10
10
|
|
|
11
|
+
import { toHalfFloatArray } from './TextureUtils.js';
|
|
12
|
+
|
|
11
13
|
function IESLamp( text ) {
|
|
12
14
|
|
|
13
15
|
const _self = this;
|
|
@@ -286,7 +288,7 @@ export class IESLoader extends Loader {
|
|
|
286
288
|
loader.setPath( this.path );
|
|
287
289
|
loader.setRequestHeader( this.requestHeader );
|
|
288
290
|
|
|
289
|
-
const texture = new DataTexture( null, 360, 180, RedFormat,
|
|
291
|
+
const texture = new DataTexture( null, 360, 180, RedFormat, HalfFloatType );
|
|
290
292
|
texture.minFilter = LinearFilter;
|
|
291
293
|
texture.magFilter = LinearFilter;
|
|
292
294
|
|
|
@@ -294,7 +296,7 @@ export class IESLoader extends Loader {
|
|
|
294
296
|
|
|
295
297
|
const iesLamp = new IESLamp( text );
|
|
296
298
|
|
|
297
|
-
texture.image.data = this._getIESValues( iesLamp );
|
|
299
|
+
texture.image.data = toHalfFloatArray( this._getIESValues( iesLamp ) );
|
|
298
300
|
texture.needsUpdate = true;
|
|
299
301
|
|
|
300
302
|
if ( onLoad !== undefined ) {
|
|
@@ -312,10 +314,10 @@ export class IESLoader extends Loader {
|
|
|
312
314
|
parse( text ) {
|
|
313
315
|
|
|
314
316
|
const iesLamp = new IESLamp( text );
|
|
315
|
-
const texture = new DataTexture( null, 360, 180, RedFormat,
|
|
317
|
+
const texture = new DataTexture( null, 360, 180, RedFormat, HalfFloatType );
|
|
316
318
|
texture.minFilter = LinearFilter;
|
|
317
319
|
texture.magFilter = LinearFilter;
|
|
318
|
-
texture.image.data = this._getIESValues( iesLamp );
|
|
320
|
+
texture.image.data = toHalfFloatArray( this._getIESValues( iesLamp ) );
|
|
319
321
|
texture.needsUpdate = true;
|
|
320
322
|
|
|
321
323
|
return texture;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DataUtils } from 'three';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export function toHalfFloatArray( f32Array ) {
|
|
5
|
+
|
|
6
|
+
const f16Array = new Uint16Array( f32Array.length );
|
|
7
|
+
for ( let i = 0, n = f32Array.length; i < n; ++ i ) {
|
|
8
|
+
|
|
9
|
+
f16Array[ i ] = DataUtils.toHalfFloat( f32Array[ i ] );
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return f16Array;
|
|
14
|
+
|
|
15
|
+
}
|