@3driseai/3drise-viewer 0.1.16 → 0.1.18

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 (145) hide show
  1. package/README.md +4 -3
  2. package/dist/components/ChladniGrid.d.ts +15 -0
  3. package/dist/components/ChladniGrid.d.ts.map +1 -0
  4. package/dist/components/ChladniGrid.js +62 -0
  5. package/dist/components/CustomPrimitive.d.ts +2 -0
  6. package/dist/components/CustomPrimitive.d.ts.map +1 -1
  7. package/dist/components/CustomPrimitive.js +2 -2
  8. package/dist/components/EffectsGenerator.d.ts.map +1 -1
  9. package/dist/components/EffectsGenerator.js +26 -2
  10. package/dist/components/FlowNetGrid.d.ts +15 -0
  11. package/dist/components/FlowNetGrid.d.ts.map +1 -0
  12. package/dist/components/FlowNetGrid.js +61 -0
  13. package/dist/components/Galaxy.d.ts.map +1 -1
  14. package/dist/components/Galaxy.js +2 -0
  15. package/dist/components/GirihGrid.d.ts +15 -0
  16. package/dist/components/GirihGrid.d.ts.map +1 -0
  17. package/dist/components/GirihGrid.js +62 -0
  18. package/dist/components/GravWaveGrid.d.ts +15 -0
  19. package/dist/components/GravWaveGrid.d.ts.map +1 -0
  20. package/dist/components/GravWaveGrid.js +62 -0
  21. package/dist/components/GridsGenerator.d.ts +2 -2
  22. package/dist/components/GridsGenerator.d.ts.map +1 -1
  23. package/dist/components/GridsGenerator.js +21 -0
  24. package/dist/components/HyperbolicGrid.d.ts +15 -0
  25. package/dist/components/HyperbolicGrid.d.ts.map +1 -0
  26. package/dist/components/HyperbolicGrid.js +61 -0
  27. package/dist/components/LayoutInstances.d.ts +13 -0
  28. package/dist/components/LayoutInstances.d.ts.map +1 -0
  29. package/dist/components/LayoutInstances.js +39 -0
  30. package/dist/components/ModelPrimitive.d.ts +2 -0
  31. package/dist/components/ModelPrimitive.d.ts.map +1 -1
  32. package/dist/components/ModelPrimitive.js +3 -3
  33. package/dist/components/ObjectNode.d.ts.map +1 -1
  34. package/dist/components/ObjectNode.js +44 -9
  35. package/dist/components/ParticlesGenerator.d.ts +10 -0
  36. package/dist/components/ParticlesGenerator.d.ts.map +1 -0
  37. package/dist/components/ParticlesGenerator.js +23 -0
  38. package/dist/components/ReactionDiffusionGrid.d.ts +15 -0
  39. package/dist/components/ReactionDiffusionGrid.d.ts.map +1 -0
  40. package/dist/components/ReactionDiffusionGrid.js +376 -0
  41. package/dist/components/WallpaperGrid.d.ts +15 -0
  42. package/dist/components/WallpaperGrid.d.ts.map +1 -0
  43. package/dist/components/WallpaperGrid.js +555 -0
  44. package/dist/components/cursor/CursorController.d.ts.map +1 -1
  45. package/dist/components/effects/BlackHoleEffect.d.ts +3 -3
  46. package/dist/components/effects/BlackHoleEffect.d.ts.map +1 -1
  47. package/dist/components/effects/BlackHoleEffect.js +293 -163
  48. package/dist/components/effects/DandelionSeedsEffect.d.ts +13 -0
  49. package/dist/components/effects/DandelionSeedsEffect.d.ts.map +1 -0
  50. package/dist/components/effects/DandelionSeedsEffect.js +510 -0
  51. package/dist/components/effects/FallingLeavesEffect.d.ts +13 -0
  52. package/dist/components/effects/FallingLeavesEffect.d.ts.map +1 -0
  53. package/dist/components/effects/FallingLeavesEffect.js +446 -0
  54. package/dist/components/effects/FieldLinesEffect.d.ts +11 -0
  55. package/dist/components/effects/FieldLinesEffect.d.ts.map +1 -0
  56. package/dist/components/effects/FieldLinesEffect.js +260 -0
  57. package/dist/components/effects/FireflySwarmEffect.d.ts +13 -0
  58. package/dist/components/effects/FireflySwarmEffect.d.ts.map +1 -0
  59. package/dist/components/effects/FireflySwarmEffect.js +408 -0
  60. package/dist/components/effects/GalaxyEffect.d.ts +13 -0
  61. package/dist/components/effects/GalaxyEffect.d.ts.map +1 -0
  62. package/dist/components/effects/GalaxyEffect.js +374 -0
  63. package/dist/components/effects/HarmonicShellEffect.d.ts +11 -0
  64. package/dist/components/effects/HarmonicShellEffect.d.ts.map +1 -0
  65. package/dist/components/effects/HarmonicShellEffect.js +209 -0
  66. package/dist/components/effects/IceCrystalsEffect.d.ts +3 -3
  67. package/dist/components/effects/IceCrystalsEffect.d.ts.map +1 -1
  68. package/dist/components/effects/IceCrystalsEffect.js +286 -166
  69. package/dist/components/effects/IceHaloEffect.d.ts +13 -0
  70. package/dist/components/effects/IceHaloEffect.d.ts.map +1 -0
  71. package/dist/components/effects/IceHaloEffect.js +306 -0
  72. package/dist/components/effects/LichtenbergEffect.d.ts +13 -0
  73. package/dist/components/effects/LichtenbergEffect.d.ts.map +1 -0
  74. package/dist/components/effects/LichtenbergEffect.js +517 -0
  75. package/dist/components/effects/MoleculesEffect.d.ts +3 -3
  76. package/dist/components/effects/MoleculesEffect.d.ts.map +1 -1
  77. package/dist/components/effects/MoleculesEffect.js +322 -164
  78. package/dist/components/effects/MurmurationEffect.d.ts +13 -0
  79. package/dist/components/effects/MurmurationEffect.d.ts.map +1 -0
  80. package/dist/components/effects/MurmurationEffect.js +539 -0
  81. package/dist/components/effects/PlanetaryRingsEffect.d.ts +13 -0
  82. package/dist/components/effects/PlanetaryRingsEffect.d.ts.map +1 -0
  83. package/dist/components/effects/PlanetaryRingsEffect.js +458 -0
  84. package/dist/components/effects/PortalEffect.d.ts +3 -3
  85. package/dist/components/effects/PortalEffect.d.ts.map +1 -1
  86. package/dist/components/effects/PortalEffect.js +240 -163
  87. package/dist/components/effects/ShockwaveEffect.d.ts +5 -3
  88. package/dist/components/effects/ShockwaveEffect.d.ts.map +1 -1
  89. package/dist/components/effects/ShockwaveEffect.js +538 -142
  90. package/dist/components/effects/SmokePlumeEffect.d.ts +3 -3
  91. package/dist/components/effects/SmokePlumeEffect.d.ts.map +1 -1
  92. package/dist/components/effects/SmokePlumeEffect.js +180 -116
  93. package/dist/components/effects/SmokeRingEffect.d.ts +3 -3
  94. package/dist/components/effects/SmokeRingEffect.d.ts.map +1 -1
  95. package/dist/components/effects/SmokeRingEffect.js +260 -135
  96. package/dist/components/effects/StrangeAttractorEffect.d.ts +11 -0
  97. package/dist/components/effects/StrangeAttractorEffect.d.ts.map +1 -0
  98. package/dist/components/effects/StrangeAttractorEffect.js +229 -0
  99. package/dist/components/effects/VolumetricFogEffect.d.ts +5 -3
  100. package/dist/components/effects/VolumetricFogEffect.d.ts.map +1 -1
  101. package/dist/components/effects/VolumetricFogEffect.js +211 -93
  102. package/dist/components/effects/WaterCausticsEffect.d.ts +13 -0
  103. package/dist/components/effects/WaterCausticsEffect.d.ts.map +1 -0
  104. package/dist/components/effects/WaterCausticsEffect.js +308 -0
  105. package/dist/components/effects/index.d.ts +9 -0
  106. package/dist/components/effects/index.d.ts.map +1 -1
  107. package/dist/components/effects/index.js +9 -0
  108. package/dist/components/index.d.ts +19 -0
  109. package/dist/components/index.d.ts.map +1 -1
  110. package/dist/components/index.js +10 -0
  111. package/dist/components/particles/BioluminescentWakeParticles.d.ts +12 -0
  112. package/dist/components/particles/BioluminescentWakeParticles.d.ts.map +1 -0
  113. package/dist/components/particles/BioluminescentWakeParticles.js +1123 -0
  114. package/dist/components/particles/BrownianDustParticles.d.ts +12 -0
  115. package/dist/components/particles/BrownianDustParticles.d.ts.map +1 -0
  116. package/dist/components/particles/BrownianDustParticles.js +757 -0
  117. package/dist/components/particles/ElectronOrbitalsParticles.d.ts +12 -0
  118. package/dist/components/particles/ElectronOrbitalsParticles.d.ts.map +1 -0
  119. package/dist/components/particles/ElectronOrbitalsParticles.js +944 -0
  120. package/dist/components/particles/GrinderSparksParticles.d.ts +12 -0
  121. package/dist/components/particles/GrinderSparksParticles.d.ts.map +1 -0
  122. package/dist/components/particles/GrinderSparksParticles.js +744 -0
  123. package/dist/components/particles/TidalStreamParticles.d.ts +12 -0
  124. package/dist/components/particles/TidalStreamParticles.d.ts.map +1 -0
  125. package/dist/components/particles/TidalStreamParticles.js +788 -0
  126. package/dist/components/particles/index.d.ts +11 -0
  127. package/dist/components/particles/index.d.ts.map +1 -0
  128. package/dist/components/particles/index.js +6 -0
  129. package/dist/constants.d.ts +1 -1
  130. package/dist/constants.d.ts.map +1 -1
  131. package/dist/constants.js +1 -1
  132. package/dist/hooks/useModelObject.d.ts +6 -1
  133. package/dist/hooks/useModelObject.d.ts.map +1 -1
  134. package/dist/hooks/useModelObject.js +19 -6
  135. package/dist/types/gridConfigs.d.ts +98 -0
  136. package/dist/types/gridConfigs.d.ts.map +1 -1
  137. package/dist/types/index.d.ts +1 -1
  138. package/dist/types/index.d.ts.map +1 -1
  139. package/dist/utils/particleTrails.d.ts +70 -0
  140. package/dist/utils/particleTrails.d.ts.map +1 -0
  141. package/dist/utils/particleTrails.js +369 -0
  142. package/dist/utils/pointerField.d.ts +28 -0
  143. package/dist/utils/pointerField.d.ts.map +1 -0
  144. package/dist/utils/pointerField.js +103 -0
  145. package/package.json +2 -2
