// https://www.shadertoy.com/view/MslGRn #define vec2 float2 #define vec3 float3 #define vec4 float4 #define ivec2 int2 #define ivec3 int3 #define ivec4 int4 #define mat3 float3x3 #define mat4 float4x4 #define fract frac #define mix lerp #define iTime Time.x #define iResolution ViewSize uniform float2 mouse< string name = "Virtual Mouse Coordinates"; string field_type = "slider"; float2 minimum = {0, 0}; float2 maximum = {100., 100.}; float2 scale = {.01, .01}; float2 step = {.01, .01}; > = {0., 0.}; uniform float4x4 ViewProj< bool automatic = true; >; uniform float4 Time< bool automatic = true; >; uniform float4 ViewSize< bool automatic = true; >; int2 iMouse() { return int2(mouse.x * ViewSize.x, mouse.y * ViewSize.y); } #define TWO_OCTAVES #define THREE_OCTAVES #define SLICES 50.0 #define START_AMPLITUDE 0.01 #define START_FREQUENCY 1.25 #define START_DENSITY 0.0 #define ANIMATION_SPEED 0.075 float hash( float n ) { return fract(sin(n)*43758.5453123); } float noise( in vec3 x ) { vec3 p = floor(x); vec3 f = fract(x); f = f*f*(3.0-2.0*f); float n = p.x + p.y*57.0 + 113.0*p.z; float res = mix(mix(mix( hash(n+ 0.0), 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); return res; } // fbm noise for 2-4 octaves including rotation per octave float fbm( vec3 p ) { // rotation matrix for fbm octaves mat3 m = mat3( 0.00, 0.80, 0.60, -0.80, 0.36, -0.48, -0.60, -0.48, 0.64 ); float f = 0.0; f += 0.5000*noise( p ); p = mul(p, m) * 2.02; f += 0.2500*noise( p ); #ifdef TWO_OCTAVES return f/0.75; #else p = mul(m, p) * 2.03; f += 0.1250*noise( p ); #ifdef THREE_OCTAVES return f/0.875; #else p = mul(m, p) * 2.01; f += 0.0625*noise( p ); return f/0.9375; #endif #endif } vec3 gradient(float s) { return vec3(0.0, max(1.0-s*2.0, 0.0), max(s>0.5?1.0-(s-0.5)*5.0:1.0, 0.0)); } #define RADIUS 0.5 bool intersectSphere(vec3 origin, vec3 direction, out float tmin, out float tmax) { bool hit = false; float a = dot(direction, direction); float b = 2.0*dot(origin, direction); float c = dot(origin, origin) - 0.5*0.5; float disc = b*b - 4.0*a*c; // discriminant tmin = tmax = 0.0; if (disc > 0.0) { // Real root of disc, so intersection float sdisc = sqrt(disc); float t0 = (-b - sdisc)/(2.0*a); // closest intersection distance float t1 = (-b + sdisc)/(2.0*a); // furthest intersection distance tmax = t1; if (t0 >= 0.0) tmin = t0; hit = true; } return hit; } vec2 rt(vec2 x,float y) { return vec2(cos(y)*x.x-sin(y)*x.y,sin(y)*x.x+cos(y)*x.y); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { // normalized and aspect ratio corrected pixel coordinate vec2 p = (fragCoord.xy / iResolution.xy)*2.0-1.0; p.x *= iResolution.x/ iResolution.y; // camera and user input vec3 oo = vec3(0, 0, 1.0-iMouse().y/iResolution.y); vec3 od = normalize(vec3(p.x, p.y, -2.0)); vec3 o,d; o.xz = rt(oo.xz, 6.3*iMouse().x/iResolution.x); o.y = oo.y; d.xz = rt(od.xz, 6.3*iMouse().x/iResolution.x); d.y = od.y; // render vec4 col = vec4(0, 0, 0, 1); float tmin, tmax; if (intersectSphere(o, d, tmin, tmax)) { // step thoug the sphere with max SLICES steps for (float i = 0.0; i < SLICES; i+=1.0) { // stay within the sphere bounds float t = tmin+i/SLICES; if (t > tmax) break; vec3 curpos = o + d*t; // get sphere falloff in s float s = (0.5-length(curpos))*2.0; s*=s; // get turbulence in d float a = START_AMPLITUDE; float b = START_FREQUENCY; float d = START_DENSITY; for (int j = 0; j < 3; j++) { d += 0.5/abs((fbm(5.0*curpos*b+ANIMATION_SPEED*iTime/b)*2.0-1.0)/a); b *= 2.0; a /= 2.0; } // get gradient color depending on s col.rgb += gradient(s)*max(d*s,0.0); } } fragColor = col; } struct VertFragData { float4 pos : POSITION; float2 uv : TEXCOORD0; }; VertFragData VSDefault(VertFragData vtx) { vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); return vtx; } float4 PSDefault(VertFragData vtx) : TARGET { float4 col = float4(1., 1., 1., 1.); mainImage(col, vtx.uv * ViewSize.xy); return col; } technique Draw { pass { vertex_shader = VSDefault(vtx); pixel_shader = PSDefault(vtx); } }