1
0

add burst

This commit is contained in:
2026-03-07 20:22:44 +09:00
parent 69d4c5a787
commit 3f41d65e30
6 changed files with 294 additions and 10 deletions

View File

@@ -101,8 +101,6 @@ const SPHERE_PRESET = {
{ radius: 0.2, segments: 48, size: 0.01, opacity: 0.4 },
{ radius: 0.26, segments: 32, size: 0.006, opacity: 0.15 },
],
lightColor: '#aaccff',
lightIntensity: 0.3,
rotateSpeed: 0.8,
pulseSpeed: 1.0,
pulseRange: 0.12,
@@ -171,12 +169,228 @@ function SphereEffect({ position = [0, 1.0, 0], scale = 1 }) {
);
}
// --- BlackHole Effect (burst) - fullscreen raymarching ---
const bhVertexShader = `
attribute vec3 position;
varying vec2 vUv;
void main() {
vUv = position.xy;
gl_Position = vec4(position.xy, 0.0, 1.0);
}
`;
const bhFragmentShader = `
precision highp float;
varying vec2 vUv;
uniform vec2 uResolution;
uniform float uTime;
uniform float uPhase; // 0-1: blackhole, 1-2: explode, 2-3: dissipate
#define MAX_STEPS 48
#define STEP_SIZE 0.1
#define PI 3.14159265
float hash(float n){ return fract(sin(n)*43758.5453123); }
float hash2(vec2 p){ return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); }
float noise(vec3 p){
vec3 i=floor(p); vec3 f=fract(p); f=f*f*(3.0-2.0*f);
float n=i.x+i.y*57.0+113.0*i.z;
return mix(mix(mix(hash(n),hash(n+1.0),f.x),mix(hash(n+57.0),hash(n+58.0),f.x),f.y),
mix(mix(hash(n+113.0),hash(n+114.0),f.x),mix(hash(n+170.0),hash(n+171.0),f.x),f.y),f.z);
}
vec3 starField(vec3 dir){
vec3 col=vec3(0.0);
col+=smoothstep(0.4,0.9,noise(dir*3.0+vec3(0.5,1.0,0.2))+0.5*noise(dir*7.0))*vec3(0.05,0.06,0.15);
for(int i=0;i<3;i++){
float sc=pow(8.0,float(i+1));
vec3 g=fract(dir*sc)-0.5;
float id=floor(dir.x*sc)*1.3+floor(dir.y*sc)*4.7+floor(dir.z*sc)*9.1;
col+=step(0.995-float(i)*0.003,hash(id))*smoothstep(0.12,0.0,length(g))*vec3(0.9,0.95,1.0)*(1.0-float(i)*0.3);
}
return col;
}
// --- Phase 1: Black Hole ---
vec3 traceBlackHole(vec3 ro, vec3 rd, float mass){
float rs=1.5*mass, rs2=rs*rs;
vec3 pos=ro, vel=normalize(rd);
for(int i=0;i<MAX_STEPS;i++){
float r=length(pos);
if(r<rs*0.98) return vec3(0.0);
vel+=-(1.5*rs2/(r*r*r))*(pos/r)*STEP_SIZE;
vel=normalize(vel);
pos+=vel*STEP_SIZE;
if(r>20.0) break;
}
return starField(normalize(vel));
}
// --- Phase 2: Supernova Explosion ---
vec3 supernova(vec2 uv, float t, float sr){
vec3 col=vec3(0.0);
float angle=atan(uv.y,uv.x);
// sharp shockwave rings
for(int i=0;i<3;i++){
float delay=float(i)*0.15;
float rt=max(0.0, t-delay);
float ringR=rt*(2.0+float(i)*0.6);
// very thin ring with sharp falloff
float ringDist=abs(sr-ringR);
float ringW=0.008+float(i)*0.004;
float ring=exp(-ringDist*ringDist/(ringW*ringW));
// bright edge glow just outside ring
float edgeGlow=exp(-ringDist*ringDist/(ringW*ringW*8.0))*0.3;
vec3 ringCol=mix(vec3(1.0,0.95,0.85),vec3(1.0,0.75,0.3),float(i)/3.0);
float fade=exp(-rt*1.5)*(3.0-float(i)*0.5);
col+=ringCol*(ring+edgeGlow)*fade;
}
// intense central flash with slow decay
float flash=1.0/(sr*6.0+0.03)*max(0.0,1.0-t*1.2);
col+=vec3(1.0,0.97,0.92)*flash*0.6;
// hot debris particles with trails
for(int i=0;i<50;i++){
float fi=float(i);
float a=hash(fi*1.17)*PI*2.0;
float speed=0.8+hash(fi*2.31)*2.5;
float r=t*speed;
float life=1.0-smoothstep(0.0,0.6+hash(fi*3.7)*0.6, t);
vec2 dir=vec2(cos(a),sin(a));
vec2 ppos=dir*r;
// spiral motion
float spin=hash(fi*7.3)*2.0-1.0;
ppos+=vec2(-dir.y,dir.x)*sin(t*3.0+fi)*0.1*spin;
float d=length(uv-ppos);
// sharp tiny particle with subtle trail
float trail=exp(-d*d*8000.0)+exp(-pow(dot(uv-ppos,dir),2.0)*20000.0-pow(length(uv-ppos-dir*0.01),2.0)*5000.0)*0.3;
float bright=life*trail;
// temperature gradient: white-hot core -> gold -> amber
float temp=hash(fi*9.1);
vec3 pcol=mix(vec3(1.0,0.95,0.85),mix(vec3(1.0,0.75,0.3),vec3(0.9,0.5,0.1),temp),t*0.8);
col+=pcol*bright*1.2;
}
return col;
}
// --- Phase 3: Supernova afterglow (reuse explosion, fade out) ---
vec3 stardust(vec2 uv, float t, float sr){
// Continue supernova at t=1.0 state, then fade everything out
float fade=pow(1.0-t, 2.0);
// Run supernova frozen near end, slowly expanding
vec2 expandedUv=uv/(1.0+t*0.3);
float expandedSr=length(expandedUv);
vec3 col=supernova(expandedUv, 0.85+t*0.15, expandedSr)*fade;
return col;
}
void main(){
float aspect=uResolution.x/uResolution.y;
vec2 uv=vec2(vUv.x*aspect, vUv.y);
float sr=length(uv);
vec3 col=vec3(0.0);
float alpha=0.0;
if(uPhase<1.0){
// Phase 1: Black hole forming (0 -> 1)
float grow=uPhase*uPhase;
vec2 bhUv=uv*16.0;
float mass=3.0*grow;
vec3 cp=vec3(0.0,0.0,3.0);
vec3 rd=normalize(vec3(bhUv*(1.4-mass*0.1),-1.0));
col=traceBlackHole(cp,rd,mass);
float bhSr=length(bhUv);
float rs=1.5*mass;
float g=max(grow,0.001);
col+=vec3(0.3,0.5,1.0)*0.5*0.01*g/(bhSr*5.0/g+0.008)*rs;
col+=vec3(0.6,0.75,1.0)*exp(-abs(bhSr-0.055*g)*50.0/g)*g*0.6;
col=pow(col/(1.0+col),vec3(0.45));
alpha=clamp(grow*2.0,0.0,1.0)*clamp(length(col)*3.0,0.0,1.0);
} else if(uPhase<1.1){
// White flash transition
float t=(uPhase-1.0)/0.1;
float flash=1.0-t;
col=vec3(1.0,0.98,0.95)*flash*flash;
alpha=flash;
} else if(uPhase<2.0){
// Phase 2: Supernova explosion
float t=(uPhase-1.1)/0.9;
col=supernova(uv, t, sr);
col=min(col, vec3(1.0));
alpha=clamp(length(col)*5.0,0.0,1.0);
} else {
// Phase 3: Stardust fade out
float t=(uPhase-2.0)/1.0;
col=stardust(uv, t, sr);
col=min(col, vec3(1.0));
alpha=clamp(length(col)*5.0,0.0,1.0)*(1.0-t*t);
}
gl_FragColor=vec4(col,alpha);
}
`;
const BURST_TOTAL_DURATION = 4.5; // seconds for full animation
function BlackHoleEffect() {
const matRef = useRef();
const startRef = useRef(null);
const uniforms = useMemo(() => ({
uTime: { value: 0 },
uPhase: { value: 0 },
uResolution: { value: new THREE.Vector2(1, 1) },
}), []);
useFrame(({ clock, gl }) => {
if (!matRef.current) return;
const t = clock.getElapsedTime();
if (startRef.current === null) startRef.current = t;
const elapsed = t - startRef.current;
// Map elapsed time to 0-3 phase range over BURST_TOTAL_DURATION
const phase = Math.min(3.0, (elapsed / BURST_TOTAL_DURATION) * 3.0);
matRef.current.uniforms.uTime.value = t;
matRef.current.uniforms.uPhase.value = phase;
const size = gl.getSize(new THREE.Vector2());
matRef.current.uniforms.uResolution.value.copy(size);
});
return (
<mesh renderOrder={999} frustumCulled={false}>
<planeGeometry args={[2, 2]} />
<rawShaderMaterial
ref={matRef}
vertexShader={bhVertexShader}
fragmentShader={bhFragmentShader}
uniforms={uniforms}
transparent
depthTest={false}
depthWrite={false}
/>
</mesh>
);
}
// --- Unified export ---
function EnergySphere({ type = 'sun', position = [0, 1.0, 0], scale = 1 }) {
if (type === 'earth' || type === 'moon') {
return <SphereEffect position={position} scale={scale} />;
}
if (type === 'burst') {
return <BlackHoleEffect />;
}
return <GalaxyEffect position={position} scale={scale} />;
}