@@ -1,195 +1,325 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef, useMemo } from 'react';
3
- import { useFrame } from '@react-three/fiber';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
4
3
  import * as THREE from 'three';
4
+ import { useFrame } from '@react-three/fiber';
5
5
  import { applyGenerativeAnimations } from '../../utils/handleGenerativeEffectsAnimations.js';
6
6
  import { useObjectReady } from '../../hooks/useObjectReady.js';
7
- // ── Accretion disk shader ─────────────────────────────────────────────────────
8
- const diskVert = /* glsl */ `
9
- varying vec2 vUv;
10
- void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }
7
+ /**
8
+ * A ray-traced Schwarzschild black hole.
9
+ *
10
+ * A proxy sphere around the hole is shaded per pixel: each view ray is bent by
11
+ * the photon geodesic a = -1.5 h^2 x / r^5, so the disk behind the hole is
12
+ * lensed over and under it and a thin photon ring forms. The disk follows the
13
+ * Shakura-Sunyaev temperature profile T ~ r^-3/4 (1 - sqrt(r_in/r))^1/4, and
14
+ * its light is Doppler-beamed and gravitationally redshifted. Two jets leave
15
+ * along the spin axis.
16
+ *
17
+ * Distances in the shader are in units of the horizon radius (uRs).
18
+ * Flying the camera into the proxy flips it to back faces so the view keeps working.
19
+ */
20
+ const PRE_NORMAL = { transparent: true, depthWrite: false, blending: THREE.NormalBlending, premultipliedAlpha: true };
21
+ const ADD = { transparent: true, depthWrite: false, blending: THREE.AdditiveBlending };
22
+ const blackHoleVert = /* glsl */ `
23
+ varying vec3 vLocal;
24
+ varying vec3 vCamLocal;
25
+ void main(){
26
+ vLocal = position;
27
+ vCamLocal = (inverse(modelMatrix) * vec4(cameraPosition, 1.0)).xyz;
28
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
29
+ }
11
30
  `;
12
- const diskFrag = /* glsl */ `
13
- uniform float u_time;
14
- uniform float uRotSpeed;
15
- uniform vec3 uDiskColor;
16
- uniform float uOpacity;
31
+ const blackHoleFrag = /* glsl */ `
32
+ uniform float uTime;
33
+ uniform float uRs; // Schwarzschild radius, local units
34
+ uniform float uOuter; // disk outer edge and proxy radius, in rs
35
+ uniform float uLensing;
36
+ uniform float uBeaming;
37
+ uniform float uRotationSpeed;
17
38
  uniform float uIntensity;
39
+ uniform float uOpacity;
40
+ uniform float uInside; // 1 when the camera is inside the proxy sphere
41
+ uniform vec3 uDiskColor;
42
+ uniform vec3 uColor;
43
+ varying vec3 vLocal;
44
+ varying vec3 vCamLocal;
18
45
 
19
- varying vec2 vUv;
46
+
47
+ float hash13(vec3 p3){
48
+ p3 = fract(p3 * 0.1031);
49
+ p3 += dot(p3, p3.zyx + 31.32);
50
+ return fract((p3.x + p3.y) * p3.z);
51
+ }
52
+ float vnoise(vec3 p){
53
+ vec3 i = floor(p);
54
+ vec3 f = fract(p);
55
+ f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
56
+ float n000 = hash13(i);
57
+ float n100 = hash13(i + vec3(1.0, 0.0, 0.0));
58
+ float n010 = hash13(i + vec3(0.0, 1.0, 0.0));
59
+ float n110 = hash13(i + vec3(1.0, 1.0, 0.0));
60
+ float n001 = hash13(i + vec3(0.0, 0.0, 1.0));
61
+ float n101 = hash13(i + vec3(1.0, 0.0, 1.0));
62
+ float n011 = hash13(i + vec3(0.0, 1.0, 1.0));
63
+ float n111 = hash13(i + vec3(1.0, 1.0, 1.0));
64
+ return mix(mix(mix(n000, n100, f.x), mix(n010, n110, f.x), f.y),
65
+ mix(mix(n001, n101, f.x), mix(n011, n111, f.x), f.y), f.z);
66
+ }
67
+ // low-frequency fBm; the rotation between octaves hides the lattice
68
+ const mat3 FBM_ROT = mat3(0.00, 0.80, 0.60, -0.80, 0.36, -0.48, -0.60, -0.48, 0.64);
69
+ float fbm3(vec3 p, int octaves){
70
+ float a = 0.5, s = 0.0;
71
+ for (int i = 0; i < 5; i++){
72
+ if (i >= octaves) break;
73
+ s += a * vnoise(p);
74
+ p = FBM_ROT * p * 2.02;
75
+ a *= 0.5;
76
+ }
77
+ return s;
78
+ }
20
79
 
21
- vec3 tempColor(float t) {
22
- // t=0 outer edge (cool red), t=1 inner edge (blue-white hot)
23
- vec3 outer = uDiskColor * 0.4;
24
- vec3 mid = uDiskColor;
25
- vec3 inner = vec3(0.85, 0.95, 1.0) * 2.5;
26
- if (t < 0.5) return mix(outer, mid, t * 2.0);
27
- else return mix(mid, inner, (t - 0.5) * 2.0);
80
+
81
+ // Observed temperature (1 = the disk's hottest ring at rest) to colour.
82
+ vec3 diskRamp(float T){
83
+ vec3 c0 = uDiskColor * 0.3;
84
+ vec3 c1 = uDiskColor;
85
+ vec3 c2 = vec3(1.0, 0.86, 0.66);
86
+ vec3 c3 = vec3(0.78, 0.87, 1.0) * 1.5;
87
+ if (T < 0.5) return mix(c0, c1, T * 2.0);
88
+ if (T < 1.0) return mix(c1, c2, (T - 0.5) * 2.0);
89
+ return mix(c2, c3, clamp(T - 1.0, 0.0, 1.0));
28
90
  }
29
91
 
30
- float hash(float n) { return fract(sin(n) * 43758.5453); }
92
+ float diskNoise(float x, float ang, float off){
93
+ vec3 q = vec3(cos(ang) * x, sin(ang) * x, off) * 0.85;
94
+ float n = fbm3(q, 4);
95
+ // faint concentric structure, bent by the noise
96
+ return n + 0.18 * sin(log(x) * 22.0 + n * 5.0);
97
+ }
31
98
 
32
- void main() {
33
- // Polar coordinates from ring UV
34
- vec2 centered = vUv * 2.0 - 1.0;
35
- float dist = length(centered);
36
- if (dist > 1.0 || dist < 0.001) discard;
99
+ void main(){
100
+ const float RIN = 3.0; // innermost stable circular orbit, in rs
101
+ vec3 ro = vCamLocal / uRs;
102
+ vec3 rd = normalize(vLocal - vCamLocal);
103
+ vec3 pos = uInside > 0.5 ? ro : vLocal / uRs;
104
+ vec3 vel = rd;
37
105
 
38
- float angle = atan(centered.y, centered.x);
106
+ // h = |x cross v| is conserved along a photon path; the Schwarzschild
107
+ // geodesic in these units bends the ray by a = -1.5 h^2 x / r^5.
108
+ vec3 hv = cross(pos, vel);
109
+ float h2 = dot(hv, hv);
39
110
 
40
- // Normalized radial position (0=inner, 1=outer)
41
- float t = 1.0 - dist;
111
+ vec3 col = vec3(0.0);
112
+ float trans = 1.0;
113
+ float captured = 0.0;
114
+ float glow = 0.0;
42
115
 
43
- // Spiral motion bands
44
- float spiral = fract(dist * 6.0 - u_time * uRotSpeed + angle / 6.28318);
45
- float bands = pow(spiral, 2.2) * 0.6 + 0.4;
116
+ float ph = uTime * uRotationSpeed / 7.0;
117
+ float f0 = fract(ph), f1 = fract(ph + 0.5);
118
+ float w0 = 1.0 - abs(2.0 * f0 - 1.0);
119
+ float off0 = floor(ph) * 7.31, off1 = floor(ph + 0.5) * 7.31 + 3.7;
46
120
 
47
- // Brightness: peaks near inner edge, falls off to rim
48
- float bright = pow(t, 0.7) * bands;
121
+ for (int i = 0; i < 64; i++){
122
+ float r2 = dot(pos, pos);
123
+ float r = sqrt(r2);
124
+ if (r < 1.0){ captured = 1.0; break; }
125
+ if (r > uOuter * 1.02 && dot(pos, vel) > 0.0) break;
49
126
 
50
- // Fine-grained turbulence
51
- float noise = 0.85 + 0.15 * sin(angle * 7.0 + dist * 18.0 - u_time * 2.5);
127
+ float dt = clamp(0.16 * (r - 0.8), 0.03, 0.9);
128
+ vec3 acc = -1.5 * h2 * pos / (r2 * r2 * r) * uLensing;
129
+ vec3 prev = pos;
130
+ vel += acc * dt;
131
+ pos += vel * dt;
52
132
 
53
- vec3 col = tempColor(t) * bright * noise;
54
- float alpha = bright * noise * uOpacity * uIntensity * smoothstep(0.0, 0.08, dist);
55
- if (alpha < 0.005) discard;
56
- gl_FragColor = vec4(col, alpha);
57
- }
58
- `;
59
- // ── Photon sphere (lensing rim) ───────────────────────────────────────────────
60
- const lensFrag = /* glsl */ `
61
- uniform float u_time;
62
- uniform vec3 uDiskColor;
63
- uniform float uOpacity;
64
- uniform float uIntensity;
65
- varying vec3 vNormal;
66
-
67
- void main() {
68
- vec3 viewDir = normalize(cameraPosition - vNormal * 100.0);
69
- float ndv = abs(dot(normalize(vNormal), viewDir));
70
- float fresnel = pow(1.0 - ndv, 2.2);
71
- // Only show a bright equatorial band
72
- float equator = exp(-ndv * ndv * 6.0) * 2.5;
73
- float alpha = (fresnel * 0.4 + equator * 0.6) * uOpacity * uIntensity;
74
- if (alpha < 0.005) discard;
75
- vec3 col = mix(uDiskColor, vec3(1.0, 0.92, 0.8), fresnel * 0.5);
133
+ // light hugging the photon sphere (r = 1.5) forms the thin photon ring
134
+ glow += exp(-pow((r - 1.5) * 9.0, 2.0)) * dt;
135
+
136
+ // thin disk in the y = 0 plane
137
+ if (prev.y * pos.y < 0.0){
138
+ vec3 hit = mix(prev, pos, prev.y / (prev.y - pos.y));
139
+ float x = length(hit.xz);
140
+ if (x > RIN && x < uOuter){
141
+ // Shakura-Sunyaev thin disk: T ~ r^-3/4 (1 - sqrt(rin/r))^1/4, peak ~0.488
142
+ float T = pow(x / RIN, -0.75) * pow(1.0 - sqrt(RIN / x), 0.25) / 0.488;
143
+ // Keplerian orbit: Omega = sqrt(GM/r^3) with GM = 1/2 in these units
144
+ float omega = sqrt(0.5 / (x * x * x));
145
+ float ang = atan(hit.z, hit.x);
146
+ float n = diskNoise(x, ang - omega * f0 * 7.0 * 6.0, off0) * w0
147
+ + diskNoise(x, ang - omega * f1 * 7.0 * 6.0, off1) * (1.0 - w0);
148
+ // relativistic Doppler beaming and gravitational redshift
149
+ vec3 vdir = normalize(vec3(-hit.z, 0.0, hit.x));
150
+ float beta = min(sqrt(0.5 / max(x - 1.0, 0.5)), 0.7);
151
+ float cosA = dot(vdir, -normalize(vel));
152
+ float gam = 1.0 / sqrt(1.0 - beta * beta);
153
+ float D = 1.0 / (gam * (1.0 - beta * cosA));
154
+ float g = mix(1.0, D * sqrt(1.0 - 1.0 / x), uBeaming);
155
+ float Tobs = T * g;
156
+ float edge = smoothstep(RIN, RIN * 1.15, x) * (1.0 - smoothstep(uOuter * 0.7, uOuter, x));
157
+ float dens = clamp(0.2 + 1.1 * (n - 0.3), 0.0, 1.0) * edge;
158
+ float a = clamp(dens * uOpacity * 1.4, 0.0, 1.0);
159
+ vec3 emit = diskRamp(Tobs) * pow(max(Tobs, 0.0), 2.2) * 1.6 * uIntensity;
160
+ col += trans * emit * a;
161
+ trans *= 1.0 - a;
162
+ }
163
+ }
164
+ if (trans < 0.02) break;
165
+ }
166
+
167
+ col += trans * uColor * glow * 0.9 * uIntensity * (1.0 - captured);
168
+ float alpha = captured > 0.5 ? 1.0 : clamp(1.0 - trans + glow * 0.4, 0.0, 1.0);
76
169
  gl_FragColor = vec4(col, alpha);
77
170
  }
78
171
  `;
