@takram/three-geospatial 0.0.1-alpha.6 → 0.0.1-alpha.8

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.
@@ -0,0 +1,207 @@
1
+ import { Material } from 'three'
2
+
3
+ import { clamp } from './math'
4
+
5
+ interface EffectLike {
6
+ defines: Map<string, string>
7
+ }
8
+
9
+ export function define(name: string) {
10
+ return <T extends Material | EffectLike, K extends keyof T>(
11
+ target: T[K] extends boolean ? T : never,
12
+ propertyKey: K
13
+ ) => {
14
+ if (target instanceof Material) {
15
+ Object.defineProperty(target, propertyKey, {
16
+ enumerable: true,
17
+ get(this: Extract<T, Material>): boolean {
18
+ return this.defines?.[name] != null
19
+ },
20
+ set(this: Extract<T, Material>, value: boolean) {
21
+ if (value !== this[propertyKey]) {
22
+ if (value) {
23
+ this.defines ??= {}
24
+ this.defines[name] = '1'
25
+ } else {
26
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
27
+ delete this.defines?.[name]
28
+ }
29
+ this.needsUpdate = true
30
+ }
31
+ }
32
+ })
33
+ } else {
34
+ Object.defineProperty(target, propertyKey, {
35
+ enumerable: true,
36
+ get(this: Extract<T, EffectLike>): boolean {
37
+ return this.defines.has(name)
38
+ },
39
+ set(this: Extract<T, EffectLike>, value: boolean) {
40
+ if (value !== this[propertyKey]) {
41
+ if (value) {
42
+ this.defines.set(name, '1')
43
+ } else {
44
+ this.defines.delete(name)
45
+ }
46
+ ;(this as any).setChanged() // Bypass protected privilege
47
+ }
48
+ }
49
+ })
50
+ }
51
+ }
52
+ }
53
+
54
+ export interface DefineIntDecoratorOptions {
55
+ min?: number
56
+ max?: number
57
+ }
58
+
59
+ export function defineInt(
60
+ name: string,
61
+ {
62
+ min = Number.MIN_SAFE_INTEGER,
63
+ max = Number.MAX_SAFE_INTEGER
64
+ }: DefineIntDecoratorOptions = {}
65
+ ) {
66
+ return <T extends Material | EffectLike, K extends keyof T>(
67
+ target: T[K] extends number ? T : never,
68
+ propertyKey: K
69
+ ) => {
70
+ if (target instanceof Material) {
71
+ Object.defineProperty(target, propertyKey, {
72
+ enumerable: true,
73
+ get(this: Extract<T, Material>): number {
74
+ const value = this.defines?.[name]
75
+ return value != null ? parseInt(value) : 0
76
+ },
77
+ set(this: Extract<T, Material>, value: number) {
78
+ const prevValue = this[propertyKey]
79
+ if (value !== prevValue) {
80
+ this.defines ??= {}
81
+ this.defines[name] = clamp(value, min, max).toFixed(0)
82
+ this.needsUpdate = true
83
+ }
84
+ }
85
+ })
86
+ } else {
87
+ Object.defineProperty(target, propertyKey, {
88
+ enumerable: true,
89
+ get(this: Extract<T, EffectLike>): number {
90
+ const value = this.defines.get(name)
91
+ return value != null ? parseInt(value) : 0
92
+ },
93
+ set(this: Extract<T, EffectLike>, value: number) {
94
+ const prevValue = this[propertyKey]
95
+ if (value !== prevValue) {
96
+ this.defines.set(name, clamp(value, min, max).toFixed(0))
97
+ ;(this as any).setChanged() // Bypass protected privilege
98
+ }
99
+ }
100
+ })
101
+ }
102
+ }
103
+ }
104
+
105
+ export interface DefineFloatDecoratorOptions {
106
+ min?: number
107
+ max?: number
108
+ precision?: number
109
+ }
110
+
111
+ export function defineFloat(
112
+ name: string,
113
+ {
114
+ min = -Infinity,
115
+ max = Infinity,
116
+ precision = 7
117
+ }: DefineFloatDecoratorOptions = {}
118
+ ) {
119
+ return <T extends Material | EffectLike, K extends keyof T>(
120
+ target: T[K] extends number ? T : never,
121
+ propertyKey: K
122
+ ) => {
123
+ if (target instanceof Material) {
124
+ Object.defineProperty(target, propertyKey, {
125
+ enumerable: true,
126
+ get(this: Extract<T, Material>): number {
127
+ const value = this.defines?.[name]
128
+ return value != null ? parseFloat(value) : 0
129
+ },
130
+ set(this: Extract<T, Material>, value: number) {
131
+ const prevValue = this[propertyKey]
132
+ if (value !== prevValue) {
133
+ this.defines ??= {}
134
+ this.defines[name] = clamp(value, min, max).toFixed(precision)
135
+ this.needsUpdate = true
136
+ }
137
+ }
138
+ })
139
+ } else {
140
+ Object.defineProperty(target, propertyKey, {
141
+ enumerable: true,
142
+ get(this: Extract<T, EffectLike>): number {
143
+ const value = this.defines.get(name)
144
+ return value != null ? parseFloat(value) : 0
145
+ },
146
+ set(this: Extract<T, EffectLike>, value: number) {
147
+ const prevValue = this[propertyKey]
148
+ if (value !== prevValue) {
149
+ this.defines.set(name, clamp(value, min, max).toFixed(precision))
150
+ ;(this as any).setChanged() // Bypass protected privilege
151
+ }
152
+ }
153
+ })
154
+ }
155
+ }
156
+ }
157
+
158
+ export interface DefineExpressionDecoratorOptions {
159
+ validate?: (value: string) => boolean
160
+ }
161
+
162
+ export function defineExpression(
163
+ name: string,
164
+ { validate }: DefineExpressionDecoratorOptions = {}
165
+ ) {
166
+ return <T extends Material | EffectLike, K extends keyof T>(
167
+ target: T[K] extends string ? T : never,
168
+ propertyKey: K
169
+ ) => {
170
+ if (target instanceof Material) {
171
+ Object.defineProperty(target, propertyKey, {
172
+ enumerable: true,
173
+ get(this: Extract<T, Material>): string {
174
+ return this.defines?.[name] ?? ''
175
+ },
176
+ set(this: Extract<T, Material>, value: string) {
177
+ if (value !== this[propertyKey]) {
178
+ if (validate?.(value) === false) {
179
+ console.error(`Expression validation failed: ${value}`)
180
+ return
181
+ }
182
+ this.defines ??= {}
183
+ this.defines[name] = value
184
+ this.needsUpdate = true
185
+ }
186
+ }
187
+ })
188
+ } else {
189
+ Object.defineProperty(target, propertyKey, {
190
+ enumerable: true,
191
+ get(this: Extract<T, EffectLike>): string {
192
+ return this.defines.get(name) ?? ''
193
+ },
194
+ set(this: Extract<T, EffectLike>, value: string) {
195
+ if (value !== this[propertyKey]) {
196
+ if (validate?.(value) === false) {
197
+ console.error(`Expression validation failed: ${value}`)
198
+ return
199
+ }
200
+ this.defines.set(name, value)
201
+ ;(this as any).setChanged() // Bypass protected privilege
202
+ }
203
+ }
204
+ })
205
+ }
206
+ }
207
+ }
@@ -0,0 +1,68 @@
1
+ import { type Uniform } from 'three'
2
+
3
+ // TODO: Make mutable value types (e.g. vectors, matrices) read-only.
4
+
5
+ // Maps argument of type [T1, K1[], T2, K2[], ...] to:
6
+ // { [K in K1]: T1[K],
7
+ // [K in K2]: T2[K], ... }
8
+ export type PropertyShorthand<Args extends readonly unknown[]> =
9
+ Args extends readonly [infer T, infer K, ...infer Rest]
10
+ ? K extends readonly string[]
11
+ ? K[number] extends keyof T
12
+ ? Rest extends readonly unknown[]
13
+ ? { [P in K[number]]: T[P] } & PropertyShorthand<Rest>
14
+ : { [P in K[number]]: T[P] }
15
+ : never // K must be keyof T
16
+ : never // K must be an array
17
+ : {} // Termination
18
+
19
+ export function definePropertyShorthand<T, Args extends readonly unknown[]>(
20
+ destination: T,
21
+ ...sourceKeysArgs: [...Args]
22
+ ): T & PropertyShorthand<Args> {
23
+ const descriptors: PropertyDescriptorMap = {}
24
+ for (let i = 0; i < sourceKeysArgs.length; i += 2) {
25
+ const source = sourceKeysArgs[i]
26
+ const keys = sourceKeysArgs[i + 1] as ReadonlyArray<keyof typeof source>
27
+ for (const key of keys) {
28
+ descriptors[key] = {
29
+ enumerable: true,
30
+ get: () => source[key],
31
+ set: (value: any) => {
32
+ source[key] = value
33
+ }
34
+ }
35
+ }
36
+ }
37
+ Object.defineProperties(destination, descriptors)
38
+ return destination as T & PropertyShorthand<Args>
39
+ }
40
+
41
+ // The argument of defineUniformShorthand can also be variadic, but I can't
42
+ // think of any practical use cases for it.
43
+
44
+ export type UniformShorthand<
45
+ T extends { uniforms: Record<K, Uniform> },
46
+ K extends keyof T['uniforms']
47
+ > = {
48
+ [P in K]: T['uniforms'][P] extends Uniform<infer U> ? U : never
49
+ }
50
+
51
+ export function defineUniformShorthand<
52
+ T,
53
+ S extends { uniforms: Record<K, Uniform> },
54
+ K extends keyof S['uniforms']
55
+ >(destination: T, source: S, keys: readonly K[]): T & UniformShorthand<S, K> {
56
+ const descriptors: PropertyDescriptorMap = {}
57
+ for (const key of keys) {
58
+ descriptors[key] = {
59
+ enumerable: true,
60
+ get: () => source.uniforms[key].value,
61
+ set: (value: S['uniforms'][K]) => {
62
+ source.uniforms[key].value = value
63
+ }
64
+ }
65
+ }
66
+ Object.defineProperties(destination, descriptors)
67
+ return destination as T & UniformShorthand<S, K>
68
+ }
package/src/index.ts CHANGED
@@ -3,6 +3,8 @@ export * from './assertions'
3
3
  export * from './bufferGeometry'
