Pass 1 renders eight plasma sheets into an atlas with linear depth in alpha; pass 2 marches the refracted ray to each sheet and absorbs it by real path length, so near and far layers separate under pointer parallax. Plasma cycle repeats exactly every 30 s; - / = change speed.
37 lines
5.0 KiB
HTML
37 lines
5.0 KiB
HTML
<!doctype html><html><head><meta charset=utf-8><title>shaders</title>
|
|
<style>html,body{margin:0;height:100%;background:#000;overflow:hidden}
|
|
canvas{display:block;width:100vw;height:100vh}
|
|
#osd{position:fixed;left:14px;bottom:12px;font:13px ui-monospace,monospace;color:#9bf;opacity:.75;pointer-events:none}</style>
|
|
</head><body><canvas id=c></canvas><div id=osd></div><script>
|
|
const SHADERS = ["precision highp float;\nuniform vec2 u_res; uniform float u_time; uniform vec2 u_mouse;\nfloat hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\nfloat noise(vec2 p){vec2 i=floor(p),f=fract(p);f=f*f*(3.0-2.0*f);\n return mix(mix(hash(i),hash(i+vec2(1,0)),f.x),mix(hash(i+vec2(0,1)),hash(i+vec2(1,1)),f.x),f.y);}\nfloat fbm(vec2 p){float a=0.5,s=0.0;for(int i=0;i<5;i++){s+=a*noise(p);p*=2.03;a*=0.5;}return s;}\nvoid main(){\n vec2 p=(gl_FragCoord.xy-0.5*u_res)/u_res.y;\n float t=u_time*0.15;\n vec2 q=vec2(fbm(p*2.0+vec2(0.0,t)),fbm(p*2.0+vec2(5.2,-t)));\n vec2 r=vec2(fbm(p*2.0+q*1.8+vec2(1.7,9.2)+t*1.3),fbm(p*2.0+q*1.8+vec2(8.3,2.8)-t*1.1));\n float v=fbm(p*2.0+r*2.2);\n vec3 col=mix(vec3(0.02,0.03,0.10),vec3(0.85,0.25,0.35),smoothstep(0.2,0.9,v));\n col=mix(col,vec3(0.15,0.65,0.95),smoothstep(0.5,1.0,length(r-0.5)));\n col+=0.35*pow(max(0.0,1.0-length(p*0.9)),3.0)*vec3(1.0,0.85,0.6);\n col*=1.0-0.5*length(p)*0.4;\n gl_FragColor=vec4(col,1.0);\n}\n", "precision highp float;\nuniform vec2 u_res; uniform float u_time; uniform vec2 u_mouse;\nvoid main(){\n vec2 p=(gl_FragCoord.xy-0.5*u_res)/u_res.y;\n float t=u_time*0.6;\n float a=atan(p.y,p.x);\n float r=length(p)+0.001;\n float z=1.0/r+t;\n float rings=fract(z*2.0+a*0.6+sin(a*3.0+t)*0.3);\n vec3 base=mix(vec3(1.0,0.15,0.55),vec3(0.15,0.9,1.0),smoothstep(0.0,1.0,rings));\n float glow=pow(1.0-r,2.0);\n float band=smoothstep(0.45,0.5,rings)*smoothstep(0.6,0.5,rings);\n vec3 col=base*band*glow*2.2;\n col+=vec3(0.9,0.5,1.0)*pow(glow,8.0)*1.5;\n col+=0.02*vec3(0.3,0.1,0.5)/(r*r);\n gl_FragColor=vec4(col,1.0);\n}\n", "precision highp float;\nuniform vec2 u_res; uniform float u_time; uniform vec2 u_mouse;\nfloat sdSphere(vec3 p,float r){return length(p)-r;}\nfloat map(vec3 p){\n float d=sdSphere(p,1.0);\n for(int i=0;i<3;i++){\n float fi=float(i);\n vec3 q=p; float a=u_time*0.5+fi*2.1;\n q.xz=mat2(cos(a),-sin(a),sin(a),cos(a))*q.xz;\n d=min(d,sdSphere(q-vec3(0.75,0.0,0.0),0.34));\n }\n return d;\n}\nvoid main(){\n vec2 uv=(gl_FragCoord.xy-0.5*u_res)/u_res.y;\n vec3 ro=vec3(0.0,0.0,3.6), rd=normalize(vec3(uv,-1.6));\n float tt=0.0; int hit=0;\n for(int i=0;i<80;i++){\n float d=map(ro+rd*tt);\n if(d<0.001){hit=1;break;}\n tt+=d;\n if(tt>8.0)break;\n }\n vec3 col=vec3(0.03,0.04,0.07)+0.15*pow(1.0-abs(uv.y),3.0);\n if(hit==1){\n vec3 pos=ro+rd*tt;\n vec3 n=normalize(vec3(map(pos+vec3(0.001,0,0))-map(pos-vec3(0.001,0,0)),\n map(pos+vec3(0,0.001,0))-map(pos-vec3(0,0.001,0)),\n map(pos+vec3(0,0,0.001))-map(pos-vec3(0,0,0.001))));\n vec3 l=normalize(vec3(0.6,0.8,0.5));\n float dif=max(dot(n,l),0.0);\n float fre=pow(1.0-max(dot(n,-rd),0.0),3.0);\n vec3 alb=0.5+0.5*cos(6.2831*(pos*0.6+vec3(0.0,0.33,0.67)));\n col=alb*(0.15+0.85*dif)+vec3(0.6,0.8,1.0)*fre*1.2;\n col*=0.9+0.1*sin(pos.y*40.0+u_time*4.0);\n }\n gl_FragColor=vec4(pow(col,vec3(0.4545)),1.0);\n}\n"];
|
|
const NAMES = ["1_plasma", "2_tunnel", "3_orb"];
|
|
const VS='attribute vec2 p;void main(){gl_Position=vec4(p,0,1);}';
|
|
const c=document.getElementById('c'),osd=document.getElementById('osd');
|
|
const gl=c.getContext('webgl',{antialias:false,preserveDrawingBuffer:false});
|
|
let progs=[],cur=0,mx=0.5,my=0.5,t0=performance.now();
|
|
function sh(t,s){const o=gl.createShader(t);gl.shaderSource(o,s);gl.compileShader(o);
|
|
if(!gl.getShaderParameter(o,gl.COMPILE_STATUS)){osd.textContent='compile error: '+gl.getShaderInfoLog(o);console.error(gl.getShaderInfoLog(o));}
|
|
return o;}
|
|
for(const s of SHADERS){const pr=gl.createProgram();
|
|
gl.attachShader(pr,sh(gl.VERTEX_SHADER,VS));gl.attachShader(pr,sh(gl.FRAGMENT_SHADER,s));
|
|
gl.linkProgram(pr);progs.push(pr);}
|
|
const b=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,b);
|
|
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),gl.STATIC_DRAW);
|
|
function resize(){const d=devicePixelRatio||1;c.width=innerWidth*d;c.height=innerHeight*d;}
|
|
addEventListener('resize',resize);resize();
|
|
addEventListener('mousemove',e=>{mx=e.clientX/innerWidth;my=1-e.clientY/innerHeight;});
|
|
addEventListener('keydown',e=>{if(e.key>='1'&&e.key<=String(progs.length)){cur=+e.key-1;}});
|
|
function frame(){
|
|
const pr=progs[cur];gl.useProgram(pr);
|
|
const l=gl.getAttribLocation(pr,'p');gl.enableVertexAttribArray(l);
|
|
gl.vertexAttribPointer(l,2,gl.FLOAT,false,0,0);
|
|
gl.uniform2f(gl.getUniformLocation(pr,'u_res'),c.width,c.height);
|
|
gl.uniform1f(gl.getUniformLocation(pr,'u_time'),(performance.now()-t0)/1000);
|
|
gl.uniform2f(gl.getUniformLocation(pr,'u_mouse'),mx,my);
|
|
gl.viewport(0,0,c.width,c.height);gl.drawArrays(gl.TRIANGLE_STRIP,0,4);
|
|
osd.textContent=NAMES[cur]+' ['+(cur+1)+'/'+progs.length+'] · keys 1-'+progs.length+' switch · move mouse';
|
|
requestAnimationFrame(frame);
|
|
}
|
|
frame();
|
|
</script></body></html>
|