79
- const lensVert = /* glsl */ `
80
- varying vec3 vNormal;
81
- void main() {
82
- vNormal = (modelMatrix * vec4(normal, 0.0)).xyz;
83
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
84
- }
85
- `;
86
- // ── Jet particle shader ───────────────────────────────────────────────────────
87
172
  const jetVert = /* glsl */ `
88
- attribute float aT;
89
- attribute float aPhase;
90
- uniform float u_time;
91
- uniform float u_speed;
92
- uniform float uLength;
93
- uniform float uDir; // +1 or -1
94
- uniform float uRadius;
95
- varying float vT;
96
- void main() {
97
- float t = fract(aT + u_time * u_speed);
98
- vT = t;
99
- float r = uRadius * (1.0 - t * 0.85);
100
- float a = aPhase + t * 4.0;
101
- float x = cos(a) * r;
102
- float z = sin(a) * r;
103
- float y = uDir * t * uLength;
104
- vec4 mv = modelViewMatrix * vec4(x, y, z, 1.0);
105
- gl_PointSize = (1.0 - t) * 6.0 * (200.0 / -mv.z);
106
- gl_Position = projectionMatrix * mv;
173
+ varying vec2 vUv;
174
+ varying vec3 vNormalW;
175
+ varying vec3 vViewW;
176
+ varying vec3 vAxisW;
177
+ void main(){
178
+ vUv = uv;
179
+ vec4 wp = modelMatrix * vec4(position, 1.0);
180
+ vNormalW = normalize(mat3(modelMatrix) * normal);
181
+ vViewW = normalize(cameraPosition - wp.xyz);
182
+ vAxisW = normalize(mat3(modelMatrix) * vec3(0.0, 1.0, 0.0));
183
+ gl_Position = projectionMatrix * viewMatrix * wp;
107
184
  }
108
185
  `;