4
4
  export * from './constants'
5
5
  export * from './DataLoader'
6
+ export * from './decorators'
7
+ export * from './defineShorthand'
6
8
  export * from './Ellipsoid'
7
9
  export * from './EllipsoidGeometry'
8
10
  export * from './Geodetic'
@@ -10,6 +12,7 @@ export * from './math'
10
12
  export * from './PointOfView'
11
13
  export * from './Rectangle'
12
14
  export * from './resolveIncludes'
15
+ export * from './STBNLoader'
13
16
  export * from './TileCoordinate'
14
17
  export * from './TilingScheme'
15
18
  export * from './typedArray'
package/src/math.ts CHANGED
@@ -10,7 +10,42 @@ export const isPowerOfTwo = MathUtils.isPowerOfTwo
10
10
  export const ceilPowerOfTwo = MathUtils.ceilPowerOfTwo
11
11
  export const floorPowerOfTwo = MathUtils.floorPowerOfTwo
12
12
  export const normalize = MathUtils.normalize
13
- export const remap = MathUtils.mapLinear
13
+
14
+ export function remap(x: number, min1: number, max1: number): number
15
+ export function remap(
16
+ x: number,
17
+ min1: number,
18
+ max1: number,
19
+ min2: number,
20
+ max2: number
21
+ ): number
22
+ export function remap(
23
+ x: number,
24
+ min1: number,
25
+ max1: number,
26
+ min2 = 0,
27
+ max2 = 1
28
+ ): number {
29
+ return MathUtils.mapLinear(x, min1, max1, min2, max2)
30
+ }
31
+
32
+ export function remapClamped(x: number, min1: number, max1: number): number
33
+ export function remapClamped(
34
+ x: number,
35
+ min1: number,
36
+ max1: number,
37
+ min2: number,
38
+ max2: number
39
+ ): number
40
+ export function remapClamped(
41
+ x: number,
42
+ min1: number,
43
+ max1: number,
44
+ min2 = 0,
45
+ max2 = 1
46
+ ): number {
47
+ return clamp(MathUtils.mapLinear(x, min1, max1, min2, max2), min2, max2)
48
+ }
14
49
 
