@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,22 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { use } from '@octanejs/three/renderer';
|
|
3
|
+
import { getGPUTier, type GetGPUTier } from 'detect-gpu';
|
|
4
|
+
import { slotDefault } from './compiler-slot.js';
|
|
5
|
+
import { resolveRenderChildren, type RenderChildren } from './octane-children.js';
|
|
6
|
+
import { resourcePromise } from './resource.js';
|
|
7
|
+
|
|
8
|
+
export const useDetectGPU = (props?: GetGPUTier) => {
|
|
9
|
+
props = slotDefault(props, undefined);
|
|
10
|
+
return use(resourcePromise(() => getGPUTier(props), ['useDetectGPU']));
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type DetectGPUProps = {
|
|
14
|
+
children?: RenderChildren<ReturnType<typeof useDetectGPU>>;
|
|
15
|
+
} & Parameters<typeof useDetectGPU>[0];
|
|
16
|
+
|
|
17
|
+
export function DetectGPU({ children, ...options }: DetectGPUProps) @{
|
|
18
|
+
const result = useDetectGPU(options);
|
|
19
|
+
<>
|
|
20
|
+
{resolveRenderChildren(children, result)}
|
|
21
|
+
</>
|
|
22
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import {
|
|
3
|
+
extend,
|
|
4
|
+
type ThreeElement,
|
|
5
|
+
type ThreeRef,
|
|
6
|
+
useFrame,
|
|
7
|
+
useThree,
|
|
8
|
+
} from '@octanejs/three';
|
|
9
|
+
import { useEffect, useMemo, useRef, useState } from '@octanejs/three/renderer';
|
|
10
|
+
import * as THREE from 'three';
|
|
11
|
+
import {
|
|
12
|
+
EffectComposer,
|
|
13
|
+
GammaCorrectionShader,
|
|
14
|
+
RenderPass,
|
|
15
|
+
ShaderPass,
|
|
16
|
+
} from 'three-stdlib';
|
|
17
|
+
import { isOctaneChildrenBlock } from './octane-element.js';
|
|
18
|
+
|
|
19
|
+
const EffectComposerElement = extend(EffectComposer);
|
|
20
|
+
const RenderPassElement = extend(RenderPass);
|
|
21
|
+
const ShaderPassElement = extend(ShaderPass);
|
|
22
|
+
|
|
23
|
+
export type EffectsProps = Omit<ThreeElement<typeof EffectComposer>, 'ref' | 'args'> & {
|
|
24
|
+
multisamping?: number;
|
|
25
|
+
colorSpace?: THREE.ColorSpace;
|
|
26
|
+
type?: THREE.TextureDataType;
|
|
27
|
+
renderIndex?: number;
|
|
28
|
+
disableGamma?: boolean;
|
|
29
|
+
disableRenderPass?: boolean;
|
|
30
|
+
disableRender?: boolean;
|
|
31
|
+
depthBuffer?: boolean;
|
|
32
|
+
stencilBuffer?: boolean;
|
|
33
|
+
anisotropy?: number;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function assignRef<T>(ref: ThreeRef<T> | undefined, value: T | null): void {
|
|
37
|
+
if (Array.isArray(ref)) for (const item of ref) assignRef(item, value);
|
|
38
|
+
else if (typeof ref === 'function') ref(value);
|
|
39
|
+
else if (ref && 'current' in ref) ref.current = value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function appendPasses(passes: any[], children: unknown): void {
|
|
43
|
+
if (Array.isArray(children)) {
|
|
44
|
+
for (const child of children) appendPasses(passes, child);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Universal plan/element descriptors are objects. Compiled children blocks and
|
|
48
|
+
// other functions are not cloneable — those render through auto-attach instead.
|
|
49
|
+
if (children == null || typeof children === 'boolean' || typeof children === 'function') return;
|
|
50
|
+
if (typeof children !== 'object') return;
|
|
51
|
+
const element = children as { props?: Record<string, unknown> };
|
|
52
|
+
const key = passes.length;
|
|
53
|
+
passes.push({
|
|
54
|
+
...element,
|
|
55
|
+
key: String(key),
|
|
56
|
+
props: { ...element.props, key, attach: `passes-${key}` },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function Effects({
|
|
61
|
+
children,
|
|
62
|
+
multisamping = 8,
|
|
63
|
+
renderIndex = 1,
|
|
64
|
+
disableRender,
|
|
65
|
+
disableGamma,
|
|
66
|
+
disableRenderPass,
|
|
67
|
+
depthBuffer = true,
|
|
68
|
+
stencilBuffer = false,
|
|
69
|
+
anisotropy = 1,
|
|
70
|
+
colorSpace,
|
|
71
|
+
type,
|
|
72
|
+
ref,
|
|
73
|
+
...props
|
|
74
|
+
}: EffectsProps & { ref?: ThreeRef<EffectComposer> }) @{
|
|
75
|
+
const composer = useRef<EffectComposer | null>(null);
|
|
76
|
+
const mergedRef = useMemo(
|
|
77
|
+
() => (value: EffectComposer | null) => {
|
|
78
|
+
composer.current = value;
|
|
79
|
+
assignRef(ref, value);
|
|
80
|
+
},
|
|
81
|
+
[ref],
|
|
82
|
+
);
|
|
83
|
+
const { scene, camera, gl, size, viewport } = useThree();
|
|
84
|
+
const [target] = useState(() => {
|
|
85
|
+
const renderTarget = new THREE.WebGLRenderTarget(size.width, size.height, {
|
|
86
|
+
type: type || THREE.HalfFloatType,
|
|
87
|
+
format: THREE.RGBAFormat,
|
|
88
|
+
depthBuffer,
|
|
89
|
+
stencilBuffer,
|
|
90
|
+
anisotropy,
|
|
91
|
+
});
|
|
92
|
+
if (type === THREE.UnsignedByteType && colorSpace != null) {
|
|
93
|
+
renderTarget.texture.colorSpace = colorSpace;
|
|
94
|
+
}
|
|
95
|
+
renderTarget.samples = multisamping;
|
|
96
|
+
return renderTarget;
|
|
97
|
+
});
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
composer.current?.setSize(size.width, size.height);
|
|
100
|
+
composer.current?.setPixelRatio(viewport.dpr);
|
|
101
|
+
}, [gl, size, viewport.dpr]);
|
|
102
|
+
useFrame(() => {
|
|
103
|
+
if (!disableRender) composer.current?.render();
|
|
104
|
+
}, renderIndex);
|
|
105
|
+
const passes: any[] = [];
|
|
106
|
+
if (!disableRenderPass) {
|
|
107
|
+
passes.push(<RenderPassElement key="renderpass" attach={`passes-${passes.length}`} args={[scene, camera] as any} />);
|
|
108
|
+
}
|
|
109
|
+
if (!disableGamma) {
|
|
110
|
+
passes.push(<ShaderPassElement key="gammapass" attach={`passes-${passes.length}`} args={[GammaCorrectionShader]} />);
|
|
111
|
+
}
|
|
112
|
+
const blockChildren = isOctaneChildrenBlock(children) ? children : null;
|
|
113
|
+
if (!blockChildren) appendPasses(passes, children);
|
|
114
|
+
<EffectComposerElement
|
|
115
|
+
ref={mergedRef}
|
|
116
|
+
args={[gl as any, target]}
|
|
117
|
+
__octaneAutoAttachArray="passes"
|
|
118
|
+
{...props as any}
|
|
119
|
+
>
|
|
120
|
+
{passes}
|
|
121
|
+
{blockChildren}
|
|
122
|
+
</EffectComposerElement>
|
|
123
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import {
|
|
3
|
+
applyProps,
|
|
4
|
+
createPortal,
|
|
5
|
+
extend,
|
|
6
|
+
type ThreeElement,
|
|
7
|
+
useFrame,
|
|
8
|
+
useThree,
|
|
9
|
+
} from '@octanejs/three';
|
|
10
|
+
import { useEffect, useLayoutEffect, useMemo, useRef, useState, type RefObject } from '@octanejs/three/renderer';
|
|
11
|
+
import type { OctaneNode } from 'octane';
|
|
12
|
+
import { universalComponent } from 'octane/universal';
|
|
13
|
+
import {
|
|
14
|
+
CubeCamera,
|
|
15
|
+
type CubeTexture,
|
|
16
|
+
type Euler,
|
|
17
|
+
HalfFloatType,
|
|
18
|
+
Scene,
|
|
19
|
+
type Texture,
|
|
20
|
+
WebGLCubeRenderTarget,
|
|
21
|
+
} from 'three';
|
|
22
|
+
import { GroundProjectedEnv as GroundProjectedEnvImpl } from 'three-stdlib';
|
|
23
|
+
import type { EnvironmentLoaderProps } from './environment-loader.js';
|
|
24
|
+
import { useEnvironment } from './useEnvironment.three.tsrx';
|
|
25
|
+
|
|
26
|
+
export type EnvironmentProps = {
|
|
27
|
+
children?: OctaneNode;
|
|
28
|
+
frames?: number;
|
|
29
|
+
near?: number;
|
|
30
|
+
far?: number;
|
|
31
|
+
resolution?: number;
|
|
32
|
+
background?: boolean | 'only';
|
|
33
|
+
blur?: number;
|
|
34
|
+
backgroundBlurriness?: number;
|
|
35
|
+
backgroundIntensity?: number;
|
|
36
|
+
backgroundRotation?: Euler;
|
|
37
|
+
environmentIntensity?: number;
|
|
38
|
+
environmentRotation?: Euler;
|
|
39
|
+
map?: Texture;
|
|
40
|
+
scene?: Scene | RefObject<Scene>;
|
|
41
|
+
ground?: boolean | { radius?: number; height?: number; scale?: number };
|
|
42
|
+
} & EnvironmentLoaderProps;
|
|
43
|
+
|
|
44
|
+
function isSceneRef(scene: Scene | RefObject<Scene>): scene is RefObject<Scene> {
|
|
45
|
+
return Boolean(scene && 'current' in scene && scene.current?.isScene);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolveScene(scene: Scene | RefObject<Scene>): Scene {
|
|
49
|
+
return isSceneRef(scene) ? scene.current! : scene;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function setEnvironmentProperties(
|
|
53
|
+
background: boolean | 'only',
|
|
54
|
+
scene: Scene | RefObject<Scene> | undefined,
|
|
55
|
+
defaultScene: Scene,
|
|
56
|
+
texture: Texture,
|
|
57
|
+
sceneProps: Partial<EnvironmentProps> = {},
|
|
58
|
+
): () => void {
|
|
59
|
+
const nextProps = {
|
|
60
|
+
backgroundBlurriness: 0,
|
|
61
|
+
backgroundIntensity: 1,
|
|
62
|
+
backgroundRotation: [0, 0, 0],
|
|
63
|
+
environmentIntensity: 1,
|
|
64
|
+
environmentRotation: [0, 0, 0],
|
|
65
|
+
...sceneProps,
|
|
66
|
+
};
|
|
67
|
+
const target = resolveScene(scene ?? defaultScene);
|
|
68
|
+
const oldBackground = target.background;
|
|
69
|
+
const oldEnvironment = target.environment;
|
|
70
|
+
const oldSceneProps = {
|
|
71
|
+
backgroundBlurriness: target.backgroundBlurriness,
|
|
72
|
+
backgroundIntensity: target.backgroundIntensity,
|
|
73
|
+
backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
|
|
74
|
+
environmentIntensity: target.environmentIntensity,
|
|
75
|
+
environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0],
|
|
76
|
+
};
|
|
77
|
+
if (background !== 'only') target.environment = texture;
|
|
78
|
+
if (background) target.background = texture;
|
|
79
|
+
applyProps(target as any, nextProps as any);
|
|
80
|
+
return () => {
|
|
81
|
+
if (background !== 'only') target.environment = oldEnvironment;
|
|
82
|
+
if (background) target.background = oldBackground;
|
|
83
|
+
applyProps(target as any, oldSceneProps as any);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function EnvironmentMap({
|
|
88
|
+
scene,
|
|
89
|
+
background = false,
|
|
90
|
+
map,
|
|
91
|
+
...config
|
|
92
|
+
}: EnvironmentProps) @{
|
|
93
|
+
const defaultScene = useThree((state) => state.scene);
|
|
94
|
+
useLayoutEffect(() => {
|
|
95
|
+
if (map) return setEnvironmentProperties(background, scene, defaultScene, map, config);
|
|
96
|
+
});
|
|
97
|
+
null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function EnvironmentCube({
|
|
101
|
+
background = false,
|
|
102
|
+
scene,
|
|
103
|
+
blur,
|
|
104
|
+
backgroundBlurriness,
|
|
105
|
+
backgroundIntensity,
|
|
106
|
+
backgroundRotation,
|
|
107
|
+
environmentIntensity,
|
|
108
|
+
environmentRotation,
|
|
109
|
+
...loaderOptions
|
|
110
|
+
}: EnvironmentProps) @{
|
|
111
|
+
const texture = useEnvironment(loaderOptions);
|
|
112
|
+
const defaultScene = useThree((state) => state.scene);
|
|
113
|
+
useLayoutEffect(() => setEnvironmentProperties(background, scene, defaultScene, texture, {
|
|
114
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
115
|
+
backgroundIntensity,
|
|
116
|
+
backgroundRotation,
|
|
117
|
+
environmentIntensity,
|
|
118
|
+
environmentRotation,
|
|
119
|
+
}));
|
|
120
|
+
useEffect(() => () => texture.dispose(), [texture]);
|
|
121
|
+
null
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function EnvironmentPortal({
|
|
125
|
+
children,
|
|
126
|
+
near = 0.1,
|
|
127
|
+
far = 1000,
|
|
128
|
+
resolution = 256,
|
|
129
|
+
frames = 1,
|
|
130
|
+
map,
|
|
131
|
+
background = false,
|
|
132
|
+
blur,
|
|
133
|
+
backgroundBlurriness,
|
|
134
|
+
backgroundIntensity,
|
|
135
|
+
backgroundRotation,
|
|
136
|
+
environmentIntensity,
|
|
137
|
+
environmentRotation,
|
|
138
|
+
scene,
|
|
139
|
+
files,
|
|
140
|
+
path,
|
|
141
|
+
preset,
|
|
142
|
+
extensions,
|
|
143
|
+
}: EnvironmentProps) @{
|
|
144
|
+
const gl = useThree((state) => state.gl);
|
|
145
|
+
const defaultScene = useThree((state) => state.scene);
|
|
146
|
+
const camera = useRef<CubeCamera | null>(null);
|
|
147
|
+
const [virtualScene] = useState(() => new Scene());
|
|
148
|
+
const target = useMemo(() => {
|
|
149
|
+
const value = new WebGLCubeRenderTarget(resolution);
|
|
150
|
+
value.texture.type = HalfFloatType;
|
|
151
|
+
return value;
|
|
152
|
+
}, [resolution]);
|
|
153
|
+
useEffect(() => () => target.dispose(), [target]);
|
|
154
|
+
useLayoutEffect(() => {
|
|
155
|
+
if (frames === 1 && camera.current) {
|
|
156
|
+
const autoClear = gl.autoClear;
|
|
157
|
+
gl.autoClear = true;
|
|
158
|
+
camera.current.update(gl as any, virtualScene);
|
|
159
|
+
gl.autoClear = autoClear;
|
|
160
|
+
}
|
|
161
|
+
return setEnvironmentProperties(background, scene, defaultScene, target.texture, {
|
|
162
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
163
|
+
backgroundIntensity,
|
|
164
|
+
backgroundRotation,
|
|
165
|
+
environmentIntensity,
|
|
166
|
+
environmentRotation,
|
|
167
|
+
});
|
|
168
|
+
}, [children, virtualScene, target.texture, scene, defaultScene, background, frames, gl]);
|
|
169
|
+
let count = 1;
|
|
170
|
+
useFrame(() => {
|
|
171
|
+
if ((frames === Infinity || count < frames) && camera.current) {
|
|
172
|
+
const autoClear = gl.autoClear;
|
|
173
|
+
gl.autoClear = true;
|
|
174
|
+
camera.current.update(gl as any, virtualScene);
|
|
175
|
+
gl.autoClear = autoClear;
|
|
176
|
+
count++;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
<>
|
|
180
|
+
{createPortal(
|
|
181
|
+
<>
|
|
182
|
+
{children}
|
|
183
|
+
<cubeCamera ref={camera} args={[near, far, target]} />
|
|
184
|
+
@if (files || preset) {
|
|
185
|
+
<EnvironmentCube background={true} files={files} preset={preset} path={path} extensions={extensions} />
|
|
186
|
+
} @else if (map) {
|
|
187
|
+
<EnvironmentMap background={true} map={map} extensions={extensions} />
|
|
188
|
+
}
|
|
189
|
+
</>,
|
|
190
|
+
virtualScene,
|
|
191
|
+
)}
|
|
192
|
+
</>
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const GroundProjectedEnvElement = extend(GroundProjectedEnvImpl);
|
|
196
|
+
|
|
197
|
+
function EnvironmentGround(props: EnvironmentProps) @{
|
|
198
|
+
const textureDefault = useEnvironment(props);
|
|
199
|
+
const texture = props.map ?? textureDefault;
|
|
200
|
+
useEffect(() => () => textureDefault.dispose(), [textureDefault]);
|
|
201
|
+
const args = useMemo<[CubeTexture | Texture]>(() => [texture], [texture]);
|
|
202
|
+
const height = typeof props.ground === 'object' ? props.ground.height : undefined;
|
|
203
|
+
const radius = typeof props.ground === 'object' ? props.ground.radius : undefined;
|
|
204
|
+
const scale = typeof props.ground === 'object' ? props.ground.scale ?? 1000 : 1000;
|
|
205
|
+
<>
|
|
206
|
+
<EnvironmentMap {...props} map={texture} />
|
|
207
|
+
<GroundProjectedEnvElement args={args as any} scale={scale} height={height} radius={radius} />
|
|
208
|
+
</>
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function Environment(props: EnvironmentProps) @{
|
|
212
|
+
const component = props.ground
|
|
213
|
+
? EnvironmentGround
|
|
214
|
+
: props.map
|
|
215
|
+
? EnvironmentMap
|
|
216
|
+
: props.children
|
|
217
|
+
? EnvironmentPortal
|
|
218
|
+
: EnvironmentCube;
|
|
219
|
+
<>{universalComponent('three', component as any, props as unknown as Record<string, unknown>)}</>
|
|
220
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { type ThreeElements, type ThreeRef } from '@octanejs/three';
|
|
3
|
+
import { useCallback, useImperativeHandle, useMemo, useState } from '@octanejs/three/renderer';
|
|
4
|
+
import type { OctaneNode } from 'octane';
|
|
5
|
+
import { MeshNormalMaterial, MeshStandardMaterial, type ColorRepresentation, type Group } from 'three';
|
|
6
|
+
import { Center } from './Center.three.tsrx';
|
|
7
|
+
import { Text3D } from './Text3D.three.tsrx';
|
|
8
|
+
|
|
9
|
+
export type ExampleProps = {
|
|
10
|
+
font: string;
|
|
11
|
+
color?: ColorRepresentation;
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
bevelSize?: number;
|
|
14
|
+
children?: OctaneNode;
|
|
15
|
+
} & Omit<ThreeElements['group'], 'ref'>;
|
|
16
|
+
|
|
17
|
+
export type ExampleApi = {
|
|
18
|
+
incr: (x?: number) => void;
|
|
19
|
+
decr: (x?: number) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function Example({
|
|
23
|
+
font,
|
|
24
|
+
color = '#cbcbcb',
|
|
25
|
+
bevelSize = 0.04,
|
|
26
|
+
debug = false,
|
|
27
|
+
children,
|
|
28
|
+
ref,
|
|
29
|
+
...props
|
|
30
|
+
}: ExampleProps & { ref?: ThreeRef<ExampleApi> }) @{
|
|
31
|
+
const [counter, setCounter] = useState(0);
|
|
32
|
+
const incr = useCallback((x = 1) => setCounter(counter + x), [counter]);
|
|
33
|
+
const decr = useCallback((x = 1) => setCounter(counter - x), [counter]);
|
|
34
|
+
const api = useMemo<ExampleApi>(() => ({ incr, decr }), [incr, decr]);
|
|
35
|
+
useImperativeHandle((ref ?? null) as any, () => api, [api]);
|
|
36
|
+
const material = useMemo(
|
|
37
|
+
() => debug
|
|
38
|
+
? new MeshNormalMaterial({ wireframe: true })
|
|
39
|
+
: new MeshStandardMaterial({ color }),
|
|
40
|
+
[debug, color],
|
|
41
|
+
);
|
|
42
|
+
<group {...props}>
|
|
43
|
+
@try {
|
|
44
|
+
<Center top cacheKey={JSON.stringify({ counter, font })}>
|
|
45
|
+
<Text3D
|
|
46
|
+
bevelEnabled
|
|
47
|
+
bevelSize={bevelSize}
|
|
48
|
+
font={font}
|
|
49
|
+
material={material}
|
|
50
|
+
children={counter}
|
|
51
|
+
/>
|
|
52
|
+
</Center>
|
|
53
|
+
} @pending {}
|
|
54
|
+
{children}
|
|
55
|
+
</group>
|
|
56
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useThree } from '@octanejs/three';
|
|
2
|
+
import { useEffect, useLayoutEffect, useMemo } from '@octanejs/three/renderer';
|
|
3
|
+
import * as THREE from 'three';
|
|
4
|
+
import { slotDefault } from './compiler-slot.js';
|
|
5
|
+
import { resolveRenderChildren, type RenderChildren } from './octane-children.js';
|
|
6
|
+
|
|
7
|
+
type FBOSettings =
|
|
8
|
+
{
|
|
9
|
+
/** @deprecated use `depthBuffer` instead. */
|
|
10
|
+
depth?: boolean;
|
|
11
|
+
} & THREE.RenderTargetOptions;
|
|
12
|
+
|
|
13
|
+
export function useFBO(width?: number | FBOSettings, height?: number, settings?: FBOSettings) {
|
|
14
|
+
width = slotDefault(width, undefined);
|
|
15
|
+
height = slotDefault(height, undefined);
|
|
16
|
+
settings = slotDefault(settings, undefined);
|
|
17
|
+
const size = useThree((state) => state.size);
|
|
18
|
+
const viewport = useThree((state) => state.viewport);
|
|
19
|
+
const targetWidth =
|
|
20
|
+
typeof width === 'number' ? width : size.width * viewport.dpr;
|
|
21
|
+
const targetHeight =
|
|
22
|
+
typeof height === 'number' ? height : size.height * viewport.dpr;
|
|
23
|
+
const resolvedSettings = (typeof width === 'number' ? settings : width) || {};
|
|
24
|
+
const { samples = 0, depth, ...targetSettings } = resolvedSettings;
|
|
25
|
+
const depthBuffer = depth ?? resolvedSettings.depthBuffer;
|
|
26
|
+
const target = useMemo(() => {
|
|
27
|
+
const value = new THREE.WebGLRenderTarget(targetWidth, targetHeight, {
|
|
28
|
+
minFilter: THREE.LinearFilter,
|
|
29
|
+
magFilter: THREE.LinearFilter,
|
|
30
|
+
type: THREE.HalfFloatType,
|
|
31
|
+
...targetSettings,
|
|
32
|
+
});
|
|
33
|
+
if (depthBuffer) {
|
|
34
|
+
value.depthTexture = new THREE.DepthTexture(targetWidth, targetHeight, THREE.FloatType);
|
|
35
|
+
}
|
|
36
|
+
value.samples = samples;
|
|
37
|
+
return value;
|
|
38
|
+
}, []);
|
|
39
|
+
useLayoutEffect(() => {
|
|
40
|
+
target.setSize(targetWidth, targetHeight);
|
|
41
|
+
if (samples) target.samples = samples;
|
|
42
|
+
}, [samples, target, targetWidth, targetHeight]);
|
|
43
|
+
useEffect(() => () => target.dispose(), []);
|
|
44
|
+
return target;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type UseFBOParams = Parameters<typeof useFBO>;
|
|
48
|
+
type FBO = ReturnType<typeof useFBO>;
|
|
49
|
+
|
|
50
|
+
export type FboProps =
|
|
51
|
+
{
|
|
52
|
+
children?: RenderChildren<FBO>;
|
|
53
|
+
width?: UseFBOParams[0];
|
|
54
|
+
height?: UseFBOParams[1];
|
|
55
|
+
} & FBOSettings;
|
|
56
|
+
|
|
57
|
+
export function Fbo({ children, width, height, ref, ...settings }: FboProps & {
|
|
58
|
+
ref?: { current: FBO | null } | ((value: FBO | null) => void);
|
|
59
|
+
}) @{
|
|
60
|
+
const target = useFBO(width, height, settings);
|
|
61
|
+
useLayoutEffect(() => {
|
|
62
|
+
if (typeof ref === 'function') ref(target);
|
|
63
|
+
else if (ref) ref.current = target;
|
|
64
|
+
return () => {
|
|
65
|
+
if (typeof ref === 'function') ref(null);
|
|
66
|
+
else if (ref) ref.current = null;
|
|
67
|
+
};
|
|
68
|
+
}, [ref, target]);
|
|
69
|
+
<>{resolveRenderChildren(children, target)}</>
|
|
70
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { useLoader, type ThreeRef } from '@octanejs/three';
|
|
3
|
+
import type { Group } from 'three';
|
|
4
|
+
import { FBXLoader } from 'three-stdlib';
|
|
5
|
+
import { Clone, type CloneProps } from './Clone.three.tsrx';
|
|
6
|
+
|
|
7
|
+
export const useFBX = Object.assign(
|
|
8
|
+
(path: string): Group => useLoader(FBXLoader, path) as unknown as Group,
|
|
9
|
+
{
|
|
10
|
+
preload(path: string) {
|
|
11
|
+
useLoader.preload(FBXLoader, path);
|
|
12
|
+
},
|
|
13
|
+
clear(input: string | string[]) {
|
|
14
|
+
useLoader.clear(FBXLoader, input);
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export function Fbx({ path, ref, ...props }: { path: string; ref?: ThreeRef<Group> } & Omit<
|
|
20
|
+
CloneProps,
|
|
21
|
+
'object'
|
|
22
|
+
>) @{
|
|
23
|
+
const fbx = useFBX(path);
|
|
24
|
+
<Clone ref={ref} {...props} object={fbx.children[0]} />
|
|
25
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** @jsxImportSource @octanejs/three/intrinsics */
|
|
2
|
+
import { type ComputeFunction, type ThreeElements, useFrame, useThree } from '@octanejs/three';
|
|
3
|
+
import { useCallback, useLayoutEffect, useRef, useState, type RefObject } from '@octanejs/three/renderer';
|
|
4
|
+
import type { OctaneNode } from 'octane';
|
|
5
|
+
import * as THREE from 'three';
|
|
6
|
+
import { RenderCubeTexture, type RenderCubeTextureApi } from './RenderCubeTexture.three.tsrx';
|
|
7
|
+
|
|
8
|
+
export type FisheyeProps = ThreeElements['mesh'] & {
|
|
9
|
+
zoom?: number;
|
|
10
|
+
segments?: number;
|
|
11
|
+
resolution?: number;
|
|
12
|
+
children: OctaneNode;
|
|
13
|
+
renderPriority?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function UpdateCubeCamera({ api }: { api: RefObject<RenderCubeTextureApi> }) @{
|
|
17
|
+
const position = new THREE.Vector3();
|
|
18
|
+
const rotation = new THREE.Quaternion();
|
|
19
|
+
const scale = new THREE.Vector3();
|
|
20
|
+
const flip = new THREE.Euler(0, Math.PI, 0);
|
|
21
|
+
useFrame((state) => {
|
|
22
|
+
state.camera.matrixWorld.decompose(position, rotation, scale);
|
|
23
|
+
api.current?.camera.position.copy(position);
|
|
24
|
+
api.current?.camera.quaternion.setFromEuler(flip).premultiply(rotation);
|
|
25
|
+
});
|
|
26
|
+
null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Fisheye({
|
|
30
|
+
renderPriority = 1,
|
|
31
|
+
zoom = 0,
|
|
32
|
+
segments = 64,
|
|
33
|
+
children,
|
|
34
|
+
resolution = 896,
|
|
35
|
+
...props
|
|
36
|
+
}: FisheyeProps) @{
|
|
37
|
+
const sphere = useRef<THREE.Mesh | null>(null);
|
|
38
|
+
const cubeApi = useRef<RenderCubeTextureApi | null>(null);
|
|
39
|
+
const { width, height } = useThree((state) => state.size);
|
|
40
|
+
const [camera] = useState(() => new THREE.OrthographicCamera());
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
camera.position.set(0, 0, 100);
|
|
43
|
+
camera.zoom = 100;
|
|
44
|
+
camera.left = width / -2;
|
|
45
|
+
camera.right = width / 2;
|
|
46
|
+
camera.top = height / 2;
|
|
47
|
+
camera.bottom = height / -2;
|
|
48
|
+
camera.updateProjectionMatrix();
|
|
49
|
+
}, [width, height]);
|
|
50
|
+
const radius = (Math.sqrt(width * width + height * height) / 100) * (0.5 + zoom / 2);
|
|
51
|
+
const normal = new THREE.Vector3();
|
|
52
|
+
const sphereBounds = new THREE.Sphere(new THREE.Vector3(), radius);
|
|
53
|
+
const normalMatrix = new THREE.Matrix3();
|
|
54
|
+
const compute = useCallback<ComputeFunction>((event, state) => {
|
|
55
|
+
state.pointer.set(
|
|
56
|
+
((event as any).offsetX / state.size.width) * 2 - 1,
|
|
57
|
+
-((event as any).offsetY / state.size.height) * 2 + 1,
|
|
58
|
+
);
|
|
59
|
+
state.raycaster.setFromCamera(state.pointer, camera);
|
|
60
|
+
if (!state.raycaster.ray.intersectSphere(sphereBounds, normal)) return;
|
|
61
|
+
normal.normalize();
|
|
62
|
+
const cubeCamera = cubeApi.current?.camera;
|
|
63
|
+
if (!cubeCamera) return;
|
|
64
|
+
normalMatrix.getNormalMatrix(cubeCamera.matrixWorld);
|
|
65
|
+
cubeCamera.getWorldPosition(state.raycaster.ray.origin);
|
|
66
|
+
state.raycaster.ray.direction.set(0, 0, 1).reflect(normal);
|
|
67
|
+
state.raycaster.ray.direction.x *= -1;
|
|
68
|
+
state.raycaster.ray.direction.applyNormalMatrix(normalMatrix).multiplyScalar(-1);
|
|
69
|
+
}, []);
|
|
70
|
+
useFrame((state) => {
|
|
71
|
+
if (renderPriority && sphere.current) state.gl.render(sphere.current as any, camera);
|
|
72
|
+
}, renderPriority);
|
|
73
|
+
<mesh ref={sphere} {...props} scale={radius}>
|
|
74
|
+
<sphereGeometry args={[1, segments, segments]} />
|
|
75
|
+
<meshBasicMaterial>
|
|
76
|
+
<RenderCubeTexture compute={compute} attach="envMap" flip resolution={resolution} ref={cubeApi}>
|
|
77
|
+
{children}
|
|
78
|
+
<UpdateCubeCamera api={cubeApi as RefObject<RenderCubeTextureApi>} />
|
|
79
|
+
</RenderCubeTexture>
|
|
80
|
+
</meshBasicMaterial>
|
|
81
|
+
</mesh>
|
|
82
|
+
}
|