109
186
  const jetFrag = /* glsl */ `
187
+ uniform float uTime;
110
188
  uniform vec3 uJetColor;
189
+ uniform float uIntensity;
111
190
  uniform float uOpacity;
112
- varying float vT;
113
- void main() {
114
- vec2 c = gl_PointCoord - 0.5;
115
- if (length(c) > 0.5) discard;
116
- float g = exp(-dot(c,c) * 6.0);
117
- float a = g * uOpacity * (1.0 - vT) * smoothstep(0.0, 0.1, vT);
118
- if (a < 0.01) discard;
119
- gl_FragColor = vec4(uJetColor, a);
191
+ varying vec2 vUv;
192
+ varying vec3 vNormalW;
193
+ varying vec3 vViewW;
194
+ varying vec3 vAxisW;
195
+
196
+
197
+ float hash13(vec3 p3){
198
+ p3 = fract(p3 * 0.1031);
199
+ p3 += dot(p3, p3.zyx + 31.32);
200
+ return fract((p3.x + p3.y) * p3.z);
201
+ }
202
+ float vnoise(vec3 p){
203
+ vec3 i = floor(p);
204
+ vec3 f = fract(p);
205
+ f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
206
+ float n000 = hash13(i);
207
+ float n100 = hash13(i + vec3(1.0, 0.0, 0.0));
208
+ float n010 = hash13(i + vec3(0.0, 1.0, 0.0));
209
+ float n110 = hash13(i + vec3(1.0, 1.0, 0.0));
210
+ float n001 = hash13(i + vec3(0.0, 0.0, 1.0));
211
+ float n101 = hash13(i + vec3(1.0, 0.0, 1.0));
212
+ float n011 = hash13(i + vec3(0.0, 1.0, 1.0));
213
+ float n111 = hash13(i + vec3(1.0, 1.0, 1.0));
214
+ return mix(mix(mix(n000, n100, f.x), mix(n010, n110, f.x), f.y),
215
+ mix(mix(n001, n101, f.x), mix(n011, n111, f.x), f.y), f.z);
216
+ }
217
+ // low-frequency fBm; the rotation between octaves hides the lattice
218
+ const mat3 FBM_ROT = mat3(0.00, 0.80, 0.60, -0.80, 0.36, -0.48, -0.60, -0.48, 0.64);
219
+ float fbm3(vec3 p, int octaves){
220
+ float a = 0.5, s = 0.0;
221
+ for (int i = 0; i < 5; i++){
222
+ if (i >= octaves) break;
223
+ s += a * vnoise(p);
224
+ p = FBM_ROT * p * 2.02;
225
+ a *= 0.5;
226
+ }
227
+ return s;
228
+ }
229
+
230
+
231
+ void main(){
232
+ // optical depth is largest through the middle of the cone
233
+ float ndv = abs(dot(normalize(vNormalW), normalize(vViewW)));
234
+ float core = pow(ndv, 1.6);
235
+ float v = vUv.y; // 0 at the base, 1 at the tip
236
+ // knots of plasma flowing outward
237
+ float knots = fbm3(vec3(vUv.x * 6.2832 * 0.5, v * 5.0 - uTime * 1.2, 0.0), 3);
238
+ float fall = exp(-v * 2.4) * smoothstep(0.0, 0.06, v);
239
+ // relativistic beaming: the jet pointing at the camera is brighter
240
+ float beta = 0.6;
241
+ float cosT = dot(normalize(vAxisW), normalize(vViewW));
242
+ float D = 1.0 / (1.25 * (1.0 - beta * cosT));
243
+ float I = core * fall * (0.35 + knots) * pow(D, 2.0) * uIntensity;
244
+ gl_FragColor = vec4(uJetColor * I * 1.6 + vec3(I * I * 0.3), clamp(I * uOpacity, 0.0, 1.0));
120
245
  }
121
246
  `;
