@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,50 @@
1
+ import type { ConstructorRepresentation } from '@octanejs/three';
2
+ import * as THREE from 'three';
3
+ import type { MeshBVHUniformStruct } from 'three-mesh-bvh';
4
+
5
+ type UniformValue =
6
+ | THREE.Texture
7
+ | THREE.TypedArray
8
+ | THREE.Matrix4
9
+ | THREE.Matrix3
10
+ | THREE.Quaternion
11
+ | THREE.Vector4
12
+ | THREE.Vector3
13
+ | THREE.Vector2
14
+ | THREE.Color
15
+ | MeshBVHUniformStruct
16
+ | number
17
+ | boolean
18
+ | null;
19
+
20
+ type Uniforms = Record<string, UniformValue | Record<string, UniformValue> | Array<UniformValue>>;
21
+
22
+ export function shaderMaterial<U extends Uniforms, M extends THREE.ShaderMaterial & U>(
23
+ uniforms: U,
24
+ vertexShader: string,
25
+ fragmentShader: string,
26
+ onInit?: (material?: M) => void,
27
+ ) {
28
+ return class extends THREE.ShaderMaterial {
29
+ static key = THREE.MathUtils.generateUUID();
30
+
31
+ constructor(parameters?: THREE.ShaderMaterialParameters) {
32
+ super({ vertexShader, fragmentShader, ...parameters });
33
+
34
+ for (const key in uniforms) {
35
+ this.uniforms[key] = new THREE.Uniform(uniforms[key]);
36
+ Object.defineProperty(this, key, {
37
+ get() {
38
+ return this.uniforms[key].value;
39
+ },
40
+ set(value) {
41
+ this.uniforms[key].value = value;
42
+ },
43
+ });
44
+ }
45
+ this.uniforms = THREE.UniformsUtils.clone(this.uniforms);
46
+
47
+ onInit?.(this as unknown as M);
48
+ }
49
+ } as unknown as ConstructorRepresentation<M> & { key: string };
50
+ }
@@ -0,0 +1,164 @@
1
+ /** @jsxImportSource @octanejs/three/intrinsics */
2
+ import { type ThreeElements, type ThreeRef, useFrame, useInstanceHandle } from '@octanejs/three';
3
+ import { useLayoutEffect, useMemo, useRef } from '@octanejs/three/renderer';
4
+ import {
5
+ Color,
6
+ DoubleSide,
7
+ type Mesh,
8
+ type MeshBasicMaterial,
9
+ type MeshDepthMaterial,
10
+ type MeshDistanceMaterial,
11
+ type PlaneGeometry,
12
+ RGBADepthPacking,
13
+ type Texture,
14
+ } from 'three';
15
+
16
+ export type ShadowProps =
17
+ Omit<ThreeElements['mesh'], 'ref'> & {
18
+ colorStop?: number;
19
+ fog?: boolean;
20
+ color?: Color | number | string;
21
+ opacity?: number;
22
+ depthWrite?: boolean;
23
+ };
24
+
25
+ export type ShadowType = Mesh<PlaneGeometry, MeshBasicMaterial>;
26
+
27
+ function assignRef<T>(ref: ThreeRef<T> | undefined, value: T | null): void {
28
+ if (Array.isArray(ref)) for (const item of ref) assignRef(item, value);
29
+ else if (typeof ref === 'function') ref(value);
30
+ else if (ref && 'current' in ref) ref.current = value;
31
+ }
32
+
33
+ export function Shadow({
34
+ fog = false,
35
+ renderOrder,
36
+ depthWrite = false,
37
+ colorStop = 0,
38
+ color = 'black',
39
+ opacity = 0.5,
40
+ ref,
41
+ ...props
42
+ }: ShadowProps & { ref?: ThreeRef<ShadowType> }) @{
43
+ const canvas = useMemo(() => {
44
+ const element = document.createElement('canvas');
45
+ element.width = 128;
46
+ element.height = 128;
47
+ const context = element.getContext('2d') as CanvasRenderingContext2D;
48
+ const gradient = context.createRadialGradient(64, 64, 0, 64, 64, 64);
49
+ gradient.addColorStop(colorStop, new Color(color).getStyle());
50
+ gradient.addColorStop(1, 'rgba(0,0,0,0)');
51
+ context.fillStyle = gradient;
52
+ context.fillRect(0, 0, 128, 128);
53
+ return element;
54
+ }, [color, colorStop]);
55
+ const mergedRef = useMemo(() => (value: ShadowType | null) => assignRef(ref, value), [ref]);
56
+ <mesh renderOrder={renderOrder} ref={mergedRef} rotation-x={-Math.PI / 2} {...props}>
57
+ <planeGeometry />
58
+ <meshBasicMaterial
59
+ transparent
60
+ opacity={opacity}
61
+ fog={fog}
62
+ depthWrite={depthWrite}
63
+ side={DoubleSide}
64
+ >
65
+ <canvasTexture attach="map" args={[canvas]} />
66
+ </meshBasicMaterial>
67
+ </mesh>
68
+ }
69
+
70
+ export interface ShadowAlphaProps {
71
+ opacity?: number;
72
+ alphaMap?: Texture | boolean;
73
+ }
74
+
75
+ export function ShadowAlpha({ opacity, alphaMap }: ShadowAlphaProps) @{
76
+ const depthMaterialRef = useRef<MeshDepthMaterial | null>(null);
77
+ const distanceMaterialRef = useRef<MeshDistanceMaterial | null>(null);
78
+ const depthInstance = useInstanceHandle(depthMaterialRef);
79
+ const uShadowOpacity = useRef({ value: 1 });
80
+ const uAlphaMap = useRef<{ value: Texture | null }>({ value: null });
81
+ const uHasAlphaMap = useRef({ value: false });
82
+ useLayoutEffect(() => {
83
+ if (!depthMaterialRef.current || !distanceMaterialRef.current) return;
84
+ depthMaterialRef.current.onBeforeCompile = distanceMaterialRef.current.onBeforeCompile = (
85
+ shader,
86
+ ) => {
87
+ const mainLineStart = shader.fragmentShader.indexOf('void main');
88
+ let mainLine = '';
89
+ let character: string | undefined;
90
+ let index = mainLineStart;
91
+ while (character !== '\n' && index < mainLineStart + 100) {
92
+ character = shader.fragmentShader.charAt(index);
93
+ mainLine += character;
94
+ index++;
95
+ }
96
+ mainLine = mainLine.trim();
97
+ shader.vertexShader = shader.vertexShader.replace(
98
+ 'void main() {',
99
+ `
100
+ varying vec2 custom_vUv;
101
+
102
+ void main() {
103
+ custom_vUv = uv;
104
+ `,
105
+ );
106
+ shader.fragmentShader = shader.fragmentShader.replace(
107
+ mainLine,
108
+ `
109
+ uniform float uShadowOpacity;
110
+ uniform sampler2D uAlphaMap;
111
+ uniform bool uHasAlphaMap;
112
+
113
+ varying vec2 custom_vUv;
114
+
115
+ float bayerDither2x2( vec2 v ) {
116
+ return mod( 3.0 * v.y + 2.0 * v.x, 4.0 );
117
+ }
118
+
119
+ float bayerDither4x4( vec2 v ) {
120
+ vec2 P1 = mod( v, 2.0 );
121
+ vec2 P2 = mod( floor( 0.5 * v ), 2.0 );
122
+ return 4.0 * bayerDither2x2( P1 ) + bayerDither2x2( P2 );
123
+ }
124
+
125
+ void main() {
126
+ float alpha =
127
+ uHasAlphaMap ?
128
+ uShadowOpacity * texture2D(uAlphaMap, custom_vUv).x
129
+ : uShadowOpacity;
130
+
131
+ if( ( bayerDither4x4( floor( mod( gl_FragCoord.xy, 4.0 ) ) ) ) / 16.0 >= alpha ) discard;
132
+ `,
133
+ );
134
+ shader.uniforms.uShadowOpacity = uShadowOpacity.current;
135
+ shader.uniforms.uAlphaMap = uAlphaMap.current;
136
+ shader.uniforms.uHasAlphaMap = uHasAlphaMap.current;
137
+ };
138
+ }, []);
139
+ useFrame(() => {
140
+ const parent = depthInstance.current?.parent?.object as
141
+ | (Mesh & {
142
+ material?: MeshBasicMaterial;
143
+ })
144
+ | undefined;
145
+ const parentMaterial = parent?.material;
146
+ if (!parentMaterial) return;
147
+ uShadowOpacity.current.value = opacity ?? parentMaterial.opacity;
148
+ if (alphaMap === false) {
149
+ uAlphaMap.current.value = null;
150
+ uHasAlphaMap.current.value = false;
151
+ } else {
152
+ uAlphaMap.current.value = (alphaMap || parentMaterial.alphaMap) as Texture | null;
153
+ uHasAlphaMap.current.value = Boolean(uAlphaMap.current.value);
154
+ }
155
+ });
156
+ <>
157
+ <meshDepthMaterial
158
+ ref={depthMaterialRef}
159
+ attach="customDepthMaterial"
160
+ depthPacking={RGBADepthPacking}
161
+ />
162
+ <meshDistanceMaterial ref={distanceMaterialRef} attach="customDistanceMaterial" />
163
+ </>
164
+ }
@@ -0,0 +1,170 @@
1
+ /** @jsxImportSource @octanejs/three/intrinsics */
2
+ import type { ThreeElements, ThreeRef } from '@octanejs/three';
3
+ import { useLayoutEffect, useRef } from '@octanejs/three/renderer';
4
+ import type { OctaneNode } from 'octane';
5
+ import * as THREE from 'three';
6
+
7
+ export type Args<T> = T extends new (...args: any) => any ? ConstructorParameters<T> : T;
8
+ export type ShapeProps<T> = Omit<ThreeElements['mesh'], 'ref' | 'args'> & { args?: Args<T> };
9
+
10
+ type ShapeComponentProps<T> = ShapeProps<T> & { ref?: ThreeRef<THREE.Mesh> };
11
+ type GeometryProps<T> = { args?: Args<T> };
12
+ type GeometryComponent<T> = (props: GeometryProps<T>) => OctaneNode;
13
+
14
+ interface ShapeMeshProps<T> extends ShapeComponentProps<T> {
15
+ Geometry: GeometryComponent<T>;
16
+ effect?: (mesh: THREE.Mesh) => void;
17
+ }
18
+
19
+ function ShapeMesh<T>({
20
+ Geometry,
21
+ args,
22
+ children,
23
+ effect,
24
+ ref,
25
+ key: _key,
26
+ ...props
27
+ }: ShapeMeshProps<T>) @{
28
+ const meshRef = useRef<THREE.Mesh | null>(null);
29
+
30
+ useLayoutEffect(() => {
31
+ if (meshRef.current !== null) effect?.(meshRef.current);
32
+ });
33
+
34
+ <mesh ref={[meshRef, ref ?? null]} {...props}>
35
+ <Geometry args={args} />
36
+ {children}
37
+ </mesh>
38
+ }
39
+
40
+ function BoxGeometry(props: GeometryProps<typeof THREE.BoxGeometry>) @{
41
+ <boxGeometry attach="geometry" args={props.args} />
42
+ }
43
+ function CircleGeometry(props: GeometryProps<typeof THREE.CircleGeometry>) @{
44
+ <circleGeometry attach="geometry" args={props.args} />
45
+ }
46
+ function ConeGeometry(props: GeometryProps<typeof THREE.ConeGeometry>) @{
47
+ <coneGeometry attach="geometry" args={props.args} />
48
+ }
49
+ function CylinderGeometry(props: GeometryProps<typeof THREE.CylinderGeometry>) @{
50
+ <cylinderGeometry attach="geometry" args={props.args} />
51
+ }
52
+ function SphereGeometry(props: GeometryProps<typeof THREE.SphereGeometry>) @{
53
+ <sphereGeometry attach="geometry" args={props.args} />
54
+ }
55
+ function PlaneGeometry(props: GeometryProps<typeof THREE.PlaneGeometry>) @{
56
+ <planeGeometry attach="geometry" args={props.args} />
57
+ }
58
+ function TubeGeometry(props: GeometryProps<typeof THREE.TubeGeometry>) @{
59
+ <tubeGeometry attach="geometry" args={props.args} />
60
+ }
61
+ function TorusGeometry(props: GeometryProps<typeof THREE.TorusGeometry>) @{
62
+ <torusGeometry attach="geometry" args={props.args} />
63
+ }
64
+ function TorusKnotGeometry(props: GeometryProps<typeof THREE.TorusKnotGeometry>) @{
65
+ <torusKnotGeometry attach="geometry" args={props.args} />
66
+ }
67
+ function TetrahedronGeometry(props: GeometryProps<typeof THREE.TetrahedronGeometry>) @{
68
+ <tetrahedronGeometry attach="geometry" args={props.args} />
69
+ }
70
+ function RingGeometry(props: GeometryProps<typeof THREE.RingGeometry>) @{
71
+ <ringGeometry attach="geometry" args={props.args} />
72
+ }
73
+ function PolyhedronGeometry(props: GeometryProps<typeof THREE.PolyhedronGeometry>) @{
74
+ <polyhedronGeometry attach="geometry" args={props.args} />
75
+ }
76
+ function IcosahedronGeometry(props: GeometryProps<typeof THREE.IcosahedronGeometry>) @{
77
+ <icosahedronGeometry attach="geometry" args={props.args} />
78
+ }
79
+ function OctahedronGeometry(props: GeometryProps<typeof THREE.OctahedronGeometry>) @{
80
+ <octahedronGeometry attach="geometry" args={props.args} />
81
+ }
82
+ function DodecahedronGeometry(props: GeometryProps<typeof THREE.DodecahedronGeometry>) @{
83
+ <dodecahedronGeometry attach="geometry" args={props.args} />
84
+ }
85
+ function ExtrudeGeometry(props: GeometryProps<typeof THREE.ExtrudeGeometry>) @{
86
+ <extrudeGeometry attach="geometry" args={props.args} />
87
+ }
88
+ function LatheGeometry(props: GeometryProps<typeof THREE.LatheGeometry>) @{
89
+ <latheGeometry attach="geometry" args={props.args} />
90
+ }
91
+ function CapsuleGeometry(props: GeometryProps<typeof THREE.CapsuleGeometry>) @{
92
+ <capsuleGeometry attach="geometry" args={props.args} />
93
+ }
94
+ function ShapeGeometry(props: GeometryProps<typeof THREE.ShapeGeometry>) @{
95
+ <shapeGeometry attach="geometry" args={props.args} />
96
+ }
97
+
98
+ export function Box(props: ShapeComponentProps<typeof THREE.BoxGeometry>) @{
99
+ <ShapeMesh {...props} Geometry={BoxGeometry} />
100
+ }
101
+ export function Circle(props: ShapeComponentProps<typeof THREE.CircleGeometry>) @{
102
+ <ShapeMesh {...props} Geometry={CircleGeometry} />
103
+ }
104
+ export function Cone(props: ShapeComponentProps<typeof THREE.ConeGeometry>) @{
105
+ <ShapeMesh {...props} Geometry={ConeGeometry} />
106
+ }
107
+ export function Cylinder(props: ShapeComponentProps<typeof THREE.CylinderGeometry>) @{
108
+ <ShapeMesh {...props} Geometry={CylinderGeometry} />
109
+ }
110
+ export function Sphere(props: ShapeComponentProps<typeof THREE.SphereGeometry>) @{
111
+ <ShapeMesh {...props} Geometry={SphereGeometry} />
112
+ }
113
+ export function Plane(props: ShapeComponentProps<typeof THREE.PlaneGeometry>) @{
114
+ <ShapeMesh {...props} Geometry={PlaneGeometry} />
115
+ }
116
+ export function Tube(props: ShapeComponentProps<typeof THREE.TubeGeometry>) @{
117
+ <ShapeMesh {...props} Geometry={TubeGeometry} />
118
+ }
119
+ export function Torus(props: ShapeComponentProps<typeof THREE.TorusGeometry>) @{
120
+ <ShapeMesh {...props} Geometry={TorusGeometry} />
121
+ }
122
+ export function TorusKnot(props: ShapeComponentProps<typeof THREE.TorusKnotGeometry>) @{
123
+ <ShapeMesh {...props} Geometry={TorusKnotGeometry} />
124
+ }
125
+ export function Tetrahedron(props: ShapeComponentProps<typeof THREE.TetrahedronGeometry>) @{
126
+ <ShapeMesh {...props} Geometry={TetrahedronGeometry} />
127
+ }
128
+ export function Ring(props: ShapeComponentProps<typeof THREE.RingGeometry>) @{
129
+ <ShapeMesh {...props} Geometry={RingGeometry} />
130
+ }
131
+ export function Polyhedron(props: ShapeComponentProps<typeof THREE.PolyhedronGeometry>) @{
132
+ <ShapeMesh {...props} Geometry={PolyhedronGeometry} />
133
+ }
134
+ export function Icosahedron(props: ShapeComponentProps<typeof THREE.IcosahedronGeometry>) @{
135
+ <ShapeMesh {...props} Geometry={IcosahedronGeometry} />
136
+ }
137
+ export function Octahedron(props: ShapeComponentProps<typeof THREE.OctahedronGeometry>) @{
138
+ <ShapeMesh {...props} Geometry={OctahedronGeometry} />
139
+ }
140
+ export function Dodecahedron(props: ShapeComponentProps<typeof THREE.DodecahedronGeometry>) @{
141
+ <ShapeMesh {...props} Geometry={DodecahedronGeometry} />
142
+ }
143
+ export function Extrude(props: ShapeComponentProps<typeof THREE.ExtrudeGeometry>) @{
144
+ <ShapeMesh {...props} Geometry={ExtrudeGeometry} />
145
+ }
146
+ export function Lathe(props: ShapeComponentProps<typeof THREE.LatheGeometry>) @{
147
+ <ShapeMesh {...props} Geometry={LatheGeometry} />
148
+ }
149
+ export function Capsule(props: ShapeComponentProps<typeof THREE.CapsuleGeometry>) @{
150
+ <ShapeMesh {...props} Geometry={CapsuleGeometry} />
151
+ }
152
+
153
+ function updateShapeUvs({ geometry }: THREE.Mesh): void {
154
+ // Calculate UVs (by https://discourse.threejs.org/u/prisoner849).
155
+ const pos = geometry.attributes.position as THREE.BufferAttribute;
156
+ const bounds = new THREE.Box3().setFromBufferAttribute(pos);
157
+ const size = new THREE.Vector3();
158
+ bounds.getSize(size);
159
+ const uv: number[] = [];
160
+
161
+ for (let index = 0; index < pos.count; index++) {
162
+ uv.push((pos.getX(index) - bounds.min.x) / size.x, (pos.getY(index) - bounds.min.y) / size.y);
163
+ }
164
+
165
+ geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
166
+ }
167
+
168
+ export function Shape(props: ShapeComponentProps<typeof THREE.ShapeGeometry>) @{
169
+ <ShapeMesh {...props} Geometry={ShapeGeometry} effect={updateShapeUvs} />
170
+ }
@@ -0,0 +1,124 @@
1
+ /** @jsxImportSource @octanejs/three/intrinsics */
2
+ import type { ThreeElements, ThreeRef } from '@octanejs/three';
3
+ import { useLayoutEffect, useMemo, useRef, useState } from '@octanejs/three/renderer';
4
+ import * as THREE from 'three';
5
+ import { slotDefault } from './compiler-slot.js';
6
+ import { shaderMaterial } from './shaderMaterial.js';
7
+
8
+ export const DiscardMaterialImpl = shaderMaterial(
9
+ {},
10
+ 'void main() { }',
11
+ 'void main() { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); discard; }',
12
+ );
13
+
14
+ export type MeshDiscardMaterialProps = Omit<ThreeElements['shaderMaterial'], 'ref'>;
15
+
16
+ export function MeshDiscardMaterial({ ref, ...props }: MeshDiscardMaterialProps & {
17
+ ref?: ThreeRef<THREE.ShaderMaterial>;
18
+ }) @{
19
+ const [material] = useState(() => new DiscardMaterialImpl());
20
+ <primitive object={material} ref={ref as any} attach="material" {...props as any} />
21
+ }
22
+
23
+ const opaqueFragment =
24
+ Number.parseInt(THREE.REVISION, 10) >= 154 ? 'opaque_fragment' : 'output_fragment';
25
+
26
+ export class PointMaterialImpl extends THREE.PointsMaterial {
27
+ constructor(props?: THREE.PointsMaterialParameters | null) {
28
+ super(props ?? undefined);
29
+ this.onBeforeCompile = (shader, renderer) => {
30
+ const { isWebGL2 } = renderer.capabilities;
31
+ shader.fragmentShader = shader.fragmentShader.replace(
32
+ `#include <${opaqueFragment}>`,
33
+ `
34
+ ${
35
+ !isWebGL2
36
+ ? `#extension GL_OES_standard_derivatives : enable\n#include <${opaqueFragment}>`
37
+ : `#include <${opaqueFragment}>`
38
+ }
39
+ vec2 cxy = 2.0 * gl_PointCoord - 1.0;
40
+ float r = dot(cxy, cxy);
41
+ float delta = fwidth(r);
42
+ float mask = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
43
+ gl_FragColor = vec4(gl_FragColor.rgb, mask * gl_FragColor.a );
44
+ #include <tonemapping_fragment>
45
+ #include <${
46
+ Number.parseInt(THREE.REVISION, 10) >= 154 ? 'colorspace_fragment' : 'encodings_fragment'
47
+ }>
48
+ `,
49
+ );
50
+ };
51
+ }
52
+ }
53
+
54
+ export type PointMaterialProps = Omit<ThreeElements['pointsMaterial'], 'ref'>;
55
+
56
+ export function PointMaterial({ ref, ...props }: PointMaterialProps & {
57
+ ref?: ThreeRef<PointMaterialImpl>;
58
+ }) @{
59
+ const [material] = useState(() => new PointMaterialImpl(null));
60
+ <primitive object={material} ref={ref as any} attach="material" {...props as any} />
61
+ }
62
+
63
+ function createScreenQuadGeometry() {
64
+ const geometry = new THREE.BufferGeometry();
65
+ const vertices = new Float32Array([-1, -1, 3, -1, -1, 3]);
66
+ geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(), Infinity);
67
+ geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 2));
68
+ return geometry;
69
+ }
70
+
71
+ export type ScreenQuadProps = Omit<ThreeElements['mesh'], 'ref' | 'args'>;
72
+
73
+ export function ScreenQuad({ children, ref, ...props }: ScreenQuadProps & {
74
+ ref?: ThreeRef<THREE.Mesh>;
75
+ }) @{
76
+ const geometry = useMemo(createScreenQuadGeometry, []);
77
+ <mesh ref={ref as any} geometry={geometry} frustumCulled={false} {...props}>{children}</mesh>
78
+ }
79
+
80
+ export type MaskProps =
81
+ Omit<ThreeElements['mesh'], 'ref' | 'id'> & {
82
+ id: number;
83
+ colorWrite?: boolean;
84
+ depthWrite?: boolean;
85
+ };
86
+
87
+ export function Mask({
88
+ id = 1,
89
+ colorWrite = false,
90
+ depthWrite = false,
91
+ ref,
92
+ ...props
93
+ }: MaskProps & { ref?: ThreeRef<THREE.Mesh> }) @{
94
+ const localRef = useRef<THREE.Mesh | null>(null);
95
+ const spread = useMemo(
96
+ () => ({
97
+ colorWrite,
98
+ depthWrite,
99
+ stencilWrite: true,
100
+ stencilRef: id,
101
+ stencilFunc: THREE.AlwaysStencilFunc,
102
+ stencilFail: THREE.ReplaceStencilOp,
103
+ stencilZFail: THREE.ReplaceStencilOp,
104
+ stencilZPass: THREE.ReplaceStencilOp,
105
+ }),
106
+ [id, colorWrite, depthWrite],
107
+ );
108
+ useLayoutEffect(() => {
109
+ if (localRef.current) Object.assign(localRef.current.material, spread);
110
+ });
111
+ <mesh ref={[localRef, ref ?? null]} renderOrder={-id} {...props} />
112
+ }
113
+
114
+ export function useMask(id: number, inverse = false) {
115
+ inverse = slotDefault(inverse, false);
116
+ return {
117
+ stencilWrite: true,
118
+ stencilRef: id,
119
+ stencilFunc: inverse ? THREE.NotEqualStencilFunc : THREE.EqualStencilFunc,
120
+ stencilFail: THREE.KeepStencilOp,
121
+ stencilZFail: THREE.KeepStencilOp,
122
+ stencilZPass: THREE.KeepStencilOp,
123
+ };
124
+ }
@@ -0,0 +1,151 @@
1
+ /** @jsxImportSource @octanejs/three/intrinsics */
2
+ import { useThree } from '@octanejs/three';
3
+ import { useEffect } from '@octanejs/three/renderer';
4
+ import * as THREE from 'three';
5
+
6
+ export type SoftShadowsProps = {
7
+ size?: number;
8
+ samples?: number;
9
+ focus?: number;
10
+ };
11
+
12
+ const pcss = ({ focus = 0, size = 25, samples = 10 }: SoftShadowsProps = {}) => `
13
+ #define PENUMBRA_FILTER_SIZE float(${size})
14
+ #define RGB_NOISE_FUNCTION(uv) (randRGB(uv))
15
+ vec3 randRGB(vec2 uv) {
16
+ return vec3(
17
+ fract(sin(dot(uv, vec2(12.75613, 38.12123))) * 13234.76575),
18
+ fract(sin(dot(uv, vec2(19.45531, 58.46547))) * 43678.23431),
19
+ fract(sin(dot(uv, vec2(23.67817, 78.23121))) * 93567.23423)
20
+ );
21
+ }
22
+
23
+ vec3 lowPassRandRGB(vec2 uv) {
24
+ // 3x3 convolution (average)
25
+ // can be implemented as separable with an extra buffer for a total of 6 samples instead of 9
26
+ vec3 result = vec3(0);
27
+ result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, -1.0));
28
+ result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, 0.0));
29
+ result += RGB_NOISE_FUNCTION(uv + vec2(-1.0, +1.0));
30
+ result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, -1.0));
31
+ result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, 0.0));
32
+ result += RGB_NOISE_FUNCTION(uv + vec2( 0.0, +1.0));
33
+ result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, -1.0));
34
+ result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, 0.0));
35
+ result += RGB_NOISE_FUNCTION(uv + vec2(+1.0, +1.0));
36
+ result *= 0.111111111; // 1.0 / 9.0
37
+ return result;
38
+ }
39
+ vec3 highPassRandRGB(vec2 uv) {
40
+ // by subtracting the low-pass signal from the original signal, we're being left with the high-pass signal
41
+ // hp(x) = x - lp(x)
42
+ return RGB_NOISE_FUNCTION(uv) - lowPassRandRGB(uv) + 0.5;
43
+ }
44
+
45
+
46
+ vec2 vogelDiskSample(int sampleIndex, int sampleCount, float angle) {
47
+ const float goldenAngle = 2.399963f; // radians
48
+ float r = sqrt(float(sampleIndex) + 0.5f) / sqrt(float(sampleCount));
49
+ float theta = float(sampleIndex) * goldenAngle + angle;
50
+ float sine = sin(theta);
51
+ float cosine = cos(theta);
52
+ return vec2(cosine, sine) * r;
53
+ }
54
+ float penumbraSize( const in float zReceiver, const in float zBlocker ) { // Parallel plane estimation
55
+ return (zReceiver - zBlocker) / zBlocker;
56
+ }
57
+ float findBlocker(sampler2D shadowMap, vec2 uv, float compare, float angle) {
58
+ float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
59
+ float blockerDepthSum = float(${focus});
60
+ float blockers = 0.0;
61
+
62
+ int j = 0;
63
+ vec2 offset = vec2(0.);
64
+ float depth = 0.;
65
+
66
+ #pragma unroll_loop_start
67
+ for(int i = 0; i < ${samples}; i ++) {
68
+ offset = (vogelDiskSample(j, ${samples}, angle) * texelSize) * 2.0 * PENUMBRA_FILTER_SIZE;
69
+ depth = unpackRGBAToDepth( texture2D( shadowMap, uv + offset));
70
+ if (depth < compare) {
71
+ blockerDepthSum += depth;
72
+ blockers++;
73
+ }
74
+ j++;
75
+ }
76
+ #pragma unroll_loop_end
77
+
78
+ if (blockers > 0.0) {
79
+ return blockerDepthSum / blockers;
80
+ }
81
+ return -1.0;
82
+ }
83
+
84
+
85
+ float vogelFilter(sampler2D shadowMap, vec2 uv, float zReceiver, float filterRadius, float angle) {
86
+ float texelSize = 1.0 / float(textureSize(shadowMap, 0).x);
87
+ float shadow = 0.0f;
88
+ int j = 0;
89
+ vec2 vogelSample = vec2(0.0);
90
+ vec2 offset = vec2(0.0);
91
+ #pragma unroll_loop_start
92
+ for (int i = 0; i < ${samples}; i++) {
93
+ vogelSample = vogelDiskSample(j, ${samples}, angle) * texelSize;
94
+ offset = vogelSample * (1.0 + filterRadius * float(${size}));
95
+ shadow += step( zReceiver, unpackRGBAToDepth( texture2D( shadowMap, uv + offset ) ) );
96
+ j++;
97
+ }
98
+ #pragma unroll_loop_end
99
+ return shadow * 1.0 / ${samples}.0;
100
+ }
101
+
102
+ float PCSS (sampler2D shadowMap, vec4 coords) {
103
+ vec2 uv = coords.xy;
104
+ float zReceiver = coords.z; // Assumed to be eye-space z in this code
105
+ float angle = highPassRandRGB(gl_FragCoord.xy).r * PI2;
106
+ float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver, angle);
107
+ if (avgBlockerDepth == -1.0) {
108
+ return 1.0;
109
+ }
110
+ float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);
111
+ return vogelFilter(shadowMap, uv, zReceiver, 1.25 * penumbraRatio, angle);
112
+ }`;
113
+
114
+ type ResetRenderer = {
115
+ properties: { remove(material: THREE.Material): void };
116
+ info: { programs: unknown[] };
117
+ compile(scene: THREE.Object3D, camera: THREE.Camera): void;
118
+ };
119
+
120
+ function reset(gl: ResetRenderer, scene: THREE.Scene, camera: THREE.Camera): void {
121
+ scene.traverse((object) => {
122
+ const material = (object as THREE.Mesh).material;
123
+ if (material) {
124
+ gl.properties.remove(material as unknown as THREE.Material);
125
+ (material as THREE.Material).dispose?.();
126
+ }
127
+ });
128
+ gl.info.programs.length = 0;
129
+ gl.compile(scene, camera);
130
+ }
131
+
132
+ export function SoftShadows({ focus = 0, samples = 10, size = 25 }: SoftShadowsProps) @{
133
+ const gl = useThree((state) => state.gl) as unknown as ResetRenderer;
134
+ const scene = useThree((state) => state.scene) as unknown as THREE.Scene;
135
+ const camera = useThree((state) => state.camera) as unknown as THREE.Camera;
136
+ useEffect(() => {
137
+ const original = THREE.ShaderChunk.shadowmap_pars_fragment;
138
+ THREE.ShaderChunk.shadowmap_pars_fragment = THREE.ShaderChunk.shadowmap_pars_fragment
139
+ .replace('#ifdef USE_SHADOWMAP', `#ifdef USE_SHADOWMAP\n${pcss({ size, samples, focus })}`)
140
+ .replace(
141
+ '#if defined( SHADOWMAP_TYPE_PCF )',
142
+ '\nreturn PCSS(shadowMap, shadowCoord);\n#if defined( SHADOWMAP_TYPE_PCF )',
143
+ );
144
+ reset(gl, scene, camera);
145
+ return () => {
146
+ THREE.ShaderChunk.shadowmap_pars_fragment = original;
147
+ reset(gl, scene, camera);
148
+ };
149
+ }, [focus, size, samples]);
150
+ null;
151
+ }