@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.
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/UPSTREAM.md +92 -0
- package/package.json +96 -0
- package/src/config.ts +14 -0
- package/src/core/AccumulativeShadows.three.tsrx +313 -0
- package/src/core/AdaptivePerformance.three.tsrx +49 -0
- package/src/core/AsciiRenderer.three.tsrx +61 -0
- package/src/core/Bounds.three.tsrx +323 -0
- package/src/core/Bvh.three.tsrx +116 -0
- package/src/core/CameraControls.three.tsrx +181 -0
- package/src/core/CameraShake.three.tsrx +104 -0
- package/src/core/Caustics.three.tsrx +107 -0
- package/src/core/Center.three.tsrx +145 -0
- package/src/core/Clone.three.tsrx +167 -0
- package/src/core/Cloud.three.tsrx +314 -0
- package/src/core/ComputedAttribute.three.tsrx +27 -0
- package/src/core/ContactShadows.three.tsrx +106 -0
- package/src/core/CubeTexture.three.tsrx +32 -0
- package/src/core/CurveModifier.three.tsrx +37 -0
- package/src/core/Decal.three.tsrx +132 -0
- package/src/core/Detailed.three.tsrx +28 -0
- package/src/core/DetectGPU.three.tsrx +22 -0
- package/src/core/Effects.three.tsrx +123 -0
- package/src/core/Environment.three.tsrx +220 -0
- package/src/core/Example.three.tsrx +56 -0
- package/src/core/Fbo.three.tsrx +70 -0
- package/src/core/Fbx.three.tsrx +25 -0
- package/src/core/Fisheye.three.tsrx +82 -0
- package/src/core/GizmoHelper.three.tsrx +115 -0
- package/src/core/GizmoViewcube.three.tsrx +82 -0
- package/src/core/GizmoViewport.three.tsrx +122 -0
- package/src/core/Gltf.three.tsrx +62 -0
- package/src/core/GradientTexture.three.tsrx +66 -0
- package/src/core/Grid.three.tsrx +170 -0
- package/src/core/Helper.three.tsrx +56 -0
- package/src/core/Hud.three.tsrx +52 -0
- package/src/core/Image.three.tsrx +146 -0
- package/src/core/Instances.three.tsrx +332 -0
- package/src/core/Ktx2.three.tsrx +59 -0
- package/src/core/Lightformer.three.tsrx +75 -0
- package/src/core/MarchingCubes.three.tsrx +125 -0
- package/src/core/MeshPortalMaterial.three.tsrx +103 -0
- package/src/core/MeshReflectorMaterial.three.tsrx +67 -0
- package/src/core/MeshRefractionMaterial.three.tsrx +70 -0
- package/src/core/MeshTransmissionMaterial.three.tsrx +71 -0
- package/src/core/MotionPathControls.three.tsrx +139 -0
- package/src/core/MultiMaterial.three.tsrx +32 -0
- package/src/core/Outlines.three.tsrx +162 -0
- package/src/core/PerformanceMonitor.three.tsrx +144 -0
- package/src/core/PointerLockControls.three.tsrx +84 -0
- package/src/core/Points.three.tsrx +242 -0
- package/src/core/PositionalAudio.three.tsrx +76 -0
- package/src/core/Preload.three.tsrx +40 -0
- package/src/core/Progress.three.tsrx +47 -0
- package/src/core/RenderCubeTexture.three.tsrx +111 -0
- package/src/core/RenderTexture.three.tsrx +102 -0
- package/src/core/Resize.three.tsrx +59 -0
- package/src/core/RoundedBox.three.tsrx +106 -0
- package/src/core/Sampler.three.tsrx +116 -0
- package/src/core/ScreenSizer.three.tsrx +43 -0
- package/src/core/ScreenSpace.three.tsrx +21 -0
- package/src/core/Segments.three.tsrx +119 -0
- package/src/core/Sky.three.tsrx +63 -0
- package/src/core/Sparkles.three.tsrx +145 -0
- package/src/core/Splat.three.tsrx +52 -0
- package/src/core/SpotLight.three.tsrx +350 -0
- package/src/core/SpriteAnimator.three.tsrx +338 -0
- package/src/core/Stage.three.tsrx +112 -0
- package/src/core/Stars.three.tsrx +103 -0
- package/src/core/Stats.three.tsrx +35 -0
- package/src/core/StatsGl.three.tsrx +60 -0
- package/src/core/Svg.three.tsrx +82 -0
- package/src/core/Text.three.tsrx +96 -0
- package/src/core/Text3D.three.tsrx +90 -0
- package/src/core/Texture.three.tsrx +72 -0
- package/src/core/Trail.three.tsrx +167 -0
- package/src/core/TrailTexture.three.tsrx +171 -0
- package/src/core/TransformControls.three.tsrx +155 -0
- package/src/core/VideoTexture.three.tsrx +116 -0
- package/src/core/Wireframe.three.tsrx +92 -0
- package/src/core/basic-controls.three.tsrx +353 -0
- package/src/core/calculateScaleFactor.ts +42 -0
- package/src/core/cameras.three.tsrx +230 -0
- package/src/core/catalog-resource.ts +12 -0
- package/src/core/catalog-textures.three.tsrx +105 -0
- package/src/core/compiler-slot.ts +9 -0
- package/src/core/effects-utils.ts +8 -0
- package/src/core/environment-loader.ts +87 -0
- package/src/core/font-resource.ts +31 -0
- package/src/core/gltf-loader.ts +33 -0
- package/src/core/gradient-types.ts +4 -0
- package/src/core/index.ts +295 -0
- package/src/core/lines.three.tsrx +329 -0
- package/src/core/meshBounds.ts +26 -0
- package/src/core/motion-materials.three.tsrx +93 -0
- package/src/core/octane-children.ts +18 -0
- package/src/core/octane-element.ts +16 -0
- package/src/core/resource.ts +29 -0
- package/src/core/scene-motion.three.tsrx +183 -0
- package/src/core/shaderMaterial.ts +50 -0
- package/src/core/shadows.three.tsrx +164 -0
- package/src/core/shapes.three.tsrx +170 -0
- package/src/core/simple-materials.three.tsrx +124 -0
- package/src/core/softShadows.three.tsrx +151 -0
- package/src/core/splat-resource.ts +598 -0
- package/src/core/useAnimations.three.tsrx +57 -0
- package/src/core/useAspect.three.tsrx +10 -0
- package/src/core/useBoxProjectedEnv.three.tsrx +113 -0
- package/src/core/useCamera.three.tsrx +26 -0
- package/src/core/useContextBridge.three.tsrx +25 -0
- package/src/core/useDepthBuffer.three.tsrx +35 -0
- package/src/core/useEnvironment.three.tsrx +81 -0
- package/src/core/useFont.three.tsrx +12 -0
- package/src/core/useIntersect.three.tsrx +38 -0
- package/src/core/useSpriteLoader.three.tsrx +249 -0
- package/src/core/video-texture-resource.ts +14 -0
- package/src/index.ts +2 -0
- package/src/materials/BlurPass.ts +94 -0
- package/src/materials/CausticsMaterials.ts +197 -0
- package/src/materials/ConvolutionMaterial.ts +65 -0
- package/src/materials/MeshReflectorMaterial.ts +180 -0
- package/src/materials/MeshRefractionMaterial.ts +131 -0
- package/src/materials/MeshTransmissionMaterial.ts +182 -0
- package/src/materials/PortalMaterial.ts +38 -0
- package/src/materials/WireframeMaterial.ts +241 -0
- package/src/materials/makeSDFGenerator.ts +155 -0
- package/src/troika-three-text.d.ts +19 -0
- package/src/web/CycleRaycast.three.tsrx +81 -0
- package/src/web/DragControls.three.tsrx +82 -0
- package/src/web/FaceControls.three.tsrx +178 -0
- package/src/web/FaceLandmarker.three.tsrx +48 -0
- package/src/web/Facemesh.three.tsrx +464 -0
- package/src/web/Html.three.tsrx +390 -0
- package/src/web/KeyboardControls.three.tsrx +98 -0
- package/src/web/Loader.tsrx +61 -0
- package/src/web/PresentationControls.three.tsrx +63 -0
- package/src/web/ScrollControls.three.tsrx +120 -0
- package/src/web/Select.three.tsrx +155 -0
- package/src/web/View.three.tsrx +46 -0
- package/src/web/face-landmarker-resource.ts +18 -0
- package/src/web/facemesh-data.ts +54 -0
- package/src/web/index.ts +41 -0
- package/src/web/keyboard-controls-types.ts +33 -0
- package/src/web/media-textures.three.tsrx +50 -0
- package/src/web/pivotControls/annotation.tsrx +17 -0
- package/src/web/pivotControls/context.ts +38 -0
- package/src/web/pivotControls/index.three.tsrx +877 -0
- package/src/web/scroll-html-root.tsrx +27 -0
- package/src/web/useCursor.three.tsrx +19 -0
- package/src/web/useGesture.ts +27 -0
- package/status.json +14 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useThree } from '@octanejs/three';
|
|
2
|
+
import { useLayoutEffect } from '@octanejs/three/renderer';
|
|
3
|
+
import {
|
|
4
|
+
Camera,
|
|
5
|
+
CubeCamera,
|
|
6
|
+
Object3D,
|
|
7
|
+
Scene,
|
|
8
|
+
type WebGLRenderer,
|
|
9
|
+
WebGLCubeRenderTarget,
|
|
10
|
+
} from 'three';
|
|
11
|
+
|
|
12
|
+
export type PreloadProps = {
|
|
13
|
+
all?: boolean;
|
|
14
|
+
scene?: Object3D;
|
|
15
|
+
camera?: Camera;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function Preload({ all, scene, camera }: PreloadProps) @{
|
|
19
|
+
const renderer = useThree(({ gl }) => gl);
|
|
20
|
+
const defaultCamera = useThree(({ camera: value }) => value);
|
|
21
|
+
const defaultScene = useThree(({ scene: value }) => value);
|
|
22
|
+
useLayoutEffect(() => {
|
|
23
|
+
const invisible: Object3D[] = [];
|
|
24
|
+
if (all) {
|
|
25
|
+
(scene || defaultScene).traverse((object) => {
|
|
26
|
+
if (object.visible === false) {
|
|
27
|
+
invisible.push(object);
|
|
28
|
+
object.visible = true;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
renderer.compile(scene || defaultScene, camera || defaultCamera);
|
|
33
|
+
const target = new WebGLCubeRenderTarget(128);
|
|
34
|
+
const cubeCamera = new CubeCamera(0.01, 100000, target);
|
|
35
|
+
cubeCamera.update(renderer as unknown as WebGLRenderer, (scene || defaultScene) as Scene);
|
|
36
|
+
target.dispose();
|
|
37
|
+
invisible.forEach((object) => (object.visible = false));
|
|
38
|
+
}, []);
|
|
39
|
+
null;
|
|
40
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { create } from '@octanejs/zustand/universal';
|
|
3
|
+
import { DefaultLoadingManager } from 'three';
|
|
4
|
+
import { resolveRenderChildren, type RenderChildren } from './octane-children.js';
|
|
5
|
+
|
|
6
|
+
interface Data {
|
|
7
|
+
errors: string[];
|
|
8
|
+
active: boolean;
|
|
9
|
+
progress: number;
|
|
10
|
+
item: string;
|
|
11
|
+
loaded: number;
|
|
12
|
+
total: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let saveLastTotalLoaded = 0;
|
|
16
|
+
|
|
17
|
+
export const useProgress = /* @__PURE__ */ create<Data>((set) => {
|
|
18
|
+
DefaultLoadingManager.onStart = (item, loaded, total) => {
|
|
19
|
+
set({
|
|
20
|
+
active: true,
|
|
21
|
+
item,
|
|
22
|
+
loaded,
|
|
23
|
+
total,
|
|
24
|
+
progress: ((loaded - saveLastTotalLoaded) / (total - saveLastTotalLoaded)) * 100,
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
DefaultLoadingManager.onLoad = () => set({ active: false });
|
|
28
|
+
DefaultLoadingManager.onError = (item) => set((state) => ({ errors: [...state.errors, item] }));
|
|
29
|
+
DefaultLoadingManager.onProgress = (item, loaded, total) => {
|
|
30
|
+
if (loaded === total) saveLastTotalLoaded = total;
|
|
31
|
+
set({
|
|
32
|
+
active: true,
|
|
33
|
+
item,
|
|
34
|
+
loaded,
|
|
35
|
+
total,
|
|
36
|
+
progress: ((loaded - saveLastTotalLoaded) / (total - saveLastTotalLoaded)) * 100 || 100,
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
return { errors: [], active: false, progress: 0, item: '', loaded: 0, total: 0 };
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export function Progress({ children }: { children?: RenderChildren<Data> }) @{
|
|
43
|
+
const result = useProgress();
|
|
44
|
+
<>
|
|
45
|
+
{resolveRenderChildren(children, result)}
|
|
46
|
+
</>
|
|
47
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { createPortal, type ComputeFunction, type ThreeElements, type ThreeRef, useFrame, useThree } from '@octanejs/three';
|
|
3
|
+
import { useEffect, useImperativeHandle, useMemo, useRef, useState, type RefObject } from '@octanejs/three/renderer';
|
|
4
|
+
import type { OctaneNode } from 'octane';
|
|
5
|
+
import * as THREE from 'three';
|
|
6
|
+
|
|
7
|
+
export type RenderCubeTextureProps = Omit<ThreeElements['texture'], 'ref' | 'args' | 'rotation'> & {
|
|
8
|
+
stencilBuffer?: boolean;
|
|
9
|
+
depthBuffer?: boolean;
|
|
10
|
+
generateMipmaps?: boolean;
|
|
11
|
+
renderPriority?: number;
|
|
12
|
+
eventPriority?: number;
|
|
13
|
+
frames?: number;
|
|
14
|
+
compute?: ComputeFunction;
|
|
15
|
+
flip?: boolean;
|
|
16
|
+
resolution?: number;
|
|
17
|
+
children: OctaneNode;
|
|
18
|
+
near?: number;
|
|
19
|
+
far?: number;
|
|
20
|
+
position?: ThreeElements['cubeCamera']['position'];
|
|
21
|
+
rotation?: ThreeElements['cubeCamera']['rotation'];
|
|
22
|
+
scale?: ThreeElements['cubeCamera']['scale'];
|
|
23
|
+
quaternion?: ThreeElements['cubeCamera']['quaternion'];
|
|
24
|
+
matrix?: ThreeElements['cubeCamera']['matrix'];
|
|
25
|
+
matrixAutoUpdate?: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type RenderCubeTextureComponentProps = Omit<RenderCubeTextureProps, 'children'> & { children?: OctaneNode };
|
|
29
|
+
|
|
30
|
+
export type RenderCubeTextureApi = {
|
|
31
|
+
scene: THREE.Scene;
|
|
32
|
+
fbo: THREE.WebGLCubeRenderTarget;
|
|
33
|
+
camera: THREE.CubeCamera;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function CubeContainer({ frames, renderPriority, children, camera }: {
|
|
37
|
+
frames: number;
|
|
38
|
+
renderPriority: number;
|
|
39
|
+
children?: OctaneNode;
|
|
40
|
+
camera: RefObject<THREE.CubeCamera>;
|
|
41
|
+
}) @{
|
|
42
|
+
let count = 0;
|
|
43
|
+
useFrame((state) => {
|
|
44
|
+
if (frames === Infinity || count < frames) {
|
|
45
|
+
camera.current?.update(state.gl as any, state.scene);
|
|
46
|
+
count++;
|
|
47
|
+
}
|
|
48
|
+
}, renderPriority);
|
|
49
|
+
<>{children}</>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function RenderCubeTexture({
|
|
53
|
+
children,
|
|
54
|
+
compute,
|
|
55
|
+
renderPriority = -1,
|
|
56
|
+
eventPriority = 0,
|
|
57
|
+
frames = Infinity,
|
|
58
|
+
stencilBuffer = false,
|
|
59
|
+
depthBuffer = true,
|
|
60
|
+
generateMipmaps = false,
|
|
61
|
+
resolution = 896,
|
|
62
|
+
near = 0.1,
|
|
63
|
+
far = 1000,
|
|
64
|
+
flip = false,
|
|
65
|
+
position,
|
|
66
|
+
rotation,
|
|
67
|
+
scale,
|
|
68
|
+
quaternion,
|
|
69
|
+
matrix,
|
|
70
|
+
matrixAutoUpdate,
|
|
71
|
+
ref,
|
|
72
|
+
...props
|
|
73
|
+
}: RenderCubeTextureComponentProps & { ref?: ThreeRef<RenderCubeTextureApi> }) @{
|
|
74
|
+
const { size, viewport } = useThree();
|
|
75
|
+
const camera = useRef<THREE.CubeCamera | null>(null);
|
|
76
|
+
const fbo = useMemo(() => {
|
|
77
|
+
const target = new THREE.WebGLCubeRenderTarget(
|
|
78
|
+
Math.max((resolution || size.width) * viewport.dpr, (resolution || size.height) * viewport.dpr),
|
|
79
|
+
{ stencilBuffer, depthBuffer, generateMipmaps },
|
|
80
|
+
);
|
|
81
|
+
target.texture.isRenderTargetTexture = !flip;
|
|
82
|
+
target.texture.flipY = true;
|
|
83
|
+
target.texture.type = THREE.HalfFloatType;
|
|
84
|
+
return target;
|
|
85
|
+
}, [resolution, flip]);
|
|
86
|
+
useEffect(() => () => fbo.dispose(), [fbo]);
|
|
87
|
+
const [virtualScene] = useState(() => new THREE.Scene());
|
|
88
|
+
const primitiveProps = props as any;
|
|
89
|
+
useImperativeHandle((ref ?? null) as any, () => ({ scene: virtualScene, fbo, camera: camera.current! }), [fbo]);
|
|
90
|
+
<>
|
|
91
|
+
{createPortal(
|
|
92
|
+
<CubeContainer renderPriority={renderPriority} frames={frames} camera={camera as RefObject<THREE.CubeCamera>}>
|
|
93
|
+
{children}
|
|
94
|
+
<group onPointerOver={() => null} />
|
|
95
|
+
</CubeContainer>,
|
|
96
|
+
virtualScene,
|
|
97
|
+
{ events: { compute, priority: eventPriority } },
|
|
98
|
+
)}
|
|
99
|
+
<primitive object={fbo.texture} {...primitiveProps} />
|
|
100
|
+
<cubeCamera
|
|
101
|
+
ref={camera}
|
|
102
|
+
args={[near, far, fbo]}
|
|
103
|
+
position={position}
|
|
104
|
+
rotation={rotation}
|
|
105
|
+
scale={scale}
|
|
106
|
+
quaternion={quaternion}
|
|
107
|
+
matrix={matrix}
|
|
108
|
+
matrixAutoUpdate={matrixAutoUpdate}
|
|
109
|
+
/>
|
|
110
|
+
</>
|
|
111
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { createPortal, type ComputeFunction, type ThreeElements, type ThreeRef, useFrame, useThree } from '@octanejs/three';
|
|
3
|
+
import { useCallback, useImperativeHandle, useState } from '@octanejs/three/renderer';
|
|
4
|
+
import type { OctaneNode } from 'octane';
|
|
5
|
+
import * as THREE from 'three';
|
|
6
|
+
import { useFBO } from './Fbo.three.tsrx';
|
|
7
|
+
|
|
8
|
+
export type RenderTextureProps = Omit<ThreeElements['texture'], 'ref' | 'args'> & {
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
samples?: number;
|
|
12
|
+
stencilBuffer?: boolean;
|
|
13
|
+
depthBuffer?: boolean;
|
|
14
|
+
generateMipmaps?: boolean;
|
|
15
|
+
renderPriority?: number;
|
|
16
|
+
eventPriority?: number;
|
|
17
|
+
frames?: number;
|
|
18
|
+
compute?: ComputeFunction;
|
|
19
|
+
children: OctaneNode;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type RenderTextureComponentProps = Omit<RenderTextureProps, 'children'> & { children?: OctaneNode };
|
|
23
|
+
|
|
24
|
+
function Container({ frames, renderPriority, children, fbo }: {
|
|
25
|
+
frames: number;
|
|
26
|
+
renderPriority: number;
|
|
27
|
+
children?: OctaneNode;
|
|
28
|
+
fbo: THREE.WebGLRenderTarget;
|
|
29
|
+
}) @{
|
|
30
|
+
let count = 0;
|
|
31
|
+
useFrame((state) => {
|
|
32
|
+
if (frames !== Infinity && count >= frames) return;
|
|
33
|
+
const gl = state.gl as any;
|
|
34
|
+
const oldAutoClear = gl.autoClear;
|
|
35
|
+
const oldXrEnabled = gl.xr.enabled;
|
|
36
|
+
const oldRenderTarget = gl.getRenderTarget();
|
|
37
|
+
const oldIsPresenting = gl.xr.isPresenting;
|
|
38
|
+
gl.autoClear = true;
|
|
39
|
+
gl.xr.enabled = false;
|
|
40
|
+
gl.xr.isPresenting = false;
|
|
41
|
+
gl.setRenderTarget(fbo);
|
|
42
|
+
gl.render(state.scene, state.camera);
|
|
43
|
+
gl.setRenderTarget(oldRenderTarget);
|
|
44
|
+
gl.autoClear = oldAutoClear;
|
|
45
|
+
gl.xr.enabled = oldXrEnabled;
|
|
46
|
+
gl.xr.isPresenting = oldIsPresenting;
|
|
47
|
+
count++;
|
|
48
|
+
}, renderPriority);
|
|
49
|
+
<>{children}</>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function RenderTexture({
|
|
53
|
+
children,
|
|
54
|
+
compute,
|
|
55
|
+
width,
|
|
56
|
+
height,
|
|
57
|
+
samples = 8,
|
|
58
|
+
renderPriority = 0,
|
|
59
|
+
eventPriority = 0,
|
|
60
|
+
frames = Infinity,
|
|
61
|
+
stencilBuffer = false,
|
|
62
|
+
depthBuffer = true,
|
|
63
|
+
generateMipmaps = false,
|
|
64
|
+
ref,
|
|
65
|
+
...props
|
|
66
|
+
}: RenderTextureComponentProps & { ref?: ThreeRef<THREE.Texture> }) @{
|
|
67
|
+
const { size, viewport } = useThree();
|
|
68
|
+
const fbo = useFBO((width || size.width) * viewport.dpr, (height || size.height) * viewport.dpr, {
|
|
69
|
+
samples,
|
|
70
|
+
stencilBuffer,
|
|
71
|
+
depthBuffer,
|
|
72
|
+
generateMipmaps,
|
|
73
|
+
});
|
|
74
|
+
const [virtualScene] = useState(() => new THREE.Scene());
|
|
75
|
+
const primitiveProps = props as any;
|
|
76
|
+
const uvCompute = useCallback<ComputeFunction>((event, state, previous) => {
|
|
77
|
+
let parent = (fbo.texture as any)?.__r3f?.parent?.object ?? (fbo.texture as any)?.__octane?.parent?.object;
|
|
78
|
+
while (parent && !(parent instanceof THREE.Object3D)) {
|
|
79
|
+
parent = parent.__r3f?.parent?.object ?? parent.__octane?.parent?.object;
|
|
80
|
+
}
|
|
81
|
+
if (!parent || !previous) return false as any;
|
|
82
|
+
if (!previous.raycaster.camera) previous.events.compute?.(event, previous, previous.previousRoot?.getState());
|
|
83
|
+
const [intersection] = previous.raycaster.intersectObject(parent);
|
|
84
|
+
if (!intersection?.uv) return false as any;
|
|
85
|
+
state.raycaster.setFromCamera(
|
|
86
|
+
state.pointer.set(intersection.uv.x * 2 - 1, intersection.uv.y * 2 - 1),
|
|
87
|
+
state.camera,
|
|
88
|
+
);
|
|
89
|
+
}, []);
|
|
90
|
+
useImperativeHandle((ref ?? null) as any, () => fbo.texture, [fbo]);
|
|
91
|
+
<>
|
|
92
|
+
{createPortal(
|
|
93
|
+
<Container renderPriority={renderPriority} frames={frames} fbo={fbo}>
|
|
94
|
+
{children}
|
|
95
|
+
<group onPointerOver={() => null} />
|
|
96
|
+
</Container>,
|
|
97
|
+
virtualScene,
|
|
98
|
+
{ events: { compute: compute ?? uvCompute, priority: eventPriority } },
|
|
99
|
+
)}
|
|
100
|
+
<primitive object={fbo.texture} {...primitiveProps} />
|
|
101
|
+
</>
|
|
102
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { type ThreeElements, type ThreeRef } from '@octanejs/three';
|
|
3
|
+
import { useLayoutEffect, useMemo, useRef } from '@octanejs/three/renderer';
|
|
4
|
+
import * as THREE from 'three';
|
|
5
|
+
|
|
6
|
+
function assignRef<T>(ref: ThreeRef<T> | undefined, value: T | null): void {
|
|
7
|
+
if (Array.isArray(ref)) for (const item of ref) assignRef(item, value);
|
|
8
|
+
else if (typeof ref === 'function') ref(value);
|
|
9
|
+
else if (ref && 'current' in ref) ref.current = value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ResizeProps =
|
|
13
|
+
Omit<ThreeElements['group'], 'ref'> & {
|
|
14
|
+
width?: boolean;
|
|
15
|
+
height?: boolean;
|
|
16
|
+
depth?: boolean;
|
|
17
|
+
box3?: THREE.Box3;
|
|
18
|
+
precise?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function Resize({
|
|
22
|
+
children,
|
|
23
|
+
width,
|
|
24
|
+
height,
|
|
25
|
+
depth,
|
|
26
|
+
box3,
|
|
27
|
+
precise = true,
|
|
28
|
+
ref,
|
|
29
|
+
...props
|
|
30
|
+
}: ResizeProps & { ref?: ThreeRef<THREE.Group> }) @{
|
|
31
|
+
const container = useRef<THREE.Group | null>(null);
|
|
32
|
+
const outer = useRef<THREE.Group | null>(null);
|
|
33
|
+
const inner = useRef<THREE.Group | null>(null);
|
|
34
|
+
const mergedRef = useMemo(
|
|
35
|
+
() => (value: THREE.Group | null) => {
|
|
36
|
+
container.current = value;
|
|
37
|
+
assignRef(ref, value);
|
|
38
|
+
},
|
|
39
|
+
[ref],
|
|
40
|
+
);
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
if (!outer.current || !inner.current) return;
|
|
43
|
+
outer.current.matrixWorld.identity();
|
|
44
|
+
const box = box3 || new THREE.Box3().setFromObject(inner.current, precise);
|
|
45
|
+
const w = box.max.x - box.min.x;
|
|
46
|
+
const h = box.max.y - box.min.y;
|
|
47
|
+
const d = box.max.z - box.min.z;
|
|
48
|
+
let dimension = Math.max(w, h, d);
|
|
49
|
+
if (width) dimension = w;
|
|
50
|
+
if (height) dimension = h;
|
|
51
|
+
if (depth) dimension = d;
|
|
52
|
+
outer.current.scale.setScalar(1 / dimension);
|
|
53
|
+
}, [width, height, depth, box3, precise]);
|
|
54
|
+
<group ref={mergedRef} {...props}>
|
|
55
|
+
<group ref={outer}>
|
|
56
|
+
<group ref={inner}>{children}</group>
|
|
57
|
+
</group>
|
|
58
|
+
</group>
|
|
59
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import type { ThreeElements, ThreeRef } from '@octanejs/three';
|
|
3
|
+
import { useLayoutEffect, useMemo, useRef } from '@octanejs/three/renderer';
|
|
4
|
+
import { type ExtrudeGeometry, type Mesh, Shape } from 'three';
|
|
5
|
+
import { toCreasedNormals } from 'three-stdlib';
|
|
6
|
+
|
|
7
|
+
const eps = 0.00001;
|
|
8
|
+
|
|
9
|
+
function createShape(width: number, height: number, radius0: number): Shape {
|
|
10
|
+
const shape = new Shape();
|
|
11
|
+
const radius = radius0 - eps;
|
|
12
|
+
shape.absarc(eps, eps, eps, -Math.PI / 2, -Math.PI, true);
|
|
13
|
+
shape.absarc(eps, height - radius * 2, eps, Math.PI, Math.PI / 2, true);
|
|
14
|
+
shape.absarc(width - radius * 2, height - radius * 2, eps, Math.PI / 2, 0, true);
|
|
15
|
+
shape.absarc(width - radius * 2, eps, eps, 0, -Math.PI / 2, true);
|
|
16
|
+
return shape;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type RoundedBoxProps =
|
|
20
|
+
{
|
|
21
|
+
args?: [width?: number, height?: number, depth?: number];
|
|
22
|
+
radius?: number;
|
|
23
|
+
smoothness?: number;
|
|
24
|
+
bevelSegments?: number;
|
|
25
|
+
steps?: number;
|
|
26
|
+
creaseAngle?: number;
|
|
27
|
+
} & Omit<ThreeElements['mesh'], 'ref' | 'args'>;
|
|
28
|
+
|
|
29
|
+
export type RoundedBoxGeometryProps =
|
|
30
|
+
Omit<RoundedBoxProps, 'children'> & Omit<ThreeElements['extrudeGeometry'], 'args' | 'ref'>;
|
|
31
|
+
|
|
32
|
+
export function RoundedBox({
|
|
33
|
+
args: [width = 1, height = 1, depth = 1] = [],
|
|
34
|
+
radius = 0.05,
|
|
35
|
+
steps = 1,
|
|
36
|
+
smoothness = 4,
|
|
37
|
+
bevelSegments = 4,
|
|
38
|
+
creaseAngle = 0.4,
|
|
39
|
+
children,
|
|
40
|
+
ref,
|
|
41
|
+
...rest
|
|
42
|
+
}: RoundedBoxProps & { ref?: ThreeRef<Mesh> }) @{
|
|
43
|
+
const meshRef = useMemo(() => (value: Mesh | null) => assignThreeRef(ref, value), [ref]);
|
|
44
|
+
|
|
45
|
+
<mesh ref={meshRef} {...rest}>
|
|
46
|
+
<RoundedBoxGeometry
|
|
47
|
+
args={[width, height, depth]}
|
|
48
|
+
radius={radius}
|
|
49
|
+
steps={steps}
|
|
50
|
+
smoothness={smoothness}
|
|
51
|
+
bevelSegments={bevelSegments}
|
|
52
|
+
creaseAngle={creaseAngle}
|
|
53
|
+
/>
|
|
54
|
+
{children}
|
|
55
|
+
</mesh>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function assignThreeRef<T>(ref: ThreeRef<T> | undefined, value: T | null): void {
|
|
59
|
+
if (Array.isArray(ref)) {
|
|
60
|
+
for (const item of ref) assignThreeRef(item, value);
|
|
61
|
+
} else if (typeof ref === 'function') {
|
|
62
|
+
ref(value);
|
|
63
|
+
} else if (ref !== undefined && 'current' in ref) {
|
|
64
|
+
ref.current = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function RoundedBoxGeometry({
|
|
69
|
+
args: [width = 1, height = 1, depth = 1] = [],
|
|
70
|
+
radius = 0.05,
|
|
71
|
+
steps = 1,
|
|
72
|
+
smoothness = 4,
|
|
73
|
+
bevelSegments = 4,
|
|
74
|
+
creaseAngle = 0.4,
|
|
75
|
+
ref,
|
|
76
|
+
...rest
|
|
77
|
+
}: RoundedBoxGeometryProps & { ref?: ThreeRef<ExtrudeGeometry> }) @{
|
|
78
|
+
const shape = useMemo(() => createShape(width, height, radius), [width, height, radius]);
|
|
79
|
+
const params = useMemo(
|
|
80
|
+
() => ({
|
|
81
|
+
depth: depth - radius * 2,
|
|
82
|
+
bevelEnabled: true,
|
|
83
|
+
bevelSegments: bevelSegments * 2,
|
|
84
|
+
steps,
|
|
85
|
+
bevelSize: radius - eps,
|
|
86
|
+
bevelThickness: radius,
|
|
87
|
+
curveSegments: smoothness,
|
|
88
|
+
}),
|
|
89
|
+
[depth, radius, smoothness, bevelSegments, steps],
|
|
90
|
+
);
|
|
91
|
+
const geometryRef = useRef<ExtrudeGeometry | null>(null);
|
|
92
|
+
|
|
93
|
+
useLayoutEffect(() => {
|
|
94
|
+
if (geometryRef.current !== null) {
|
|
95
|
+
geometryRef.current.center();
|
|
96
|
+
// three-mesh-bvh augments the workspace BufferGeometry type from its
|
|
97
|
+
// peer instance; both libraries operate on the same Three.js object.
|
|
98
|
+
toCreasedNormals(
|
|
99
|
+
geometryRef.current as unknown as Parameters<typeof toCreasedNormals>[0],
|
|
100
|
+
creaseAngle,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}, [shape, params, creaseAngle]);
|
|
104
|
+
|
|
105
|
+
<extrudeGeometry ref={[geometryRef, ref ?? null]} args={[shape, params]} {...rest} />
|
|
106
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { type ThreeElements } from '@octanejs/three';
|
|
3
|
+
import { useLayoutEffect, useRef, useState, type RefObject } from '@octanejs/three/renderer';
|
|
4
|
+
import type { OctaneNode } from 'octane';
|
|
5
|
+
import {
|
|
6
|
+
Color,
|
|
7
|
+
Group,
|
|
8
|
+
InstancedBufferAttribute,
|
|
9
|
+
InstancedMesh,
|
|
10
|
+
Mesh,
|
|
11
|
+
Object3D,
|
|
12
|
+
Vector3,
|
|
13
|
+
} from 'three';
|
|
14
|
+
import { MeshSurfaceSampler } from 'three-stdlib';
|
|
15
|
+
import { slotDefault } from './compiler-slot.js';
|
|
16
|
+
|
|
17
|
+
type SamplePayload = {
|
|
18
|
+
position: Vector3;
|
|
19
|
+
normal: Vector3;
|
|
20
|
+
color: Color;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type TransformPayload = SamplePayload & {
|
|
24
|
+
dummy: Object3D;
|
|
25
|
+
sampledMesh: Mesh;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type TransformFn = (payload: TransformPayload, index: number) => void;
|
|
29
|
+
|
|
30
|
+
export type SamplerProps = Omit<ThreeElements['group'], 'ref'> & {
|
|
31
|
+
mesh?: RefObject<Mesh>;
|
|
32
|
+
instances?: RefObject<InstancedMesh>;
|
|
33
|
+
weight?: string;
|
|
34
|
+
transform?: TransformFn;
|
|
35
|
+
count?: number;
|
|
36
|
+
children?: OctaneNode;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface useSurfaceSamplerProps {
|
|
40
|
+
transform?: TransformFn;
|
|
41
|
+
weight?: string;
|
|
42
|
+
count?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function useSurfaceSampler(
|
|
46
|
+
mesh: RefObject<Mesh>,
|
|
47
|
+
count = 16,
|
|
48
|
+
transform?: TransformFn,
|
|
49
|
+
weight?: string,
|
|
50
|
+
instanceMesh?: RefObject<InstancedMesh> | null,
|
|
51
|
+
): InstancedBufferAttribute {
|
|
52
|
+
count = slotDefault(count, 16);
|
|
53
|
+
transform = slotDefault(transform, undefined);
|
|
54
|
+
weight = slotDefault(weight, undefined);
|
|
55
|
+
instanceMesh = slotDefault(instanceMesh, undefined);
|
|
56
|
+
const [buffer, setBuffer] = useState(() => {
|
|
57
|
+
const values = Array.from(
|
|
58
|
+
{ length: count },
|
|
59
|
+
() => [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
|
60
|
+
).flat();
|
|
61
|
+
return new InstancedBufferAttribute(Float32Array.from(values), 16);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
useLayoutEffect(() => {
|
|
65
|
+
if (!mesh.current) return;
|
|
66
|
+
// three-stdlib currently resolves a newer @types/three copy; runtime instances are compatible.
|
|
67
|
+
const sampler = new MeshSurfaceSampler(mesh.current as any);
|
|
68
|
+
if (weight) sampler.setWeightAttribute(weight);
|
|
69
|
+
sampler.build();
|
|
70
|
+
const position = new Vector3();
|
|
71
|
+
const normal = new Vector3();
|
|
72
|
+
const color = new Color();
|
|
73
|
+
const dummy = new Object3D();
|
|
74
|
+
mesh.current.updateMatrixWorld(true);
|
|
75
|
+
for (let index = 0; index < count; index++) {
|
|
76
|
+
sampler.sample(position as any, normal as any, color as any);
|
|
77
|
+
if (transform) {
|
|
78
|
+
transform({ dummy, sampledMesh: mesh.current, position, normal, color }, index);
|
|
79
|
+
} else {
|
|
80
|
+
dummy.position.copy(position);
|
|
81
|
+
}
|
|
82
|
+
dummy.updateMatrix();
|
|
83
|
+
instanceMesh?.current?.setMatrixAt(index, dummy.matrix);
|
|
84
|
+
dummy.matrix.toArray(buffer.array, index * 16);
|
|
85
|
+
}
|
|
86
|
+
if (instanceMesh?.current) instanceMesh.current.instanceMatrix.needsUpdate = true;
|
|
87
|
+
buffer.needsUpdate = true;
|
|
88
|
+
setBuffer(new InstancedBufferAttribute(buffer.array as Float32Array, buffer.itemSize).copy(buffer));
|
|
89
|
+
}, [mesh, instanceMesh, weight, count, transform]);
|
|
90
|
+
|
|
91
|
+
return buffer;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function Sampler({
|
|
95
|
+
children,
|
|
96
|
+
weight,
|
|
97
|
+
transform,
|
|
98
|
+
instances,
|
|
99
|
+
mesh,
|
|
100
|
+
count = 16,
|
|
101
|
+
...props
|
|
102
|
+
}: SamplerProps) @{
|
|
103
|
+
const group = useRef<Group | null>(null);
|
|
104
|
+
const instancedRef = useRef<InstancedMesh | null>(null);
|
|
105
|
+
const meshToSampleRef = useRef<Mesh | null>(null);
|
|
106
|
+
useLayoutEffect(() => {
|
|
107
|
+
instancedRef.current = instances?.current ?? group.current?.children.find(
|
|
108
|
+
(child) => Object.hasOwn(child, 'instanceMatrix'),
|
|
109
|
+
) as InstancedMesh | null;
|
|
110
|
+
meshToSampleRef.current = mesh?.current ?? group.current?.children.find(
|
|
111
|
+
(child) => child.type === 'Mesh',
|
|
112
|
+
) as Mesh | null;
|
|
113
|
+
}, [children, mesh?.current, instances?.current]);
|
|
114
|
+
useSurfaceSampler(meshToSampleRef, count, transform, weight, instancedRef);
|
|
115
|
+
<group ref={group} {...props}>{children}</group>
|
|
116
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { type ThreeElements, type ThreeRef, useFrame } from '@octanejs/three';
|
|
3
|
+
import { useMemo, useRef } from '@octanejs/three/renderer';
|
|
4
|
+
import { Object3D, Vector3 } from 'three';
|
|
5
|
+
import { calculateScaleFactor } from './calculateScaleFactor.js';
|
|
6
|
+
|
|
7
|
+
const worldPosition = new Vector3();
|
|
8
|
+
|
|
9
|
+
export type ScreenSizerProps =
|
|
10
|
+
Omit<ThreeElements['object3D'], 'ref'> & {
|
|
11
|
+
scale?: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function assignRef<T>(ref: ThreeRef<T> | undefined, value: T | null): void {
|
|
15
|
+
if (Array.isArray(ref)) for (const item of ref) assignRef(item, value);
|
|
16
|
+
else if (typeof ref === 'function') ref(value);
|
|
17
|
+
else if (ref && 'current' in ref) ref.current = value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function ScreenSizer({ scale = 1, ref, ...props }: ScreenSizerProps & {
|
|
21
|
+
ref?: ThreeRef<Object3D>;
|
|
22
|
+
}) @{
|
|
23
|
+
const container = useRef<Object3D | null>(null);
|
|
24
|
+
const mergedRef = useMemo(
|
|
25
|
+
() => (value: Object3D | null) => {
|
|
26
|
+
container.current = value;
|
|
27
|
+
assignRef(ref, value);
|
|
28
|
+
},
|
|
29
|
+
[ref],
|
|
30
|
+
);
|
|
31
|
+
useFrame((state) => {
|
|
32
|
+
const object = container.current;
|
|
33
|
+
if (!object) return;
|
|
34
|
+
const factor = calculateScaleFactor(
|
|
35
|
+
object.getWorldPosition(worldPosition),
|
|
36
|
+
scale,
|
|
37
|
+
state.camera,
|
|
38
|
+
state.size,
|
|
39
|
+
);
|
|
40
|
+
object.scale.setScalar(factor * scale);
|
|
41
|
+
});
|
|
42
|
+
<object3D ref={mergedRef} {...props} />
|
|
43
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { type ThreeElements, type ThreeRef, useFrame } from '@octanejs/three';
|
|
3
|
+
import { useRef } from '@octanejs/three/renderer';
|
|
4
|
+
import type { Group } from 'three';
|
|
5
|
+
|
|
6
|
+
export type ScreenSpaceProps = Omit<ThreeElements['group'], 'ref'> & { depth?: number };
|
|
7
|
+
|
|
8
|
+
export function ScreenSpace({ children, depth = -1, ref, ...rest }: ScreenSpaceProps & {
|
|
9
|
+
ref?: ThreeRef<Group>;
|
|
10
|
+
}) @{
|
|
11
|
+
const localRef = useRef<Group | null>(null);
|
|
12
|
+
useFrame(({ camera }) => {
|
|
13
|
+
if (localRef.current) {
|
|
14
|
+
localRef.current.quaternion.copy(camera.quaternion);
|
|
15
|
+
localRef.current.position.copy(camera.position);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
<group ref={[localRef, ref ?? null]} {...rest}>
|
|
19
|
+
<group position={[0, 0, -depth]}>{children}</group>
|
|
20
|
+
</group>
|
|
21
|
+
}
|