247
+ const _inv = new THREE.Matrix4();
248
+ const _cam = new THREE.Vector3();
122
249
  const BlackHoleEffect = ({ boundingRadius, config, animations, onObjectReady, onObjectDispose }) => {
123
- const { diskColor, jetEnabled, jetColor, rotationSpeed, tilt, opacity, speed, intensity } = config;
124
- const startValuesCacheRef = useRef({});
125
- const groupRef = useRef(null);
126
- useObjectReady(groupRef, config, onObjectReady, onObjectDispose);
127
- const r = boundingRadius;
128
- const { diskMat, lensMat, jetMat1, jetMat2, jetGeo } = useMemo(() => {
129
- const dc = new THREE.Color(diskColor);
130
- const dcv = new THREE.Vector3(dc.r, dc.g, dc.b);
131
- const dMat = new THREE.ShaderMaterial({
132
- vertexShader: diskVert, fragmentShader: diskFrag,
133
- uniforms: {
134
- u_time: { value: 0 },
135
- uRotSpeed: { value: rotationSpeed },
136
- uDiskColor: { value: dcv },
137
- uOpacity: { value: opacity },
138
- uIntensity: { value: intensity },
139
- },
140
- transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, side: THREE.DoubleSide,
141
- });
142
- const lMat = new THREE.ShaderMaterial({
143
- vertexShader: lensVert, fragmentShader: lensFrag,
144
- uniforms: {
145
- u_time: { value: 0 },
146
- uDiskColor: { value: dcv },
147
- uOpacity: { value: opacity },
148
- uIntensity: { value: intensity },
149
- },
150
- transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, side: THREE.BackSide,
151
- });
152
- // Jet geometry (shared, mirrored with uDir ±1)
153
- const JN = 80;
154
- const jT = new Float32Array(JN);
155
- const jPhase = new Float32Array(JN);
156
- for (let i = 0; i < JN; i++) {
157
- jT[i] = i / JN;
158
- jPhase[i] = Math.random() * Math.PI * 2;
159
- }
160
- const jGeo = new THREE.BufferGeometry();
161
- jGeo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(JN * 3), 3));
162
- jGeo.setAttribute('aT', new THREE.BufferAttribute(jT, 1));
163
- jGeo.setAttribute('aPhase', new THREE.BufferAttribute(jPhase, 1));
164
- jGeo.frustumCulled = false;
165
- const jc = new THREE.Color(jetColor);
166
- const makeJetMat = (dir) => new THREE.ShaderMaterial({
167
- vertexShader: jetVert, fragmentShader: jetFrag,
168
- uniforms: {
169
- u_time: { value: 0 },
170
- u_speed: { value: speed },
171
- uLength: { value: r * 2.2 },
172
- uDir: { value: dir },
173
- uRadius: { value: r * 0.12 },
174
- uJetColor: { value: new THREE.Vector3(jc.r, jc.g, jc.b) },
175
- uOpacity: { value: opacity * 0.8 },
176
- },
177
- transparent: true, depthWrite: false, blending: THREE.AdditiveBlending,
178
- });
179
- return { diskMat: dMat, lensMat: lMat, jetMat1: makeJetMat(1), jetMat2: makeJetMat(-1), jetGeo: jGeo };
180
- // eslint-disable-next-line react-hooks/exhaustive-deps
181
- }, [diskColor, jetColor, rotationSpeed, opacity, intensity, speed, r]);
182
- useFrame((state) => {
183
- const t = state.clock.getElapsedTime();
184
- diskMat.uniforms.u_time.value = t;
185
- lensMat.uniforms.u_time.value = t;
186
- jetMat1.uniforms.u_time.value = t;
187
- jetMat2.uniforms.u_time.value = t;
188
- if (animations?.length) {
189
- applyGenerativeAnimations([diskMat, lensMat, jetMat1, jetMat2], animations, startValuesCacheRef.current, Date.now(), false);
250
+ const { intensity = 1.2, speed = 1, color = '#ffd2a0', opacity = 0.95, diskColor = '#ff6600', jetEnabled = true, jetColor = '#88aaff', rotationSpeed = 1, tilt = 15, horizonSize = 0.4, diskOuter = 3, lensing = 1, beaming = 1, } = config;
251
+ const rootRef = useRef(null);
252
+ const diskRef = useRef(null);
253
+ const insideRef = useRef(false);
254
+ const animCache = useRef({});
255
+ useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
256
+ // a standalone effect gets boundingRadius 1; guard against an empty host
257
+ const b = boundingRadius > 0 ? boundingRadius : 1;
258
+ const Rs = b * horizonSize;
259
+ // outer edge of the disk, in horizon radii; never inside the photon sphere region
260
+ const outerRs = Math.max(diskOuter / Math.max(horizonSize, 1e-3), 3.5);
261
+ const proxyR = Rs * outerRs * 1.03;
262
+ const uniforms = useMemo(() => ({
263
+ uTime: { value: 0 },
264
+ uSpeed: { value: 1 },
265
+ uIntensity: { value: 1 },
266
+ uOpacity: { value: 1 },
267
+ uColor: { value: new THREE.Color() },
268
+ uDiskColor: { value: new THREE.Color() },
269
+ uJetColor: { value: new THREE.Color() },
270
+ uRotationSpeed: { value: 1 },
271
+ uLensing: { value: 1 },
272
+ uBeaming: { value: 1 },
273
+ uRs: { value: 1 },
274
+ uOuter: { value: 7.5 },
275
+ uInside: { value: 0 },
276
+ }), []);
277
+ const materials = useMemo(() => [
278
+ new THREE.ShaderMaterial({ vertexShader: blackHoleVert, fragmentShader: blackHoleFrag, uniforms, ...PRE_NORMAL }),
279
+ new THREE.ShaderMaterial({ vertexShader: jetVert, fragmentShader: jetFrag, uniforms, ...ADD, side: THREE.DoubleSide }),
280
+ ], [uniforms]);
281
+ useEffect(() => () => materials.forEach((m) => m.dispose()), [materials]);
282
+ const proxyGeometry = useMemo(() => new THREE.SphereGeometry(proxyR, 64, 40), [proxyR]);
283
+ const jetGeometry = useMemo(() => {
284
+ const jetH = b * 2.4;
285
+ const g = new THREE.CylinderGeometry(Rs * 1.8, Rs * 0.25, jetH, 32, 1, true);
286
+ g.translate(0, jetH / 2 + Rs * 1.2, 0);
287
+ return g;
288
+ }, [b, Rs]);
289
+ useEffect(() => () => proxyGeometry.dispose(), [proxyGeometry]);
290
+ useEffect(() => () => jetGeometry.dispose(), [jetGeometry]);
291
+ useLayoutEffect(() => {
292
+ uniforms.uSpeed.value = speed;
293
+ uniforms.uIntensity.value = intensity;
294
+ uniforms.uOpacity.value = opacity;
295
+ uniforms.uColor.value.set(color);
296
+ uniforms.uDiskColor.value.set(diskColor);
297
+ uniforms.uJetColor.value.set(jetColor);
298
+ uniforms.uRotationSpeed.value = rotationSpeed;
299
+ uniforms.uLensing.value = lensing;
300
+ uniforms.uBeaming.value = beaming;
301
+ uniforms.uRs.value = Rs;
302
+ uniforms.uOuter.value = outerRs;
303
+ }, [uniforms, speed, intensity, opacity, color, diskColor, jetColor, rotationSpeed, lensing, beaming, Rs, outerRs]);
304
+ useFrame((state, delta) => {
305
+ uniforms.uTime.value += delta * uniforms.uSpeed.value;
306
+ const disk = diskRef.current;
307
+ if (disk) {
308
+ disk.updateWorldMatrix(true, false);
309
+ _inv.copy(disk.matrixWorld).invert();
310
+ const inside = _cam.copy(state.camera.position).applyMatrix4(_inv).length() < proxyR;
311
+ if (inside !== insideRef.current) {
312
+ insideRef.current = inside;
313
+ const mat = materials[0];
314
+ uniforms.uInside.value = inside ? 1 : 0;
315
+ mat.side = inside ? THREE.BackSide : THREE.FrontSide;
316
+ mat.depthTest = !inside;
317
+ mat.needsUpdate = true;
318
+ }
190
319
  }
320
+ if (animations?.length)
321
+ applyGenerativeAnimations(materials, animations, animCache.current, Date.now(), false);
191
322
  });
192
- const tiltRad = (tilt * Math.PI) / 180;
193
- return (_jsxs("group", { ref: groupRef, rotation: [0, 0, tiltRad], children: [_jsx("mesh", { material: lensMat, children: _jsx("sphereGeometry", { args: [r * 0.55, 48, 48] }) }), _jsx("mesh", { material: diskMat, rotation: [Math.PI / 2, 0, 0], children: _jsx("ringGeometry", { args: [r * 0.38, r * 1.15, 72] }) }), jetEnabled && (_jsxs(_Fragment, { children: [_jsx("points", { geometry: jetGeo, material: jetMat1 }), _jsx("points", { geometry: jetGeo, material: jetMat2 })] }))] }));
323
+ return (_jsx("group", { ref: rootRef, children: _jsxs("group", { rotation: [0, 0, (tilt * Math.PI) / 180], children: [_jsx("mesh", { ref: diskRef, geometry: proxyGeometry, material: materials[0] }), _jsxs("group", { visible: jetEnabled, children: [_jsx("mesh", { geometry: jetGeometry, material: materials[1], frustumCulled: false }), _jsx("mesh", { geometry: jetGeometry, material: materials[1], scale: [1, -1, 1], frustumCulled: false })] })] }) }));
194
324
  };
195
325
  export default BlackHoleEffect;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { AnimationOptions, DandelionSeedsConfig } from '@3driseai/3drise-core';
3
+ import type { ObjectReadyProps } from '../../types/objectReady';
4
+ export interface DandelionSeedsEffectProps extends ObjectReadyProps {
5
+ boundingRadius: number;
6
+ config: DandelionSeedsConfig;
7
+ animations?: AnimationOptions[];
8
+ /** True when the effect is attached to an object, so it can react to the host. */
9
+ hasHost?: boolean;
10
+ }
11
+ declare const DandelionSeedsEffect: React.FC<DandelionSeedsEffectProps>;
12
+ export default DandelionSeedsEffect;
13
+ //# sourceMappingURL=DandelionSeedsEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DandelionSeedsEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/DandelionSeedsEffect.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsD,MAAM,OAAO,CAAC;AAG3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAGpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IAC/D,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAChC,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AA6cD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA+B7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}