@octanejs/drei 0.0.1

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.
Files changed (152) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/UPSTREAM.md +92 -0
  4. package/package.json +96 -0
  5. package/src/config.ts +14 -0
  6. package/src/core/AccumulativeShadows.three.tsrx +313 -0
  7. package/src/core/AdaptivePerformance.three.tsrx +49 -0
  8. package/src/core/AsciiRenderer.three.tsrx +61 -0
  9. package/src/core/Bounds.three.tsrx +323 -0
  10. package/src/core/Bvh.three.tsrx +116 -0
  11. package/src/core/CameraControls.three.tsrx +181 -0
  12. package/src/core/CameraShake.three.tsrx +104 -0
  13. package/src/core/Caustics.three.tsrx +107 -0
  14. package/src/core/Center.three.tsrx +145 -0
  15. package/src/core/Clone.three.tsrx +167 -0
  16. package/src/core/Cloud.three.tsrx +314 -0
  17. package/src/core/ComputedAttribute.three.tsrx +27 -0
  18. package/src/core/ContactShadows.three.tsrx +106 -0
  19. package/src/core/CubeTexture.three.tsrx +32 -0
  20. package/src/core/CurveModifier.three.tsrx +37 -0
  21. package/src/core/Decal.three.tsrx +132 -0
  22. package/src/core/Detailed.three.tsrx +28 -0
  23. package/src/core/DetectGPU.three.tsrx +22 -0
  24. package/src/core/Effects.three.tsrx +123 -0
  25. package/src/core/Environment.three.tsrx +220 -0
  26. package/src/core/Example.three.tsrx +56 -0
  27. package/src/core/Fbo.three.tsrx +70 -0
  28. package/src/core/Fbx.three.tsrx +25 -0
  29. package/src/core/Fisheye.three.tsrx +82 -0
  30. package/src/core/GizmoHelper.three.tsrx +115 -0
  31. package/src/core/GizmoViewcube.three.tsrx +82 -0
  32. package/src/core/GizmoViewport.three.tsrx +122 -0
  33. package/src/core/Gltf.three.tsrx +62 -0
  34. package/src/core/GradientTexture.three.tsrx +66 -0
  35. package/src/core/Grid.three.tsrx +170 -0
  36. package/src/core/Helper.three.tsrx +56 -0
  37. package/src/core/Hud.three.tsrx +52 -0
  38. package/src/core/Image.three.tsrx +146 -0
  39. package/src/core/Instances.three.tsrx +332 -0
  40. package/src/core/Ktx2.three.tsrx +59 -0
  41. package/src/core/Lightformer.three.tsrx +75 -0
  42. package/src/core/MarchingCubes.three.tsrx +125 -0
  43. package/src/core/MeshPortalMaterial.three.tsrx +103 -0
  44. package/src/core/MeshReflectorMaterial.three.tsrx +67 -0
  45. package/src/core/MeshRefractionMaterial.three.tsrx +70 -0
  46. package/src/core/MeshTransmissionMaterial.three.tsrx +71 -0
  47. package/src/core/MotionPathControls.three.tsrx +139 -0
  48. package/src/core/MultiMaterial.three.tsrx +32 -0
  49. package/src/core/Outlines.three.tsrx +162 -0
  50. package/src/core/PerformanceMonitor.three.tsrx +144 -0
  51. package/src/core/PointerLockControls.three.tsrx +84 -0
  52. package/src/core/Points.three.tsrx +242 -0
  53. package/src/core/PositionalAudio.three.tsrx +76 -0
  54. package/src/core/Preload.three.tsrx +40 -0
  55. package/src/core/Progress.three.tsrx +47 -0
  56. package/src/core/RenderCubeTexture.three.tsrx +111 -0
  57. package/src/core/RenderTexture.three.tsrx +102 -0
  58. package/src/core/Resize.three.tsrx +59 -0
  59. package/src/core/RoundedBox.three.tsrx +106 -0
  60. package/src/core/Sampler.three.tsrx +116 -0
  61. package/src/core/ScreenSizer.three.tsrx +43 -0
  62. package/src/core/ScreenSpace.three.tsrx +21 -0
  63. package/src/core/Segments.three.tsrx +119 -0
  64. package/src/core/Sky.three.tsrx +63 -0
  65. package/src/core/Sparkles.three.tsrx +145 -0
  66. package/src/core/Splat.three.tsrx +52 -0
  67. package/src/core/SpotLight.three.tsrx +350 -0
  68. package/src/core/SpriteAnimator.three.tsrx +338 -0
  69. package/src/core/Stage.three.tsrx +112 -0
  70. package/src/core/Stars.three.tsrx +103 -0
  71. package/src/core/Stats.three.tsrx +35 -0
  72. package/src/core/StatsGl.three.tsrx +60 -0
  73. package/src/core/Svg.three.tsrx +82 -0
  74. package/src/core/Text.three.tsrx +96 -0
  75. package/src/core/Text3D.three.tsrx +90 -0
  76. package/src/core/Texture.three.tsrx +72 -0
  77. package/src/core/Trail.three.tsrx +167 -0
  78. package/src/core/TrailTexture.three.tsrx +171 -0
  79. package/src/core/TransformControls.three.tsrx +155 -0
  80. package/src/core/VideoTexture.three.tsrx +116 -0
  81. package/src/core/Wireframe.three.tsrx +92 -0
  82. package/src/core/basic-controls.three.tsrx +353 -0
  83. package/src/core/calculateScaleFactor.ts +42 -0
  84. package/src/core/cameras.three.tsrx +230 -0
  85. package/src/core/catalog-resource.ts +12 -0
  86. package/src/core/catalog-textures.three.tsrx +105 -0
  87. package/src/core/compiler-slot.ts +9 -0
  88. package/src/core/effects-utils.ts +8 -0
  89. package/src/core/environment-loader.ts +87 -0
  90. package/src/core/font-resource.ts +31 -0
  91. package/src/core/gltf-loader.ts +33 -0
  92. package/src/core/gradient-types.ts +4 -0
  93. package/src/core/index.ts +295 -0
  94. package/src/core/lines.three.tsrx +329 -0
  95. package/src/core/meshBounds.ts +26 -0
  96. package/src/core/motion-materials.three.tsrx +93 -0
  97. package/src/core/octane-children.ts +18 -0
  98. package/src/core/octane-element.ts +16 -0
  99. package/src/core/resource.ts +29 -0
  100. package/src/core/scene-motion.three.tsrx +183 -0
  101. package/src/core/shaderMaterial.ts +50 -0
  102. package/src/core/shadows.three.tsrx +164 -0
  103. package/src/core/shapes.three.tsrx +170 -0
  104. package/src/core/simple-materials.three.tsrx +124 -0
  105. package/src/core/softShadows.three.tsrx +151 -0
  106. package/src/core/splat-resource.ts +598 -0
  107. package/src/core/useAnimations.three.tsrx +57 -0
  108. package/src/core/useAspect.three.tsrx +10 -0
  109. package/src/core/useBoxProjectedEnv.three.tsrx +113 -0
  110. package/src/core/useCamera.three.tsrx +26 -0
  111. package/src/core/useContextBridge.three.tsrx +25 -0
  112. package/src/core/useDepthBuffer.three.tsrx +35 -0
  113. package/src/core/useEnvironment.three.tsrx +81 -0
  114. package/src/core/useFont.three.tsrx +12 -0
  115. package/src/core/useIntersect.three.tsrx +38 -0
  116. package/src/core/useSpriteLoader.three.tsrx +249 -0
  117. package/src/core/video-texture-resource.ts +14 -0
  118. package/src/index.ts +2 -0
  119. package/src/materials/BlurPass.ts +94 -0
  120. package/src/materials/CausticsMaterials.ts +197 -0
  121. package/src/materials/ConvolutionMaterial.ts +65 -0
  122. package/src/materials/MeshReflectorMaterial.ts +180 -0
  123. package/src/materials/MeshRefractionMaterial.ts +131 -0
  124. package/src/materials/MeshTransmissionMaterial.ts +182 -0
  125. package/src/materials/PortalMaterial.ts +38 -0
  126. package/src/materials/WireframeMaterial.ts +241 -0
  127. package/src/materials/makeSDFGenerator.ts +155 -0
  128. package/src/troika-three-text.d.ts +19 -0
  129. package/src/web/CycleRaycast.three.tsrx +81 -0
  130. package/src/web/DragControls.three.tsrx +82 -0
  131. package/src/web/FaceControls.three.tsrx +178 -0
  132. package/src/web/FaceLandmarker.three.tsrx +48 -0
  133. package/src/web/Facemesh.three.tsrx +464 -0
  134. package/src/web/Html.three.tsrx +390 -0
  135. package/src/web/KeyboardControls.three.tsrx +98 -0
  136. package/src/web/Loader.tsrx +61 -0
  137. package/src/web/PresentationControls.three.tsrx +63 -0
  138. package/src/web/ScrollControls.three.tsrx +120 -0
  139. package/src/web/Select.three.tsrx +155 -0
  140. package/src/web/View.three.tsrx +46 -0
  141. package/src/web/face-landmarker-resource.ts +18 -0
  142. package/src/web/facemesh-data.ts +54 -0
  143. package/src/web/index.ts +41 -0
  144. package/src/web/keyboard-controls-types.ts +33 -0
  145. package/src/web/media-textures.three.tsrx +50 -0
  146. package/src/web/pivotControls/annotation.tsrx +17 -0
  147. package/src/web/pivotControls/context.ts +38 -0
  148. package/src/web/pivotControls/index.three.tsrx +877 -0
  149. package/src/web/scroll-html-root.tsrx +27 -0
  150. package/src/web/useCursor.three.tsrx +19 -0
  151. package/src/web/useGesture.ts +27 -0
  152. package/status.json +14 -0
