Skip to content

double spiral

最終更新日時: 2025年08月25日 12:57

#ifdef GL_ES
precision mediump float;
#endif
// Double Spiral 2017-11-28 modified by @hintz
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
#define pi 3.141592653589793238462643383279
#define pi_inv 0.318309886183790671537767526745
#define pi2_inv 0.159154943091895335768883763372
vec2 complex_div(vec2 numerator, vec2 denominator)
{
return vec2(numerator.x*denominator.x + numerator.y*denominator.y, numerator.y*denominator.x - numerator.x*denominator.y)/ vec2(denominator.x*denominator.x + denominator.y*denominator.y);
}
float sigmoid(float x)
{
return sin(x*.11)*exp(-x*x);
}
float smoothcircle(vec2 uv, vec2 center, vec2 aspect, float radius, float sharpness)
{
return sigmoid((length((uv - center) * aspect) - radius) * sharpness);
}
vec2 spiralzoom(vec2 domain, vec2 center, float n, float spiral_factor, float zoom_factor, vec2 pos)
{
vec2 uv = domain - center;
float angle = atan(uv.y, uv.x);
float d = length(uv);
return vec2(angle*n*pi2_inv + log(d)*spiral_factor, -log(d)*zoom_factor) + pos;
}
vec2 mobius(vec2 domain, vec2 zero_pos, vec2 asymptote_pos)
{
return complex_div(domain - zero_pos, domain - asymptote_pos);
}
float gear(vec2 domain, float phase, vec2 pos)
{
float angle = atan(domain.y - pos.y, domain.x - pos.x);
float d = 0.2 + sin((angle + phase) * 10.)*0.;
return smoothcircle(domain, pos, vec2(1), d, 40.);
}
float geartile(vec2 domain, float phase)
{
domain = fract(domain);
return
gear(domain, -phase, vec2(-0.25,0.25)) +
gear(domain, phase, vec2(-0.25,0.75)) +
gear(domain, phase, vec2(1.25,0.25)) +
gear(domain, -phase, vec2(1.25,0.75)) +
gear(domain, -phase, vec2(0.25,-0.25)) +
gear(domain, phase, vec2(0.75,-0.25)) +
gear(domain, phase, vec2(0.25,1.25)) +
gear(domain, -phase, vec2(0.75,1.25)) +
gear(domain, phase, vec2(0.25,0.25)) +
gear(domain, -phase, vec2(0.25,0.75)) +
gear(domain, -phase, vec2(0.75,0.25)) +
gear(domain, phase, vec2(0.75,0.75));
}
void main(void)
{
vec2 uv = (gl_FragCoord.xy - .5*resolution) / resolution.x;
float phase = (time+10.)*0.5;
float dist = 0.5;
vec2 uv_bipolar = mobius(uv, vec2(-dist*0.5, 0.), vec2(dist*0.5, 0.));
uv_bipolar = spiralzoom(uv_bipolar, vec2(0.0), 5., -0.125*pi, 0.8, vec2(0.125,0.125)*phase*5.);
uv_bipolar = vec2(-uv_bipolar.y,uv_bipolar.x); // 90° rotation
vec2 uv_spiral = spiralzoom(uv, vec2(0.5), 5., -0.125*pi, 0.8, vec2(-0.,0.25)*phase);
vec2 uv_tilt = uv_spiral;
float z = 1./(1.-uv_tilt.y)/(uv_tilt.y);
uv_tilt = 0.5 + (uv_tilt - 0.5) * log(z);
float grid = geartile(uv_bipolar, -phase);
gl_FragColor = vec4(uv+vec2(0.5),0.0,1.0);
gl_FragColor = mix(vec4(0,0,1.0,0), gl_FragColor, 1.1+sin(uv_bipolar.y * pi * 2.0));
gl_FragColor += vec4(0.6*abs(uv_bipolar.x+uv_bipolar.y),0.8,1.0+(uv_bipolar.y * pi * 5.0),1.0)* -grid*500.0;
}

このコードは、複素数演算と極座標変換を利用して、**二重螺旋(Double Spiral)**のような視覚効果を生成する。 mobius()spiralzoom()のような数学的な変換を適用し、歯車模様(geartile())を重ねることで、複雑なパターンを描画している。

gl_FragCoord.xy(画素の座標)をresolution(画面解像度)で正規化し、画面中心を (0,0)(0,0) とする。

