A sphere of particles in the fragment shader using raymarching.
Warning
The sphere is not rendered correctly, and there are glitches in the rendred result. Any suggestions to get rid of those glitches are welcome.
| // template: https://www.shadertoy.com/view/WtGXDD | |
| #ifdef GL_ES | |
| precision mediump float; | |
| #endif | |
| #define MAX_STEPS 100 | |
| #define MAX_DIST 10. | |
| #define SURF_DIST .001 | |
| #define TAU 6.283185 | |
| #define PI 3.141592 | |
| #define S smoothstep | |
| #define T u_time | |
| uniform vec2 u_resolution; | |
| uniform vec2 u_mouse; | |
| uniform float u_time; | |
| // Precision-adjusted variations of https://www.shadertoy.com/view/4djSRW | |
| float hash(float p) { p = fract(p * 0.011); p *= p + 7.5; p *= p + p; return fract(p); } | |
| float hash(vec2 p) {vec3 p3 = fract(vec3(p.xyx) * 0.13); p3 += dot(p3, p3.yzx + 3.333); return fract((p3.x + p3.y) * p3.z); } | |
| float noise(vec2 x) { | |
| vec2 i = floor(x); | |
| vec2 f = fract(x); | |
| float a = hash(i); | |
| float b = hash(i + vec2(1.0, 0.0)); | |
| float c = hash(i + vec2(0.0, 1.0)); | |
| float d = hash(i + vec2(1.0, 1.0)); | |
| vec2 u = f * f * (3.0 - 2.0 * f); | |
| return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; | |
| } | |
| mat2 Rot(float a) { float s=sin(a), c = cos(a); return mat2(c, -s, s, c); } | |
| float fold(vec3 p, float n, float arct) { | |
| float section = 6.283185 / n; | |
| return floor(0.5 + arct / section) * section; | |
| } | |
| float GetDist(vec3 p) { | |
| float div = 150.0, radius = 1.0, yid, xzid, size = 1.0/div; | |
| yid = fold(p, div, atan(p.y, p.z)); | |
| p.xz *= Rot(sin(40. * yid + T) / 30.0); | |
| xzid = fold(p, div, atan(p.x, p.z)); | |
| p.yz *= Rot(xzid / 1.5 + sin(xzid + T / 10.0) / 10.); | |
| xzid = fold(p, div, atan(p.x, p.z)); p.xz *= Rot(xzid); | |
| yid = fold(p, div, atan(p.y, p.z)); p.yz *= Rot(yid); | |
| float noise2d = noise(vec2(yid, xzid) * 5.0 + (T/5.)); | |
| radius += 0.02 * sin(xzid * 6.28 + T); | |
| radius -= 0.1 * noise2d; | |
| size *= noise2d; | |
| return length(p - vec3(0, 0, radius)) - size; | |
| } | |
| float RayMarch(vec3 ro, vec3 rd) { | |
| float dO = 0.; | |
| for(int i = 0; i < MAX_STEPS; i++) { | |
| vec3 p = ro + rd * dO; | |
| float dS = GetDist(p); | |
| dO += dS; | |
| if(dO > MAX_DIST || abs(dS) < SURF_DIST) break; | |
| } | |
| return dO; | |
| } | |
| vec3 GetNormal(vec3 p) { | |
| vec2 e = vec2(.001, 0); | |
| vec3 n = GetDist(p) - vec3(GetDist(p-e.xyy), GetDist(p-e.yxy),GetDist(p-e.yyx)); | |
| return normalize(n); | |
| } | |
| vec3 GetRayDir(vec2 uv, vec3 p, vec3 l, float z) { | |
| vec3 f = normalize(l-p), | |
| r = normalize(cross(vec3(0,1,0), f)), | |
| u = cross(f,r), | |
| c = f*z, | |
| i = c + uv.x*r + uv.y*u; | |
| return normalize(i); | |
| } | |
| void main() { | |
| vec2 uv = (gl_FragCoord.xy - .5 * u_resolution.xy)/u_resolution.y; | |
| vec2 m = u_mouse.xy/u_resolution.xy; | |
| vec3 ro = vec3(0, 0.2, 3.0); // camera position | |
| vec3 rd = GetRayDir(uv, ro, vec3(0,0.,0), 1.2); | |
| vec3 col = vec3(0); | |
| float d = RayMarch(ro, rd); | |
| if(d<MAX_DIST) { | |
| vec3 p = ro + rd * d; | |
| vec3 n = GetNormal(p); | |
| float dif = dot(n, normalize(vec3(1))) * .5 + .5; | |
| col = vec3(dif) * mix(vec3(0.4, 0.0, 0.0), vec3(0.0, 1.0, 1.0), (length(p) - 0.92) * 20.0); | |
| } | |
| col = pow(col, vec3(.4545)); // gamma correction | |
| gl_FragColor = vec4(col, 1.0); | |
| } |