@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,182 @@
1
+ import * as THREE from 'three';
2
+
3
+ interface Uniform<T> {
4
+ value: T;
5
+ }
6
+ interface Shader {
7
+ uniforms: Record<string, Uniform<any>>;
8
+ defines: Record<string, string>;
9
+ vertexShader: string;
10
+ fragmentShader: string;
11
+ }
12
+
13
+ export class MeshTransmissionMaterialImpl extends THREE.MeshPhysicalMaterial {
14
+ uniforms: Record<string, Uniform<any>>;
15
+
16
+ constructor(samples = 6, transmissionSampler = false) {
17
+ super();
18
+ this.uniforms = {
19
+ chromaticAberration: { value: 0.05 },
20
+ transmission: { value: 0 },
21
+ _transmission: { value: 1 },
22
+ transmissionMap: { value: null },
23
+ roughness: { value: 0 },
24
+ thickness: { value: 0 },
25
+ thicknessMap: { value: null },
26
+ attenuationDistance: { value: Infinity },
27
+ attenuationColor: { value: new THREE.Color('white') },
28
+ anisotropicBlur: { value: 0.1 },
29
+ time: { value: 0 },
30
+ distortion: { value: 0 },
31
+ distortionScale: { value: 0.5 },
32
+ temporalDistortion: { value: 0 },
33
+ buffer: { value: null },
34
+ };
35
+ this.onBeforeCompile = (parameters) => {
36
+ const shader = parameters as unknown as Shader;
37
+ shader.defines ||= {};
38
+ shader.uniforms = { ...shader.uniforms, ...this.uniforms };
39
+ if ((this as any).anisotropy > 0) shader.defines.USE_ANISOTROPY = '';
40
+ if (transmissionSampler) shader.defines.USE_SAMPLER = '';
41
+ else shader.defines.USE_TRANSMISSION = '';
42
+ shader.fragmentShader =
43
+ `
44
+ uniform float chromaticAberration;
45
+ uniform float anisotropicBlur;
46
+ uniform float time;
47
+ uniform float distortion;
48
+ uniform float distortionScale;
49
+ uniform float temporalDistortion;
50
+ uniform sampler2D buffer;
51
+ vec3 random3(vec3 c) {
52
+ float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));
53
+ vec3 r; r.z = fract(512.0*j); j *= .125; r.x = fract(512.0*j); j *= .125; r.y = fract(512.0*j); return r-0.5;
54
+ }
55
+ uint hash(uint x) { x += (x << 10u); x ^= (x >> 6u); x += (x << 3u); x ^= (x >> 11u); x += (x << 15u); return x; }
56
+ uint hash(uvec2 v) { return hash(v.x ^ hash(v.y)); }
57
+ uint hash(uvec3 v) { return hash(v.x ^ hash(v.y) ^ hash(v.z)); }
58
+ uint hash(uvec4 v) { return hash(v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w)); }
59
+ float floatConstruct(uint m) {
60
+ const uint ieeeMantissa = 0x007FFFFFu; const uint ieeeOne = 0x3F800000u;
61
+ m &= ieeeMantissa; m |= ieeeOne; float f = uintBitsToFloat(m); return f - 1.0;
62
+ }
63
+ float randomBase(float x) { return floatConstruct(hash(floatBitsToUint(x))); }
64
+ float randomBase(vec2 v) { return floatConstruct(hash(floatBitsToUint(v))); }
65
+ float randomBase(vec3 v) { return floatConstruct(hash(floatBitsToUint(v))); }
66
+ float randomBase(vec4 v) { return floatConstruct(hash(floatBitsToUint(v))); }
67
+ float rand(float seed) { return randomBase(vec3(gl_FragCoord.xy, seed)); }
68
+ const float F3 = 0.3333333; const float G3 = 0.1666667;
69
+ float snoise(vec3 p) {
70
+ vec3 s = floor(p + dot(p, vec3(F3))); vec3 x = p - s + dot(s, vec3(G3)); vec3 e = step(vec3(0.0), x - x.yzx);
71
+ vec3 i1 = e*(1.0 - e.zxy); vec3 i2 = 1.0 - e.zxy*(1.0 - e); vec3 x1 = x - i1 + G3; vec3 x2 = x - i2 + 2.0*G3; vec3 x3 = x - 1.0 + 3.0*G3;
72
+ vec4 w, d; w.x = dot(x, x); w.y = dot(x1, x1); w.z = dot(x2, x2); w.w = dot(x3, x3); w = max(0.6 - w, 0.0);
73
+ d.x = dot(random3(s), x); d.y = dot(random3(s + i1), x1); d.z = dot(random3(s + i2), x2); d.w = dot(random3(s + 1.0), x3);
74
+ w *= w; w *= w; d *= w; return dot(d, vec4(52.0));
75
+ }
76
+ float snoiseFractal(vec3 m) { return 0.5333333*snoise(m) + 0.2666667*snoise(2.0*m) + 0.1333333*snoise(4.0*m) + 0.0666667*snoise(8.0*m); }
77
+ ` + shader.fragmentShader;
78
+ shader.fragmentShader = shader.fragmentShader.replace(
79
+ '#include <transmission_pars_fragment>',
80
+ `
81
+ #ifdef USE_TRANSMISSION
82
+ uniform float _transmission;
83
+ uniform float thickness;
84
+ uniform float attenuationDistance;
85
+ uniform vec3 attenuationColor;
86
+ #ifdef USE_TRANSMISSIONMAP
87
+ uniform sampler2D transmissionMap;
88
+ #endif
89
+ #ifdef USE_THICKNESSMAP
90
+ uniform sampler2D thicknessMap;
91
+ #endif
92
+ uniform vec2 transmissionSamplerSize;
93
+ uniform sampler2D transmissionSamplerMap;
94
+ uniform mat4 modelMatrix;
95
+ uniform mat4 projectionMatrix;
96
+ varying vec3 vWorldPosition;
97
+ vec3 getVolumeTransmissionRay(const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix) {
98
+ vec3 refractionVector = refract(-v, normalize(n), 1.0 / ior);
99
+ vec3 modelScale; modelScale.x = length(vec3(modelMatrix[0].xyz)); modelScale.y = length(vec3(modelMatrix[1].xyz)); modelScale.z = length(vec3(modelMatrix[2].xyz));
100
+ return normalize(refractionVector) * thickness * modelScale;
101
+ }
102
+ float applyIorToRoughness(const in float roughness, const in float ior) { return roughness * clamp(ior * 2.0 - 2.0, 0.0, 1.0); }
103
+ vec4 getTransmissionSample(const in vec2 fragCoord, const in float roughness, const in float ior) {
104
+ float framebufferLod = log2(transmissionSamplerSize.x) * applyIorToRoughness(roughness, ior);
105
+ #ifdef USE_SAMPLER
106
+ #ifdef texture2DLodEXT
107
+ return texture2DLodEXT(transmissionSamplerMap, fragCoord.xy, framebufferLod);
108
+ #else
109
+ return texture2D(transmissionSamplerMap, fragCoord.xy, framebufferLod);
110
+ #endif
111
+ #else
112
+ return texture2D(buffer, fragCoord.xy);
113
+ #endif
114
+ }
115
+ vec3 applyVolumeAttenuation(const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance) {
116
+ if (isinf(attenuationDistance)) return radiance;
117
+ vec3 attenuationCoefficient = -log(attenuationColor) / attenuationDistance;
118
+ vec3 transmittance = exp(-attenuationCoefficient * transmissionDistance);
119
+ return transmittance * radiance;
120
+ }
121
+ vec4 getIBLVolumeRefraction(const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,
122
+ const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,
123
+ const in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,
124
+ const in vec3 attenuationColor, const in float attenuationDistance) {
125
+ vec3 transmissionRay = getVolumeTransmissionRay(n, v, thickness, ior, modelMatrix);
126
+ vec3 refractedRayExit = position + transmissionRay;
127
+ vec4 ndcPos = projMatrix * viewMatrix * vec4(refractedRayExit, 1.0);
128
+ vec2 refractionCoords = ndcPos.xy / ndcPos.w; refractionCoords += 1.0; refractionCoords /= 2.0;
129
+ vec4 transmittedLight = getTransmissionSample(refractionCoords, roughness, ior);
130
+ vec3 attenuatedColor = applyVolumeAttenuation(transmittedLight.rgb, length(transmissionRay), attenuationColor, attenuationDistance);
131
+ vec3 F = EnvironmentBRDF(n, v, specularColor, specularF90, roughness);
132
+ return vec4((1.0 - F) * attenuatedColor * diffuseColor, transmittedLight.a);
133
+ }
134
+ #endif
135
+ `,
136
+ );
137
+ shader.fragmentShader = shader.fragmentShader.replace(
138
+ '#include <transmission_fragment>',
139
+ `
140
+ material.transmission = _transmission;
141
+ material.transmissionAlpha = 1.0;
142
+ material.thickness = thickness;
143
+ material.attenuationDistance = attenuationDistance;
144
+ material.attenuationColor = attenuationColor;
145
+ #ifdef USE_TRANSMISSIONMAP
146
+ material.transmission *= texture2D(transmissionMap, vUv).r;
147
+ #endif
148
+ #ifdef USE_THICKNESSMAP
149
+ material.thickness *= texture2D(thicknessMap, vUv).g;
150
+ #endif
151
+ vec3 pos = vWorldPosition;
152
+ float runningSeed = 0.0;
153
+ vec3 v = normalize(cameraPosition - pos);
154
+ vec3 n = inverseTransformDirection(normal, viewMatrix);
155
+ vec3 transmission = vec3(0.0);
156
+ float transmissionR, transmissionB, transmissionG;
157
+ float randomCoords = rand(runningSeed++);
158
+ float thickness_smear = thickness * max(pow(roughnessFactor, 0.33), anisotropicBlur);
159
+ vec3 distortionNormal = vec3(0.0);
160
+ vec3 temporalOffset = vec3(time, -time, -time) * temporalDistortion;
161
+ if (distortion > 0.0) distortionNormal = distortion * vec3(snoiseFractal(vec3(pos * distortionScale + temporalOffset)), snoiseFractal(vec3(pos.zxy * distortionScale - temporalOffset)), snoiseFractal(vec3(pos.yxz * distortionScale + temporalOffset)));
162
+ for (float i = 0.0; i < ${samples}.0; i++) {
163
+ vec3 sampleNorm = normalize(n + roughnessFactor * roughnessFactor * 2.0 * normalize(vec3(rand(runningSeed++) - 0.5, rand(runningSeed++) - 0.5, rand(runningSeed++) - 0.5)) * pow(rand(runningSeed++), 0.33) + distortionNormal);
164
+ transmissionR = getIBLVolumeRefraction(sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, pos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness + thickness_smear * (i + randomCoords) / float(${samples}), material.attenuationColor, material.attenuationDistance).r;
165
+ transmissionG = getIBLVolumeRefraction(sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + chromaticAberration * (i + randomCoords) / float(${samples})), material.thickness + thickness_smear * (i + randomCoords) / float(${samples}), material.attenuationColor, material.attenuationDistance).g;
166
+ transmissionB = getIBLVolumeRefraction(sampleNorm, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, pos, modelMatrix, viewMatrix, projectionMatrix, material.ior * (1.0 + 2.0 * chromaticAberration * (i + randomCoords) / float(${samples})), material.thickness + thickness_smear * (i + randomCoords) / float(${samples}), material.attenuationColor, material.attenuationDistance).b;
167
+ transmission.r += transmissionR; transmission.g += transmissionG; transmission.b += transmissionB;
168
+ }
169
+ transmission /= ${samples}.0;
170
+ totalDiffuse = mix(totalDiffuse, transmission.rgb, material.transmission);
171
+ `,
172
+ );
173
+ };
174
+ for (const name of Object.keys(this.uniforms))
175
+ Object.defineProperty(this, name, {
176
+ get: () => this.uniforms[name].value,
177
+ set: (value) => {
178
+ this.uniforms[name].value = value;
179
+ },
180
+ });
181
+ }
182
+ }
@@ -0,0 +1,38 @@
1
+ import * as THREE from 'three';
2
+ import { shaderMaterial } from '../core/shaderMaterial.js';
3
+
4
+ export const PortalMaterialImpl = shaderMaterial(
5
+ { blur: 0, map: null, sdf: null, blend: 0, size: 0, resolution: new THREE.Vector2() },
6
+ `varying vec2 vUv;
7
+ void main() {
8
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
9
+ vUv = uv;
10
+ }`,
11
+ `uniform sampler2D sdf;
12
+ uniform sampler2D map;
13
+ uniform float blur;
14
+ uniform float size;
15
+ uniform float time;
16
+ uniform vec2 resolution;
17
+ varying vec2 vUv;
18
+ #include <packing>
19
+ void main() {
20
+ vec2 uv = gl_FragCoord.xy / resolution.xy;
21
+ vec4 t = texture2D(map, uv);
22
+ float k = blur;
23
+ float d = texture2D(sdf, vUv).r/size;
24
+ float alpha = 1.0 - smoothstep(0.0, 1.0, clamp(d/k + 1.0, 0.0, 1.0));
25
+ gl_FragColor = vec4(t.rgb, blur == 0.0 ? t.a : t.a * alpha);
26
+ #include <tonemapping_fragment>
27
+ #include <colorspace_fragment>
28
+ }`,
29
+ );
30
+
31
+ export type PortalMaterialInstance = InstanceType<typeof PortalMaterialImpl> & {
32
+ blur: number;
33
+ blend: number;
34
+ size: number;
35
+ resolution: THREE.Vector2;
36
+ sdf: THREE.Texture | null;
37
+ map: THREE.Texture | null;
38
+ };
@@ -0,0 +1,241 @@
1
+ import { useEffect } from '@octanejs/three/renderer';
2
+ import * as THREE from 'three';
3
+ import { shaderMaterial } from '../core/shaderMaterial.js';
4
+
5
+ export interface WireframeMaterialProps extends THREE.ShaderMaterialParameters {
6
+ fillOpacity?: number;
7
+ fillMix?: number;
8
+ strokeOpacity?: number;
9
+ thickness?: number;
10
+ colorBackfaces?: boolean;
11
+ dashInvert?: boolean;
12
+ dash?: boolean;
13
+ dashRepeats?: number;
14
+ dashLength?: number;
15
+ squeeze?: boolean;
16
+ squeezeMin?: number;
17
+ squeezeMax?: number;
18
+ stroke?: THREE.ColorRepresentation;
19
+ backfaceStroke?: THREE.ColorRepresentation;
20
+ fill?: THREE.ColorRepresentation;
21
+ }
22
+
23
+ export const WireframeMaterialShaders = {
24
+ uniforms: {
25
+ strokeOpacity: 1,
26
+ fillOpacity: 0.25,
27
+ fillMix: 0,
28
+ thickness: 0.05,
29
+ colorBackfaces: false,
30
+ dashInvert: true,
31
+ dash: false,
32
+ dashRepeats: 4,
33
+ dashLength: 0.5,
34
+ squeeze: false,
35
+ squeezeMin: 0.2,
36
+ squeezeMax: 1,
37
+ stroke: new THREE.Color('#ff0000'),
38
+ backfaceStroke: new THREE.Color('#0000ff'),
39
+ fill: new THREE.Color('#00ff00'),
40
+ },
41
+ vertex: `
42
+ attribute vec3 barycentric;
43
+ varying vec3 v_edges_Barycentric;
44
+ varying vec3 v_edges_Position;
45
+ void initWireframe() {
46
+ v_edges_Barycentric = barycentric;
47
+ v_edges_Position = position.xyz;
48
+ }
49
+ `,
50
+ fragment: `
51
+ #ifndef PI
52
+ #define PI 3.1415926535897932384626433832795
53
+ #endif
54
+ varying vec3 v_edges_Barycentric;
55
+ varying vec3 v_edges_Position;
56
+ uniform float strokeOpacity;
57
+ uniform float fillOpacity;
58
+ uniform float fillMix;
59
+ uniform float thickness;
60
+ uniform bool colorBackfaces;
61
+ // Dash
62
+ uniform bool dashInvert;
63
+ uniform bool dash;
64
+ uniform bool dashOnly;
65
+ uniform float dashRepeats;
66
+ uniform float dashLength;
67
+ // Squeeze
68
+ uniform bool squeeze;
69
+ uniform float squeezeMin;
70
+ uniform float squeezeMax;
71
+ // Colors
72
+ uniform vec3 stroke;
73
+ uniform vec3 backfaceStroke;
74
+ uniform vec3 fill;
75
+ // This is like
76
+ float wireframe_aastep(float threshold, float dist) {
77
+ float afwidth = fwidth(dist) * 0.5;
78
+ return smoothstep(threshold - afwidth, threshold + afwidth, dist);
79
+ }
80
+ float wireframe_map(float value, float min1, float max1, float min2, float max2) {
81
+ return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
82
+ }
83
+ float getWireframe() {
84
+ vec3 barycentric = v_edges_Barycentric;
85
+ // Distance from center of each triangle to its edges.
86
+ float d = min(min(barycentric.x, barycentric.y), barycentric.z);
87
+ // for dashed rendering, we can use this to get the 0 .. 1 value of the line length
88
+ float positionAlong = max(barycentric.x, barycentric.y);
89
+ if (barycentric.y < barycentric.x && barycentric.y < barycentric.z) {
90
+ positionAlong = 1.0 - positionAlong;
91
+ }
92
+ // the thickness of the stroke
93
+ float computedThickness = wireframe_map(thickness, 0.0, 1.0, 0.0, 0.34);
94
+ // if we want to shrink the thickness toward the center of the line segment
95
+ if (squeeze) {
96
+ computedThickness *= mix(squeezeMin, squeezeMax, (1.0 - sin(positionAlong * PI)));
97
+ }
98
+ // Create dash pattern
99
+ if (dash) {
100
+ // here we offset the stroke position depending on whether it
101
+ // should overlap or not
102
+ float offset = 1.0 / dashRepeats * dashLength / 2.0;
103
+ if (!dashInvert) {
104
+ offset += 1.0 / dashRepeats / 2.0;
105
+ }
106
+ // if we should animate the dash or not
107
+ // if (dashAnimate) {
108
+ // offset += time * 0.22;
109
+ // }
110
+ // create the repeating dash pattern
111
+ float pattern = fract((positionAlong + offset) * dashRepeats);
112
+ computedThickness *= 1.0 - wireframe_aastep(dashLength, pattern);
113
+ }
114
+ // compute the anti-aliased stroke edge
115
+ float edge = 1.0 - wireframe_aastep(computedThickness, d);
116
+ return edge;
117
+ }
118
+ `,
119
+ };
120
+
121
+ export const WireframeMaterial = shaderMaterial(
122
+ WireframeMaterialShaders.uniforms,
123
+ WireframeMaterialShaders.vertex +
124
+ `
125
+ void main() {
126
+ initWireframe();
127
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
128
+ }
129
+ `,
130
+ WireframeMaterialShaders.fragment +
131
+ `
132
+ void main () {
133
+ float edge = getWireframe();
134
+ vec4 colorStroke = vec4(stroke, edge);
135
+ #ifdef FLIP_SIDED
136
+ colorStroke.rgb = backfaceStroke;
137
+ #endif
138
+ vec4 colorFill = vec4(fill, fillOpacity);
139
+ vec4 outColor = mix(colorFill, colorStroke, edge * strokeOpacity);
140
+ gl_FragColor = outColor;
141
+ }
142
+ `,
143
+ );
144
+
145
+ export function setWireframeOverride(
146
+ material: THREE.Material,
147
+ uniforms: Record<string, THREE.IUniform>,
148
+ ) {
149
+ material.onBeforeCompile = (shader) => {
150
+ shader.uniforms = { ...shader.uniforms, ...uniforms };
151
+ shader.vertexShader = shader.vertexShader.replace(
152
+ 'void main() {',
153
+ `${WireframeMaterialShaders.vertex}\nvoid main() {\ninitWireframe();`,
154
+ );
155
+ shader.fragmentShader = shader.fragmentShader.replace(
156
+ 'void main() {',
157
+ `${WireframeMaterialShaders.fragment}\nvoid main() {`,
158
+ );
159
+ shader.fragmentShader = shader.fragmentShader.replace(
160
+ '#include <color_fragment>',
161
+ `
162
+ #include <color_fragment>
163
+ float edge = getWireframe();
164
+ vec4 colorStroke = vec4(stroke, edge);
165
+ #ifdef FLIP_SIDED
166
+ colorStroke.rgb = backfaceStroke;
167
+ #endif
168
+ vec4 colorFill = vec4(mix(diffuseColor.rgb, fill, fillMix), mix(diffuseColor.a, fillOpacity, fillMix));
169
+ vec4 outColor = mix(colorFill, colorStroke, edge * strokeOpacity);
170
+ diffuseColor.rgb = outColor.rgb;
171
+ diffuseColor.a *= outColor.a;
172
+ `,
173
+ );
174
+ };
175
+ material.side = THREE.DoubleSide;
176
+ material.transparent = true;
177
+ }
178
+
179
+ export function useWireframeUniforms(
180
+ uniforms: Record<string, THREE.IUniform>,
181
+ props: WireframeMaterialProps,
182
+ ) {
183
+ useEffect(
184
+ () => void (uniforms.fillOpacity.value = props.fillOpacity ?? uniforms.fillOpacity.value),
185
+ [props.fillOpacity],
186
+ );
187
+ useEffect(
188
+ () => void (uniforms.fillMix.value = props.fillMix ?? uniforms.fillMix.value),
189
+ [props.fillMix],
190
+ );
191
+ useEffect(
192
+ () => void (uniforms.strokeOpacity.value = props.strokeOpacity ?? uniforms.strokeOpacity.value),
193
+ [props.strokeOpacity],
194
+ );
195
+ useEffect(
196
+ () => void (uniforms.thickness.value = props.thickness ?? uniforms.thickness.value),
197
+ [props.thickness],
198
+ );
199
+ useEffect(
200
+ () => void (uniforms.colorBackfaces.value = !!props.colorBackfaces),
201
+ [props.colorBackfaces],
202
+ );
203
+ useEffect(() => void (uniforms.dash.value = !!props.dash), [props.dash]);
204
+ useEffect(() => void (uniforms.dashInvert.value = !!props.dashInvert), [props.dashInvert]);
205
+ useEffect(
206
+ () => void (uniforms.dashRepeats.value = props.dashRepeats ?? uniforms.dashRepeats.value),
207
+ [props.dashRepeats],
208
+ );
209
+ useEffect(
210
+ () => void (uniforms.dashLength.value = props.dashLength ?? uniforms.dashLength.value),
211
+ [props.dashLength],
212
+ );
213
+ useEffect(() => void (uniforms.squeeze.value = !!props.squeeze), [props.squeeze]);
214
+ useEffect(
215
+ () => void (uniforms.squeezeMin.value = props.squeezeMin ?? uniforms.squeezeMin.value),
216
+ [props.squeezeMin],
217
+ );
218
+ useEffect(
219
+ () => void (uniforms.squeezeMax.value = props.squeezeMax ?? uniforms.squeezeMax.value),
220
+ [props.squeezeMax],
221
+ );
222
+ useEffect(
223
+ () =>
224
+ void (uniforms.stroke.value = props.stroke
225
+ ? new THREE.Color(props.stroke)
226
+ : uniforms.stroke.value),
227
+ [props.stroke],
228
+ );
229
+ useEffect(
230
+ () =>
231
+ void (uniforms.fill.value = props.fill ? new THREE.Color(props.fill) : uniforms.fill.value),
232
+ [props.fill],
233
+ );
234
+ useEffect(
235
+ () =>
236
+ void (uniforms.backfaceStroke.value = props.backfaceStroke
237
+ ? new THREE.Color(props.backfaceStroke)
238
+ : uniforms.backfaceStroke.value),
239
+ [props.backfaceStroke],
240
+ );
241
+ }
@@ -0,0 +1,155 @@
1
+ import * as THREE from 'three';
2
+ import { FullScreenQuad } from 'three-stdlib';
3
+
4
+ type Quad = { material: THREE.ShaderMaterial; render(renderer: any): void };
5
+ const quad = (material: THREE.ShaderMaterial) =>
6
+ new FullScreenQuad(material as any) as unknown as Quad;
7
+
8
+ export function makeSDFGenerator(clientWidth: number, clientHeight: number, renderer: any) {
9
+ const finalTarget = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
10
+ minFilter: THREE.LinearMipmapLinearFilter,
11
+ magFilter: THREE.LinearFilter,
12
+ type: THREE.FloatType,
13
+ format: THREE.RedFormat,
14
+ generateMipmaps: true,
15
+ });
16
+ const outsideRenderTarget = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
17
+ minFilter: THREE.NearestFilter,
18
+ magFilter: THREE.NearestFilter,
19
+ });
20
+ const insideRenderTarget = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
21
+ minFilter: THREE.NearestFilter,
22
+ magFilter: THREE.NearestFilter,
23
+ });
24
+ const outsideRenderTarget2 = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
25
+ minFilter: THREE.NearestFilter,
26
+ magFilter: THREE.NearestFilter,
27
+ });
28
+ const insideRenderTarget2 = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
29
+ minFilter: THREE.NearestFilter,
30
+ magFilter: THREE.NearestFilter,
31
+ });
32
+ const outsideRenderTargetFinal = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
33
+ minFilter: THREE.NearestFilter,
34
+ magFilter: THREE.NearestFilter,
35
+ type: THREE.FloatType,
36
+ format: THREE.RedFormat,
37
+ });
38
+ const insideRenderTargetFinal = new THREE.WebGLRenderTarget(clientWidth, clientHeight, {
39
+ minFilter: THREE.NearestFilter,
40
+ magFilter: THREE.NearestFilter,
41
+ type: THREE.FloatType,
42
+ format: THREE.RedFormat,
43
+ });
44
+ const vertexShader = `varying vec2 vUv;
45
+ void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`;
46
+ const uvRender = quad(
47
+ new THREE.ShaderMaterial({
48
+ uniforms: { tex: { value: null } },
49
+ vertexShader,
50
+ fragmentShader: `uniform sampler2D tex; varying vec2 vUv; #include <packing>
51
+ void main() { gl_FragColor = pack2HalfToRGBA(vUv * (round(texture2D(tex, vUv).x))); }`,
52
+ }),
53
+ );
54
+ const uvRenderInside = quad(
55
+ new THREE.ShaderMaterial({
56
+ uniforms: { tex: { value: null } },
57
+ vertexShader,
58
+ fragmentShader: `uniform sampler2D tex; varying vec2 vUv; #include <packing>
59
+ void main() { gl_FragColor = pack2HalfToRGBA(vUv * (1.0 - round(texture2D(tex, vUv).x))); }`,
60
+ }),
61
+ );
62
+ const jumpFloodRender = quad(
63
+ new THREE.ShaderMaterial({
64
+ uniforms: {
65
+ tex: { value: null },
66
+ offset: { value: 0 },
67
+ level: { value: 0 },
68
+ maxSteps: { value: 0 },
69
+ },
70
+ vertexShader,
71
+ fragmentShader: `varying vec2 vUv; uniform sampler2D tex; uniform float offset; uniform float level; uniform float maxSteps; #include <packing>
72
+ void main() {
73
+ float closestDist = 9999999.9; vec2 closestPos = vec2(0.0);
74
+ for (float x = -1.0; x <= 1.0; x += 1.0) {
75
+ for (float y = -1.0; y <= 1.0; y += 1.0) {
76
+ vec2 voffset = vUv; voffset += vec2(x, y) * vec2(${1 / clientWidth}, ${1 / clientHeight}) * offset;
77
+ vec2 pos = unpackRGBATo2Half(texture2D(tex, voffset)); float dist = distance(pos.xy, vUv);
78
+ if(pos.x != 0.0 && pos.y != 0.0 && dist < closestDist) { closestDist = dist; closestPos = pos; }
79
+ }
80
+ }
81
+ gl_FragColor = pack2HalfToRGBA(closestPos);
82
+ }`,
83
+ }),
84
+ );
85
+ const distanceFieldRender = quad(
86
+ new THREE.ShaderMaterial({
87
+ uniforms: {
88
+ tex: { value: null },
89
+ size: { value: new THREE.Vector2(clientWidth, clientHeight) },
90
+ },
91
+ vertexShader,
92
+ fragmentShader: `varying vec2 vUv; uniform sampler2D tex; uniform vec2 size; #include <packing>
93
+ void main() { gl_FragColor = vec4(distance(size * unpackRGBATo2Half(texture2D(tex, vUv)), size * vUv), 0.0, 0.0, 0.0); }`,
94
+ }),
95
+ );
96
+ const compositeRender = quad(
97
+ new THREE.ShaderMaterial({
98
+ uniforms: {
99
+ inside: { value: insideRenderTargetFinal.texture },
100
+ outside: { value: outsideRenderTargetFinal.texture },
101
+ tex: { value: null },
102
+ },
103
+ vertexShader,
104
+ fragmentShader: `varying vec2 vUv; uniform sampler2D inside; uniform sampler2D outside; uniform sampler2D tex; #include <packing>
105
+ void main() {
106
+ float i = texture2D(inside, vUv).x; float o = texture2D(outside, vUv).x;
107
+ if (texture2D(tex, vUv).x == 0.0) gl_FragColor = vec4(o, 0.0, 0.0, 0.0);
108
+ else gl_FragColor = vec4(-i, 0.0, 0.0, 0.0);
109
+ }`,
110
+ }),
111
+ );
112
+ const runJumpFlood = (
113
+ initialTarget: THREE.WebGLRenderTarget,
114
+ alternateTarget: THREE.WebGLRenderTarget,
115
+ ) => {
116
+ const passes = Math.ceil(Math.log(Math.max(clientWidth, clientHeight)) / Math.log(2));
117
+ let lastTarget = initialTarget;
118
+ let target = initialTarget;
119
+ for (let index = 0; index < passes; index++) {
120
+ const offset = Math.pow(2, passes - index - 1);
121
+ target = lastTarget === initialTarget ? alternateTarget : initialTarget;
122
+ jumpFloodRender.material.uniforms.level.value = index;
123
+ jumpFloodRender.material.uniforms.maxSteps.value = passes;
124
+ jumpFloodRender.material.uniforms.offset.value = offset;
125
+ jumpFloodRender.material.uniforms.tex.value = lastTarget.texture;
126
+ renderer.setRenderTarget(target);
127
+ jumpFloodRender.render(renderer);
128
+ lastTarget = target;
129
+ }
130
+ return target;
131
+ };
132
+ return (image: THREE.Texture) => {
133
+ image.minFilter = THREE.NearestFilter;
134
+ image.magFilter = THREE.NearestFilter;
135
+ uvRender.material.uniforms.tex.value = image;
136
+ renderer.setRenderTarget(outsideRenderTarget);
137
+ uvRender.render(renderer);
138
+ let target = runJumpFlood(outsideRenderTarget, outsideRenderTarget2);
139
+ renderer.setRenderTarget(outsideRenderTargetFinal);
140
+ distanceFieldRender.material.uniforms.tex.value = target.texture;
141
+ distanceFieldRender.render(renderer);
142
+ uvRenderInside.material.uniforms.tex.value = image;
143
+ renderer.setRenderTarget(insideRenderTarget);
144
+ uvRenderInside.render(renderer);
145
+ target = runJumpFlood(insideRenderTarget, insideRenderTarget2);
146
+ renderer.setRenderTarget(insideRenderTargetFinal);
147
+ distanceFieldRender.material.uniforms.tex.value = target.texture;
148
+ distanceFieldRender.render(renderer);
149
+ renderer.setRenderTarget(finalTarget);
150
+ compositeRender.material.uniforms.tex.value = image;
151
+ compositeRender.render(renderer);
152
+ renderer.setRenderTarget(null);
153
+ return finalTarget;
154
+ };
155
+ }
@@ -0,0 +1,19 @@
1
+ declare module 'troika-three-text' {
2
+ import { Mesh } from 'three';
3
+
4
+ export class Text extends Mesh {
5
+ font?: string;
6
+ text: string;
7
+ anchorX: number | string;
8
+ anchorY: number | string;
9
+ fontSize: number;
10
+ sdfGlyphSize: number;
11
+ sync(callback?: () => void): void;
12
+ dispose(): void;
13
+ }
14
+
15
+ export function preloadFont(
16
+ options: { font?: string; characters?: string },
17
+ callback: () => void,
18
+ ): void;
19
+ }