uv=gl_FragCoord.xy0.5×resolutionresolution.xuv = \frac{gl\_FragCoord.xy - 0.5 \times resolution}{resolution.x}
vec2 uv = (gl_FragCoord.xy - .5*resolution) / resolution.x;
  • mobius()関数を使用し、複素数除算で座標を変換する。
  • zero_pos(極)とasymptote_pos(漸近線)を設定し、座標を変形。
uv_bipolar=mobius(uv,(dist×0.5,0),(dist×0.5,0))uv\_bipolar = mobius(uv, (-dist \times 0.5, 0), (dist \times 0.5, 0))
vec2 uv_bipolar = mobius(uv, vec2(-dist*0.5, 0.), vec2(dist*0.5, 0.));
  • spiralzoom()を適用し、座標を極座標ベースのスパイラル形状に歪める。
uv_bipolar=spiralzoom(uv_bipolar,(0,0),5,0.125π,0.8,(0.125,0.125)×phase×5)uv\_bipolar = spiralzoom(uv\_bipolar, (0,0), 5, -0.125\pi, 0.8, (0.125,0.125) \times phase \times 5)
uv_bipolar = spiralzoom(uv_bipolar, vec2(0.0), 5., -0.125*pi, 0.8, vec2(0.125,0.125)*phase*5.);
  • (x,y)(x,y)(y,x)(-y,x) にすることで、座標を90°回転。
uv_bipolar=(uv_bipolar.y,uv_bipolar.x)uv\_bipolar = (-uv\_bipolar.y, uv\_bipolar.x)
uv_bipolar = vec2(-uv_bipolar.y,uv_bipolar.x);
  • もう一つのspiralzoom()を適用し、異なるパターンを作成。
uv_spiral=spiralzoom(uv,(0.5,0),5,0.125π,0.8,(0,0.25)×phase)uv\_spiral = spiralzoom(uv, (0.5, 0), 5, -0.125\pi, 0.8, (0, 0.25) \times phase)
vec2 uv_spiral = spiralzoom(uv, vec2(0.5), 5., -0.125*pi, 0.8, vec2(-0.,0.25)*phase);
  • log(z)を使って、変換後の座標に非線形な歪みを与える。
z=11uv_tilt.y×1uv_tilt.yz = \frac{1}{1 - uv\_tilt.y} \times \frac{1}{uv\_tilt.y} uv_tilt=0.5+(uv_tilt0.5)×logzuv\_tilt = 0.5 + (uv\_tilt - 0.5) \times \log z
vec2 uv_tilt = uv_spiral;
float z = 1./(1.-uv_tilt.y)/(uv_tilt.y);
uv_tilt = 0.5 + (uv_tilt - 0.5) * log(z);
  • geartile()で多数の歯車パターンを適用。
grid=geartile(uv_bipolar,phase)grid = geartile(uv\_bipolar, -phase)
float grid = geartile(uv_bipolar, -phase);
  • 青ベースのグラデーションを適用。
  • mix()を使い、スパイラルと歯車模様をブレンド。
gl_FragColor=vec4(uv+(0.5,0),0.0,1.0)gl\_FragColor = vec4(uv + (0.5, 0), 0.0, 1.0) gl_FragColor=mix((0,0,1.0,0),gl_FragColor,1.1+sin(uv_bipolar.y×π×2.0))gl\_FragColor = mix((0,0,1.0,0), gl\_FragColor, 1.1+\sin(uv\_bipolar.y \times \pi \times 2.0)) gl_FragColor+=(0.6×uv_bipolar.x+uv_bipolar.y,0.8,1.0+(uv_bipolar.y×π×5.0),1.0)×grid×500.0gl\_FragColor += (0.6 \times |uv\_bipolar.x + uv\_bipolar.y|, 0.8, 1.0 + (uv\_bipolar.y \times \pi \times 5.0), 1.0) \times -grid \times 500.0
gl_FragColor = vec4(uv+vec2(0.5),0.0,1.0);
gl_FragColor = mix(vec4(0,0,1.0,0), gl_FragColor, 1.1+sin(uv_bipolar.y * pi * 2.0));
gl_FragColor += vec4(0.6*abs(uv_bipolar.x+uv_bipolar.y),0.8,1.0+(uv_bipolar.y * pi * 5.0),1.0)* -grid*500.0;
  • mobius()で座標を変形
  • spiralzoom()で螺旋パターンを適用
  • geartile()で歯車パターンを配置
  • gl_FragColorで最終的な色を決定

結果として、バイポーラ変換・螺旋変換・歯車模様を組み合わせた、動的な二重螺旋のエフェクトが生まれる。