15
50
  // Prefer glsl's argument order which differs from that of MathUtils.
16
51
  export function smoothstep(min: number, max: number, x: number): number {
package/src/r3f/types.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
- type Color,
3
- type ExtendedColors,
4
2
  type NodeProps,
5
3
  type Overwrite,
6
- type Vector2,
7
- type Vector3,
8
- type Vector4
4
+ type Color as R3FColor,
5
+ type Vector2 as R3FVector2,
6
+ type Vector3 as R3FVector3,
7
+ type Vector4 as R3FVector4
9
8
  } from '@react-three/fiber'
10
9
  import {
10
+ type Color as ColorImpl,
11
11
  type Vector2 as Vector2Impl,
12
12
  type Vector3 as Vector3Impl,
13
13
  type Vector4 as Vector4Impl
@@ -17,16 +17,15 @@ import { type WritableKeysOf } from 'type-fest'
17
17
  import { type Callable } from '../types'
18
18
 
19
19
  // prettier-ignore
20
- export type ExtendedVectors<T> = {
20
+ export type ExtendedProps<T> = {
21
21
  [K in keyof T]:
22
- Vector2Impl extends T[K] ? Vector2 | T[K] :
23
- Vector3Impl extends T[K] ? Vector3 | T[K] :
24
- Vector4Impl extends T[K] ? Vector4 | T[K] :
22
+ Vector2Impl extends T[K] ? R3FVector2 | T[K] :
23
+ Vector3Impl extends T[K] ? R3FVector3 | T[K] :
24
+ Vector4Impl extends T[K] ? R3FVector4 | T[K] :
25
+ ColorImpl extends T[K] ? R3FColor | T[K] :
25
26
  T[K]
26
27
  }
27
28
 
28
- export type ExtendedProps<T> = ExtendedColors<ExtendedVectors<T>>
29
-
30
29
  // @react-three/fiber's NonFunctionKeys cannot exclude partial functions.
31
30
  // This excludes callback properties, which may be undesirable behavior.
32
31
  type NonFunctionKeys<T> = keyof {
@@ -41,7 +40,7 @@ type WritableNonExtendableKeysOf<T> =
41
40
  Vector2Impl extends T[K] ? K :
42
41
  Vector3Impl extends T[K] ? K :
43
42
  Vector4Impl extends T[K] ? K :
44
- Color extends T[K] ? K :
43
+ ColorImpl extends T[K] ? K :
45
44
  never
46
45
  ]: any
47
46
  }
@@ -60,5 +59,7 @@ export type PassThoughInstanceProps<
60
59
  >
61
60
 
62
61
  export type ExpandNestedProps<T, Prop extends keyof T & string> = {
63
- [K in keyof T[Prop] as K extends string ? `${Prop}-${K}` : never]: T[Prop][K]
62
+ [K in keyof NonNullable<T[Prop]> as K extends string
63
+ ? `${Prop}-${K}`
64
+ : 'never']: NonNullable<T[Prop]>[K]
64
65
  }
@@ -0,0 +1,79 @@
1
+ // Reference: https://github.com/mrdoob/three.js/blob/r171/examples/jsm/csm/CSMShader.js
2
+
3
+ #ifndef SHADOW_CASCADE_COUNT
4
+ #error "SHADOW_CASCADE_COUNT macro must be defined."
5
+ #endif // SHADOW_CASCADE_COUNT
6
+
7
+ int getCascadeIndex(
8
+ const mat4 viewMatrix,
9
+ const vec3 worldPosition,
10
+ const vec2 intervals[SHADOW_CASCADE_COUNT],
11
+ const float near,
12
+ const float far
13
+ ) {
14
+ vec4 viewPosition = viewMatrix * vec4(worldPosition, 1.0);
15
+ float depth = viewZToOrthographicDepth(viewPosition.z, near, far);
16
+ vec2 interval;
17
+ #pragma unroll_loop_start
18
+ for (int i = 0; i < 4; ++i) {
19
+ #if UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
20
+ interval = intervals[i];
21
+ if (depth >= interval.x && depth < interval.y) {
22
+ return UNROLLED_LOOP_INDEX;
23
+ }
24
+ #endif // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
25
+ }
26
+ #pragma unroll_loop_end
27
+ return SHADOW_CASCADE_COUNT - 1;
28
+ }
29
+
30
+ int getFadedCascadeIndex(
31
+ const mat4 viewMatrix,
32
+ const vec3 worldPosition,
33
+ const vec2 intervals[SHADOW_CASCADE_COUNT],
34
+ const float near,
35
+ const float far,
36
+ const float jitter
37
+ ) {
38
+ vec4 viewPosition = viewMatrix * vec4(worldPosition, 1.0);
39
+ float depth = viewZToOrthographicDepth(viewPosition.z, near, far);
40
+
41
+ vec2 interval;
42
+ float intervalCenter;
43
+ float closestEdge;
44
+ float margin;
45
+ int nextIndex = -1;
46
+ int prevIndex = -1;
47
+ float alpha;
48
+
49
+ #pragma unroll_loop_start
50
+ for (int i = 0; i < 4; ++i) {
51
+ #if UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
52
+ interval = intervals[i];
53
+ intervalCenter = (interval.x + interval.y) * 0.5;
54
+ closestEdge = depth < intervalCenter ? interval.x : interval.y;
55
+ margin = closestEdge * closestEdge * 0.5;
56
+ interval += margin * vec2(-0.5, 0.5);
57
+
58
+ #if UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT - 1
59
+ if (depth >= interval.x && depth < interval.y) {
60
+ prevIndex = nextIndex;
61
+ nextIndex = UNROLLED_LOOP_INDEX;
62
+ alpha = saturate(min(depth - interval.x, interval.y - depth) / margin);
63
+ }
64
+ #else // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT - 1
65
+ // Don't fade out the last cascade.
66
+ if (depth >= interval.x) {
67
+ prevIndex = nextIndex;
68
+ nextIndex = UNROLLED_LOOP_INDEX;
69
+ alpha = saturate((depth - interval.x) / margin);
70
+ }
71
+ #endif // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT - 1
72
+ #endif // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
73
+ }
74
+ #pragma unroll_loop_end
75
+
76
+ return jitter <= alpha
77
+ ? nextIndex
78
+ : prevIndex;
79
+ }
@@ -1,17 +1,21 @@
1
+ import _cascadedShadowMaps from './cascadedShadowMaps.glsl?raw'
1
2
  import _depth from './depth.glsl?raw'
2
3
  import _generators from './generators.glsl?raw'
4
+ import _interleavedGradientNoise from './interleavedGradientNoise.glsl?raw'
3
5
  import _math from './math.glsl?raw'
4
6
  import _packing from './packing.glsl?raw'
5
- import _poissonDisk from './poissonDisk.glsl?raw'
6
7
  import _raySphereIntersection from './raySphereIntersection.glsl?raw'
7
8
  import _transform from './transform.glsl?raw'
8
9
  import _turbo from './turbo.glsl?raw'
10
+ import _vogelDisk from './vogelDisk.glsl?raw'
9
11
 
12
+ export const cascadedShadowMaps: string = _cascadedShadowMaps
10
13
  export const depth: string = _depth
11
14
  export const generators: string = _generators
15
+ export const interleavedGradientNoise = _interleavedGradientNoise
12
16
  export const math: string = _math
13
17
  export const packing: string = _packing
14
- export const poissonDisk: string = _poissonDisk
15
18
  export const raySphereIntersection: string = _raySphereIntersection
16
19
  export const transform: string = _transform
17
20
  export const turbo: string = _turbo
21
+ export const vogelDisk = _vogelDisk
@@ -0,0 +1,6 @@
1
+ // Reference: https://advances.realtimerendering.com/s2014/index.html#_NEXT_GENERATION_POST
2
+
3
+ float interleavedGradientNoise(const vec2 coord) {
4
+ const vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
5
+ return fract(magic.z * fract(dot(coord, magic.xy)));
6
+ }
@@ -2,22 +2,6 @@
2
2
  #define saturate(a) clamp(a, 0.0, 1.0)
3
3
  #endif // !defined(saturate)
4
4
 
5
- float inverseLerp(const float x, const float y, const float a) {
6
- return (a - x) / (y - x);
7
- }
8
-
9
- vec2 inverseLerp(const vec2 x, const vec2 y, const vec2 a) {
10
- return (a - x) / (y - x);
11
- }
12
-
13
- vec3 inverseLerp(const vec3 x, const vec3 y, const vec3 a) {
14
- return (a - x) / (y - x);
15
- }
16
-
17
- vec4 inverseLerp(const vec4 x, const vec4 y, const vec4 a) {
18
- return (a - x) / (y - x);
19
- }
20
-
21
5
  float remap(const float x, const float min1, const float max1, const float min2, const float max2) {
22
6
  return min2 + (x - min1) / (max1 - min1) * (max2 - min2);
23
7
  }
@@ -34,6 +18,46 @@ vec4 remap(const vec4 x, const vec4 min1, const vec4 max1, const vec4 min2, cons
34
18
  return min2 + (x - min1) / (max1 - min1) * (max2 - min2);
35
19
  }
36
20
 
21
+ float remapClamped(
22
+ const float x,
23
+ const float min1,
24
+ const float max1,
25
+ const float min2,
26
+ const float max2
27
+ ) {
28
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
29
+ }
30
+
31
+ vec2 remapClamped(
32
+ const vec2 x,
33
+ const vec2 min1,
34
+ const vec2 max1,
35
+ const vec2 min2,
36
+ const vec2 max2
37
+ ) {
38
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
39
+ }
40
+
41
+ vec3 remapClamped(
42
+ const vec3 x,
43
+ const vec3 min1,
44
+ const vec3 max1,
45
+ const vec3 min2,
46
+ const vec3 max2
47
+ ) {
48
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
49
+ }
50
+
51
+ vec4 remapClamped(
52
+ const vec4 x,
53
+ const vec4 min1,
54
+ const vec4 max1,
55
+ const vec4 min2,
56
+ const vec4 max2
57
+ ) {
58
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
59
+ }
60
+
37
61
  // Implicitly remap to 0 and 1
38
62
  float remap(const float x, const float min1, const float max1) {
39
63
  return (x - min1) / (max1 - min1);
@@ -50,3 +74,19 @@ vec3 remap(const vec3 x, const vec3 min1, const vec3 max1) {
50
74
  vec4 remap(const vec4 x, const vec4 min1, const vec4 max1) {
51
75
  return (x - min1) / (max1 - min1);
52
76
  }
77
+
78
+ float remapClamped(const float x, const float min1, const float max1) {
79
+ return saturate((x - min1) / (max1 - min1));
80
+ }
81
+
82
+ vec2 remapClamped(const vec2 x, const vec2 min1, const vec2 max1) {
83
+ return saturate((x - min1) / (max1 - min1));
84
+ }
85
+
86
+ vec3 remapClamped(const vec3 x, const vec3 min1, const vec3 max1) {
87
+ return saturate((x - min1) / (max1 - min1));
88
+ }
89
+
90
+ vec4 remapClamped(const vec4 x, const vec4 min1, const vec4 max1) {
91
+ return saturate((x - min1) / (max1 - min1));
92
+ }
@@ -0,0 +1,8 @@
1
+ // Reference: https://www.gamedev.net/tutorials/programming/graphics/contact-hardening-soft-shadows-made-fast-r4906/
2
+
3
+ vec2 vogelDisk(const int index, const int sampleCount, const float phi) {
4
+ const float goldenAngle = 2.39996322972865332;
5
+ float r = sqrt(float(index) + 0.5) / sqrt(float(sampleCount));
6
+ float theta = float(index) * goldenAngle + phi;
7
+ return r * vec2(cos(theta), sin(theta));
8
+ }
@@ -1,5 +1,17 @@
1
1
  import { type TypedArray, type TypedArrayConstructor } from './typedArray'
2
2
 
3
+ let hostLittleEndian: boolean | undefined
4
+
5
+ function isHostLittleEndian(): boolean {
6
+ if (hostLittleEndian != null) {
7
+ return hostLittleEndian
8
+ }
9
+ const a = new Uint32Array([0x10000000])
10
+ const b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength)
11
+ hostLittleEndian = b[0] === 0
12
+ return hostLittleEndian
13
+ }
14
+
3
15
  type GetValue = keyof {
4
16
  [K in keyof DataView as DataView[K] extends (byteOffset: number) => number
5
17
  ? K
@@ -19,6 +31,9 @@ function parseTypedArray<K extends GetValue>(
19
31
  getValue: K,
20
32
  littleEndian = true
21
33
  ): TypedArray {
34
+ if (littleEndian === isHostLittleEndian()) {
35
+ return new TypedArray(buffer)
36
+ }
22
37
  const data = new DataView(buffer)
23
38
  const array = new TypedArray(data.byteLength / TypedArray.BYTES_PER_ELEMENT)
24
39
  for (
@@ -36,15 +51,11 @@ export type TypedArrayParser<T extends TypedArray> = (
36
51
  littleEndian?: boolean
37
52
  ) => T
38
53
 
39
- export const parseUint8Array: TypedArrayParser<Uint8Array> = (
40
- buffer,
41
- littleEndian
42
- ) => parseTypedArray(buffer, Uint8Array, 'getUint8', littleEndian)
54
+ export const parseUint8Array: TypedArrayParser<Uint8Array> = buffer =>
55
+ new Uint8Array(buffer)
43
56
 
44
- export const parseInt8Array: TypedArrayParser<Int8Array> = (
45
- buffer,
46
- littleEndian
47
- ) => parseTypedArray(buffer, Int8Array, 'getInt8', littleEndian)
57
+ export const parseInt8Array: TypedArrayParser<Int8Array> = buffer =>
58
+ new Int8Array(buffer)
48
59
 
49
60
  export const parseUint16Array: TypedArrayParser<Uint16Array> = (
50
61
  buffer,
@@ -7,15 +7,15 @@ import { Data3DTexture, DataTexture, Loader, TypedArray } from 'three';
7
7
  type ParameterProperties<T> = {
8
8
  [K in WritableKeysOf<T> as T[K] extends Callable ? never : K]: T[K];
9
9
  };
10
- export type DataTextureParameters = Omit<Partial<ParameterProperties<DataTexture>>, 'image'> & {
10
+ export interface DataTextureParameters extends Omit<Partial<ParameterProperties<DataTexture>>, 'image'> {
11
11
  width?: number;
12
12
  height?: number;
13
- };
14
- export type Data3DTextureParameters = Omit<Partial<ParameterProperties<Data3DTexture>>, 'image'> & {
13
+ }
14
+ export interface Data3DTextureParameters extends Omit<Partial<ParameterProperties<Data3DTexture>>, 'image'> {
15
15
  width?: number;
16
16
  height?: number;
17
17
  depth?: number;
18
- };
18
+ }
19
19
  export declare abstract class DataLoader<T extends DataTexture | Data3DTexture = DataTexture | Data3DTexture, U extends TypedArray = TypedArray> extends Loader<T> {
20
20
  abstract readonly Texture: Class<T>;
21
21
  abstract readonly TypedArrayLoader: Class<TypedArrayLoader<U>>;
@@ -0,0 +1 @@
1
+ export declare const STBNLoader: import('type-fest').Class<import('./DataLoader').DataLoader<import('three').Data3DTexture, Uint8Array<ArrayBufferLike>>>;
@@ -1,5 +1,6 @@
1
1
  import { BufferGeometry } from 'three';
2
2
 
3
- export type BufferGeometryLike = Pick<BufferGeometry, 'attributes' | 'index' | 'boundingBox' | 'boundingSphere'>;
3
+ export interface BufferGeometryLike extends Pick<BufferGeometry, 'attributes' | 'index' | 'boundingBox' | 'boundingSphere'> {
4
+ }
4
5
  export declare function toBufferGeometryLike(geometry: BufferGeometry): [BufferGeometryLike, ArrayBuffer[]];
5
6
  export declare function fromBufferGeometryLike(input: BufferGeometryLike, result?: BufferGeometry<import('three').NormalBufferAttributes>): BufferGeometry;