@@ -0,0 +1,353 @@
1
+ /** @jsxImportSource @octanejs/three/intrinsics */
2
+ import {
3
+ type RootState,
4
+ type ThreeElement,
5
+ type ThreeRef,
6
+ useFrame,
7
+ useThree,
8
+ } from '@octanejs/three';
9
+ import { useEffect, useMemo, useState } from '@octanejs/three/renderer';
10
+ import type * as THREE from 'three';
11
+ import {
12
+ ArcballControls as ArcballControlsImpl,
13
+ DeviceOrientationControls as DeviceOrientationControlsImpl,
14
+ FirstPersonControls as FirstPersonControlsImpl,
15
+ FlyControls as FlyControlsImpl,
16
+ MapControls as MapControlsImpl,
17
+ OrbitControls as OrbitControlsImpl,
18
+ TrackballControls as TrackballControlsImpl,
19
+ } from 'three-stdlib';
20
+
21
+ type ControlCallbacks = {
22
+ onChange?: (event?: THREE.Event) => void;
23
+ onStart?: (event?: THREE.Event) => void;
24
+ onEnd?: (event?: THREE.Event) => void;
25
+ };
26
+
27
+ type SharedControlProps =
28
+ ControlCallbacks & {
29
+ camera?: THREE.Camera;
30
+ domElement?: HTMLElement;
31
+ makeDefault?: boolean;
32
+ regress?: boolean;
33
+ };
34
+
35
+ function controlElement(state: RootState, domElement?: HTMLElement): HTMLElement {
36
+ return (domElement || state.events.connected || state.gl.domElement) as HTMLElement;
37
+ }
38
+
39
+ function installDefaultControl(
40
+ makeDefault: boolean | undefined,
41
+ controls: unknown,
42
+ get: () => any,
43
+ set: (value: any) => void,
44
+ ) {
45
+ if (!makeDefault) return;
46
+ const old = get().controls;
47
+ set({ controls });
48
+ return () => set({ controls: old });
49
+ }
50
+
51
+ export type OrbitControlsChangeEvent =
52
+ Parameters<Parameters<OrbitControlsImpl['addEventListener']>[1]>[0];
53
+ export type OrbitControlsProps =
54
+ Omit<ThreeElement<typeof OrbitControlsImpl>, 'ref' | 'args'> & SharedControlProps & {
55
+ enableDamping?: boolean;
56
+ keyEvents?: boolean | HTMLElement;
57
+ target?: THREE.Vector3 | [number, number, number];
58
+ };
59
+
60
+ export function OrbitControls({
61
+ makeDefault,
62
+ camera,
63
+ regress,
64
+ domElement,
65
+ enableDamping = true,
66
+ keyEvents = false,
67
+ onChange,
68
+ onStart,
69
+ onEnd,
70
+ ref,
71
+ ...rest
72
+ }: OrbitControlsProps & { ref?: ThreeRef<OrbitControlsImpl> }) @{
73
+ const state = useThree();
74
+ const explicitCamera = camera || state.camera;
75
+ const explicitElement = controlElement(state, domElement);
76
+ const controls = useMemo(() => new OrbitControlsImpl(explicitCamera as any), [explicitCamera]);
77
+ useFrame(() => {
78
+ if (controls.enabled) controls.update();
79
+ }, -1);
80
+ useEffect(() => {
81
+ if (keyEvents) controls.connect(keyEvents === true ? explicitElement : keyEvents);
82
+ controls.connect(explicitElement);
83
+ return () => void controls.dispose();
84
+ }, [keyEvents, explicitElement, regress, controls, state.invalidate]);
85
+ useEffect(() => {
86
+ const change = (event: any) => {
87
+ state.invalidate();
88
+ if (regress) state.performance.regress();
89
+ onChange?.(event);
90
+ };
91
+ const start = (event: any) => onStart?.(event);
92
+ const end = (event: any) => onEnd?.(event);
93
+ controls.addEventListener('change', change);
94
+ controls.addEventListener('start', start);
95
+ controls.addEventListener('end', end);
96
+ return () => {
97
+ controls.removeEventListener('start', start);
98
+ controls.removeEventListener('end', end);
99
+ controls.removeEventListener('change', change);
100
+ };
101
+ }, [onChange, onStart, onEnd, controls, state.invalidate, state.setEvents]);
102
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
103
+ makeDefault,
104
+ controls,
105
+ ]);
106
+ <primitive ref={ref as any} object={controls} enableDamping={enableDamping} {...rest as any} />
107
+ }
108
+
109
+ export type MapControlsProps =
110
+ Omit<ThreeElement<typeof MapControlsImpl>, 'ref' | 'args'> & SharedControlProps & {
111
+ target?: THREE.Vector3 | [number, number, number];
112
+ };
113
+
114
+ export function MapControls({
115
+ domElement,
116
+ camera,
117
+ makeDefault,
118
+ onChange,
119
+ onStart,
120
+ onEnd,
121
+ ref,
122
+ enableDamping = true,
123
+ ...rest
124
+ }: MapControlsProps & { ref?: ThreeRef<MapControlsImpl> }) @{
125
+ const state = useThree();
126
+ const explicitCamera = camera || state.camera;
127
+ const explicitElement = controlElement(state, domElement);
128
+ const controls = useMemo(() => new MapControlsImpl(explicitCamera as any), [explicitCamera]);
129
+ useEffect(() => {
130
+ controls.connect(explicitElement);
131
+ const change = (event: any) => {
132
+ state.invalidate();
133
+ onChange?.(event);
134
+ };
135
+ controls.addEventListener('change', change);
136
+ if (onStart) controls.addEventListener('start', onStart as any);
137
+ if (onEnd) controls.addEventListener('end', onEnd as any);
138
+ return () => {
139
+ controls.dispose();
140
+ controls.removeEventListener('change', change);
141
+ if (onStart) controls.removeEventListener('start', onStart as any);
142
+ if (onEnd) controls.removeEventListener('end', onEnd as any);
143
+ };
144
+ }, [onChange, onStart, onEnd, controls, state.invalidate, explicitElement]);
145
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
146
+ makeDefault,
147
+ controls,
148
+ ]);
149
+ useFrame(() => controls.update(), -1);
150
+ <primitive ref={ref as any} object={controls} enableDamping={enableDamping} {...rest as any} />
151
+ }
152
+
153
+ export type TrackballControlsProps =
154
+ Omit<ThreeElement<typeof TrackballControlsImpl>, 'ref' | 'args'> & SharedControlProps & {
155
+ target?: THREE.Vector3 | [number, number, number];
156
+ };
157
+
158
+ export function TrackballControls({
159
+ makeDefault,
160
+ camera,
161
+ domElement,
162
+ regress,
163
+ onChange,
164
+ onStart,
165
+ onEnd,
166
+ ref,
167
+ ...rest
168
+ }: TrackballControlsProps & { ref?: ThreeRef<TrackballControlsImpl> }) @{
169
+ const state = useThree();
170
+ const explicitCamera = camera || state.camera;
171
+ const explicitElement = controlElement(state, domElement);
172
+ const controls = useMemo(() => new TrackballControlsImpl(explicitCamera as any), [
173
+ explicitCamera,
174
+ ]);
175
+ useFrame(() => {
176
+ if (controls.enabled) controls.update();
177
+ }, -1);
178
+ useEffect(() => {
179
+ controls.connect(explicitElement);
180
+ return () => void controls.dispose();
181
+ }, [explicitElement, regress, controls, state.invalidate]);
182
+ useEffect(() => {
183
+ const change = (event: any) => {
184
+ state.invalidate();
185
+ if (regress) state.performance.regress();
186
+ onChange?.(event);
187
+ };
188
+ controls.addEventListener('change', change);
189
+ if (onStart) controls.addEventListener('start', onStart as any);
190
+ if (onEnd) controls.addEventListener('end', onEnd as any);
191
+ return () => {
192
+ if (onStart) controls.removeEventListener('start', onStart as any);
193
+ if (onEnd) controls.removeEventListener('end', onEnd as any);
194
+ controls.removeEventListener('change', change);
195
+ };
196
+ }, [onChange, onStart, onEnd, controls, state.invalidate]);
197
+ useEffect(() => controls.handleResize(), [state.viewport]);
198
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
199
+ makeDefault,
200
+ controls,
201
+ ]);
202
+ <primitive ref={ref as any} object={controls} {...rest as any} />
203
+ }
204
+
205
+ export type ArcballControlsProps =
206
+ Omit<ThreeElement<typeof ArcballControlsImpl>, 'ref' | 'args'> & SharedControlProps & {
207
+ target?: THREE.Vector3 | [number, number, number];
208
+ };
209
+
210
+ export function ArcballControls({
211
+ camera,
212
+ makeDefault,
213
+ regress,
214
+ domElement,
215
+ onChange,
216
+ onStart,
217
+ onEnd,
218
+ ref,
219
+ ...rest
220
+ }: ArcballControlsProps & { ref?: ThreeRef<ArcballControlsImpl> }) @{
221
+ const state = useThree();
222
+ const explicitCamera = camera || state.camera;
223
+ const explicitElement = controlElement(state, domElement);
224
+ const controls = useMemo(() => new ArcballControlsImpl(explicitCamera as any), [explicitCamera]);
225
+ useFrame(() => {
226
+ if (controls.enabled) controls.update();
227
+ }, -1);
228
+ useEffect(() => {
229
+ controls.connect(explicitElement);
230
+ return () => void controls.dispose();
231
+ }, [explicitElement, regress, controls, state.invalidate]);
232
+ useEffect(() => {
233
+ const change = (event: any) => {
234
+ state.invalidate();
235
+ if (regress) state.performance.regress();
236
+ onChange?.(event);
237
+ };
238
+ controls.addEventListener('change', change);
239
+ if (onStart) controls.addEventListener('start', onStart as any);
240
+ if (onEnd) controls.addEventListener('end', onEnd as any);
241
+ return () => {
242
+ controls.removeEventListener('change', change);
243
+ if (onStart) controls.removeEventListener('start', onStart as any);
244
+ if (onEnd) controls.removeEventListener('end', onEnd as any);
245
+ };
246
+ }, [onChange, onStart, onEnd]);
247
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
248
+ makeDefault,
249
+ controls,
250
+ ]);
251
+ <primitive ref={ref as any} object={controls} {...rest as any} />
252
+ }
253
+
254
+ export type FlyControlsProps =
255
+ Omit<ThreeElement<typeof FlyControlsImpl>, 'ref' | 'args'> & {
256
+ onChange?: (event?: THREE.Event) => void;
257
+ domElement?: HTMLElement;
258
+ makeDefault?: boolean;
259
+ };
260
+
261
+ export function FlyControls({
262
+ domElement,
263
+ onChange,
264
+ makeDefault,
265
+ ref,
266
+ ...rest
267
+ }: FlyControlsProps & { ref?: ThreeRef<FlyControlsImpl> }) @{
268
+ const state = useThree();
269
+ const explicitElement = controlElement(state, domElement);
270
+ const controls = useMemo(() => new FlyControlsImpl(state.camera as any), [state.camera]);
271
+ useEffect(() => {
272
+ controls.connect(explicitElement);
273
+ return () => void controls.dispose();
274
+ }, [explicitElement, controls, state.invalidate]);
275
+ useEffect(() => {
276
+ const change = (event: any) => {
277
+ state.invalidate();
278
+ onChange?.(event);
279
+ };
280
+ controls.addEventListener?.('change', change);
281
+ return () => controls.removeEventListener?.('change', change);
282
+ }, [onChange, state.invalidate]);
283
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
284
+ makeDefault,
285
+ controls,
286
+ ]);
287
+ useFrame((_, delta) => controls.update(delta));
288
+ <primitive ref={ref as any} object={controls} {...rest as any} />
289
+ }
290
+
291
+ export type FirstPersonControlsProps =
292
+ Omit<ThreeElement<typeof FirstPersonControlsImpl>, 'ref' | 'args'> & {
293
+ domElement?: HTMLElement;
294
+ makeDefault?: boolean;
295
+ };
296
+
297
+ export function FirstPersonControls({
298
+ domElement,
299
+ makeDefault,
300
+ ref,
301
+ ...props
302
+ }: FirstPersonControlsProps & { ref?: ThreeRef<FirstPersonControlsImpl> }) @{
303
+ const state = useThree();
304
+ const explicitElement = controlElement(state, domElement);
305
+ const [controls] = useState(
306
+ () => new FirstPersonControlsImpl(state.camera as any, explicitElement),
307
+ );
308
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
309
+ makeDefault,
310
+ controls,
311
+ ]);
312
+ useFrame((_, delta) => controls.update(delta), -1);
313
+ <primitive ref={ref as any} object={controls} {...props as any} />
314
+ }
315
+
316
+ export type DeviceOrientationControlsProps =
317
+ Omit<ThreeElement<typeof DeviceOrientationControlsImpl>, 'ref' | 'args'> & {
318
+ camera?: THREE.Camera;
319
+ onChange?: (event?: THREE.Event) => void;
320
+ makeDefault?: boolean;
321
+ };
322
+
323
+ export function DeviceOrientationControls({
324
+ camera,
325
+ onChange,
326
+ makeDefault,
327
+ ref,
328
+ ...rest
329
+ }: DeviceOrientationControlsProps & { ref?: ThreeRef<DeviceOrientationControlsImpl> }) @{
330
+ const state = useThree();
331
+ const explicitCamera = camera || state.camera;
332
+ const controls = useMemo(() => new DeviceOrientationControlsImpl(explicitCamera as any), [
333
+ explicitCamera,
334
+ ]);
335
+ useEffect(() => {
336
+ const change = (event: any) => {
337
+ state.invalidate();
338
+ onChange?.(event);
339
+ };
340
+ controls.addEventListener?.('change', change);
341
+ return () => controls.removeEventListener?.('change', change);
342
+ }, [onChange, controls, state.invalidate]);
343
+ useFrame(() => controls.update(), -1);
344
+ useEffect(() => {
345
+ controls.connect();
346
+ return () => controls.dispose();
347
+ }, [controls]);
348
+ useEffect(() => installDefaultControl(makeDefault, controls, state.get, state.set), [
349
+ makeDefault,
350
+ controls,
351
+ ]);
352
+ <primitive ref={ref as any} object={controls} {...rest as any} />
353
+ }
@@ -0,0 +1,42 @@
1
+ import type { Size } from '@octanejs/three';
2
+ import * as THREE from 'three';
3
+
4
+ const tV0 = /* @__PURE__ */ new THREE.Vector3();
5
+ const tV1 = /* @__PURE__ */ new THREE.Vector3();
6
+ const tV2 = /* @__PURE__ */ new THREE.Vector3();
7
+
8
+ const getPoint2 = (point3: THREE.Vector3, camera: THREE.Camera, size: Size) => {
9
+ const widthHalf = size.width / 2;
10
+ const heightHalf = size.height / 2;
11
+ camera.updateMatrixWorld(false);
12
+ const vector = point3.project(camera);
13
+ vector.x = vector.x * widthHalf + widthHalf;
14
+ vector.y = -(vector.y * heightHalf) + heightHalf;
15
+ return vector;
16
+ };
17
+
18
+ const getPoint3 = (point2: THREE.Vector3, camera: THREE.Camera, size: Size, zValue: number = 1) => {
19
+ const vector = tV0.set(
20
+ (point2.x / size.width) * 2 - 1,
21
+ -(point2.y / size.height) * 2 + 1,
22
+ zValue,
23
+ );
24
+ vector.unproject(camera);
25
+ return vector;
26
+ };
27
+
28
+ export const calculateScaleFactor = (
29
+ point3: THREE.Vector3,
30
+ radiusPx: number,
31
+ camera: THREE.Camera,
32
+ size: Size,
33
+ ) => {
34
+ const point2 = getPoint2(tV2.copy(point3), camera, size);
35
+ let scale = 0;
36
+ for (let i = 0; i < 2; ++i) {
37
+ const point2off = tV1.copy(point2).setComponent(i, point2.getComponent(i) + radiusPx);
38
+ const point3off = getPoint3(point2off, camera, size, point2off.z);
39
+ scale = Math.max(scale, point3.distanceTo(point3off));
40
+ }
41
+ return scale;
42
+ };
@@ -0,0 +1,230 @@
1
+ /** @jsxImportSource @octanejs/three/intrinsics */
2
+ import { type ThreeElements, type ThreeRef, useFrame, useThree } from '@octanejs/three';
3
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from '@octanejs/three/renderer';
4
+ import * as THREE from 'three';
5
+ import { slotDefault } from './compiler-slot.js';
6
+ import { useFBO } from './Fbo.three.tsrx';
7
+ import {
8
+ isRenderFunction,
9
+ resolveRenderChildren,
10
+ type RenderChildren,
11
+ } from './octane-children.js';
12
+
13
+ function assignRef<T>(ref: ThreeRef<T> | undefined, value: T | null): void {
14
+ if (Array.isArray(ref)) for (const item of ref) assignRef(item, value);
15
+ else if (typeof ref === 'function') ref(value);
16
+ else if (ref && 'current' in ref) ref.current = value;
17
+ }
18
+
19
+ type CameraChildren = RenderChildren<THREE.Texture>;
20
+
21
+ export type PerspectiveCameraProps =
22
+ Omit<ThreeElements['perspectiveCamera'], 'ref' | 'children'> & {
23
+ makeDefault?: boolean;
24
+ manual?: boolean;
25
+ children?: CameraChildren;
26
+ frames?: number;
27
+ resolution?: number;
28
+ envMap?: THREE.Texture;
29
+ };
30
+
31
+ export function PerspectiveCamera({
32
+ envMap,
33
+ resolution = 256,
34
+ frames = Infinity,
35
+ makeDefault,
36
+ children,
37
+ ref,
38
+ ...props
39
+ }: PerspectiveCameraProps & { ref?: ThreeRef<THREE.PerspectiveCamera> }) @{
40
+ const set = useThree((state) => state.set);
41
+ const camera = useThree((state) => state.camera);
42
+ const size = useThree((state) => state.size);
43
+ const cameraRef = useRef<THREE.PerspectiveCamera | null>(null);
44
+ const groupRef = useRef<THREE.Group | null>(null);
45
+ const fbo = useFBO(resolution);
46
+ const mergedRef = useMemo(
47
+ () => (value: THREE.PerspectiveCamera | null) => {
48
+ cameraRef.current = value;
49
+ assignRef(ref, value);
50
+ },
51
+ [ref],
52
+ );
53
+ useLayoutEffect(() => {
54
+ if (!props.manual && cameraRef.current) cameraRef.current.aspect = size.width / size.height;
55
+ }, [size, props]);
56
+ useLayoutEffect(() => cameraRef.current?.updateProjectionMatrix());
57
+ let count = 0;
58
+ let oldEnvironment: THREE.Color | THREE.Texture | null = null;
59
+ const functional = isRenderFunction(children);
60
+ useFrame((state) => {
61
+ if (
62
+ functional && cameraRef.current && groupRef.current && (frames === Infinity || count < frames)
63
+ ) {
64
+ groupRef.current.visible = false;
65
+ state.gl.setRenderTarget?.(fbo);
66
+ oldEnvironment = state.scene.background;
67
+ if (envMap) state.scene.background = envMap;
68
+ state.gl.render(state.scene, cameraRef.current);
69
+ state.scene.background = oldEnvironment;
70
+ state.gl.setRenderTarget?.(null);
71
+ groupRef.current.visible = true;
72
+ count++;
73
+ }
74
+ });
75
+ useLayoutEffect(() => {
76
+ if (makeDefault && cameraRef.current) {
77
+ const oldCamera = camera;
78
+ set(() => ({ camera: cameraRef.current! }));
79
+ return () => set(() => ({ camera: oldCamera }));
80
+ }
81
+ }, [cameraRef, makeDefault, set]);
82
+ <>
83
+ <perspectiveCamera ref={mergedRef} {...props as any}>
84
+ {!functional && children}
85
+ </perspectiveCamera>
86
+ <group ref={groupRef}>{functional && children(fbo.texture)}</group>
87
+ </>
88
+ }
89
+
90
+ export type OrthographicCameraProps =
91
+ Omit<ThreeElements['orthographicCamera'], 'ref' | 'children'> & {
92
+ makeDefault?: boolean;
93
+ manual?: boolean;
94
+ children?: CameraChildren;
95
+ frames?: number;
96
+ resolution?: number;
97
+ envMap?: THREE.Texture;
98
+ };
99
+
100
+ export function OrthographicCamera({
101
+ envMap,
102
+ resolution = 256,
103
+ frames = Infinity,
104
+ children,
105
+ makeDefault,
106
+ ref,
107
+ ...props
108
+ }: OrthographicCameraProps & { ref?: ThreeRef<THREE.OrthographicCamera> }) @{
109
+ const set = useThree((state) => state.set);
110
+ const camera = useThree((state) => state.camera);
111
+ const size = useThree((state) => state.size);
112
+ const cameraRef = useRef<THREE.OrthographicCamera | null>(null);
113
+ const groupRef = useRef<THREE.Group | null>(null);
114
+ const fbo = useFBO(resolution);
115
+ const mergedRef = useMemo(
116
+ () => (value: THREE.OrthographicCamera | null) => {
117
+ cameraRef.current = value;
118
+ assignRef(ref, value);
119
+ },
120
+ [ref],
121
+ );
122
+ useLayoutEffect(() => {
123
+ if (!props.manual) cameraRef.current?.updateProjectionMatrix();
124
+ }, [size, props]);
125
+ useLayoutEffect(() => cameraRef.current?.updateProjectionMatrix());
126
+ useLayoutEffect(() => {
127
+ if (makeDefault && cameraRef.current) {
128
+ const oldCamera = camera;
129
+ set(() => ({ camera: cameraRef.current! }));
130
+ return () => set(() => ({ camera: oldCamera }));
131
+ }
132
+ }, [cameraRef, makeDefault, set]);
133
+ let count = 0;
134
+ let oldEnvironment: THREE.Color | THREE.Texture | null = null;
135
+ const functional = isRenderFunction(children);
136
+ useFrame((state) => {
137
+ if (
138
+ functional && cameraRef.current && groupRef.current && (frames === Infinity || count < frames)
139
+ ) {
140
+ groupRef.current.visible = false;
141
+ state.gl.setRenderTarget?.(fbo);
142
+ oldEnvironment = state.scene.background;
143
+ if (envMap) state.scene.background = envMap;
144
+ state.gl.render(state.scene, cameraRef.current);
145
+ state.scene.background = oldEnvironment;
146
+ state.gl.setRenderTarget?.(null);
147
+ groupRef.current.visible = true;
148
+ count++;
149
+ }
150
+ });
151
+ <>
152
+ <orthographicCamera
153
+ left={size.width / -2}
154
+ right={size.width / 2}
155
+ top={size.height / 2}
156
+ bottom={size.height / -2}
157
+ ref={mergedRef}
158
+ {...props as any}
159
+ >
160
+ {!functional && children}
161
+ </orthographicCamera>
162
+ <group ref={groupRef}>{functional && children(fbo.texture)}</group>
163
+ </>
164
+ }
165
+
166
+ export type CubeCameraOptions = {
167
+ resolution?: number;
168
+ near?: number;
169
+ far?: number;
170
+ envMap?: THREE.Texture;
171
+ fog?: THREE.Fog | THREE.FogExp2;
172
+ };
173
+
174
+ export function useCubeCamera(options: CubeCameraOptions = {}) {
175
+ const { resolution = 256, near = 0.1, far = 1000, envMap, fog } = slotDefault(options, {});
176
+ const gl = useThree((state) => state.gl);
177
+ const scene = useThree((state) => state.scene);
178
+ const fbo = useMemo(() => {
179
+ const value = new THREE.WebGLCubeRenderTarget(resolution);
180
+ value.texture.type = THREE.HalfFloatType;
181
+ return value;
182
+ }, [resolution]);
183
+ useEffect(() => () => fbo.dispose(), [fbo]);
184
+ const camera = useMemo(() => new THREE.CubeCamera(near, far, fbo), [near, far, fbo]);
185
+ let originalFog: THREE.Fog | THREE.FogExp2 | null;
186
+ let originalBackground: THREE.Color | THREE.Texture | null;
187
+ const update = useCallback(() => {
188
+ originalFog = scene.fog;
189
+ originalBackground = scene.background;
190
+ scene.background = envMap || originalBackground;
191
+ scene.fog = fog || originalFog;
192
+ camera.update(gl as unknown as THREE.WebGLRenderer, scene);
193
+ scene.fog = originalFog;
194
+ scene.background = originalBackground;
195
+ }, [gl, scene, camera]);
196
+ return { fbo, camera, update };
197
+ }
198
+
199
+ export type CubeCameraProps =
200
+ Omit<ThreeElements['group'], 'children'> & CubeCameraOptions & {
201
+ children?: CameraChildren;
202
+ frames?: number;
203
+ };
204
+
205
+ export function CubeCamera({
206
+ children,
207
+ frames = Infinity,
208
+ resolution,
209
+ near,
210
+ far,
211
+ envMap,
212
+ fog,
213
+ ...props
214
+ }: CubeCameraProps) @{
215
+ const ref = useRef<THREE.Group | null>(null);
216
+ const { fbo, camera, update } = useCubeCamera({ resolution, near, far, envMap, fog });
217
+ let count = 0;
218
+ useFrame(() => {
219
+ if (ref.current && (frames === Infinity || count < frames)) {
220
+ ref.current.visible = false;
221
+ update();
222
+ ref.current.visible = true;
223
+ count++;
224
+ }
225
+ });
226
+ <group {...props}>
227
+ <primitive object={camera} />
228
+ <group ref={ref}>{resolveRenderChildren(children, fbo.texture)}</group>
229
+ </group>
230
+ }
@@ -0,0 +1,12 @@
1
+ export const MATCAP_LIST_URL = 'https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/matcaps.json';
2
+ export const MATCAP_ROOT =
3
+ 'https://rawcdn.githack.com/emmelleppi/matcaps/9b36ccaaf0a24881a39062d05566c9e92be4aa0d';
4
+ export const NORMAL_ROOT =
5
+ 'https://rawcdn.githack.com/pmndrs/drei-assets/7a3104997e1576f83472829815b00880d88b32fb';
6
+ export const NORMAL_LIST_URL =
7
+ 'https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/normals/normals.json';
8
+
9
+ export async function loadCatalogList(url: string): Promise<Record<string, string>> {
10
+ const response = await fetch(url);
11
+ return response.json() as Promise<Record<string, string>>;
12
+ }