generated at
background gl

概要
glslで記述されたWebGLを背景に表示するUserScript
右メニューのボタンからテンプレートの名前をクリックすることでテーマを変更できる
frag.gl , vert.gl があるページではそれが読み込まれ、表示される
一度正しく読み込まれたテーマは次にロードするまで右のメニューから再度表示可能
UserScriptでの実装なので見えるのは読み込んでいる人だけ
外部訪問者に見せることはできない

詳細
ユーザーのページにインポートする前の設定を書き込むことで最初に読み込まれた時のテーマを決めることができる
window.glsl_frag window.glsl_vert
テンプレートからデフォルトを選択
or
URL を指定
window.glsl_vert は未設定でも化

settings.js
window.glsl_frag = "beam" // window.glsl_frag = "/api/code/{projectname}/{pagename}/frag.gl" // window.glsl_vert = "/api/code/{projectname}/{pagename}/vert.gl"

_script.js
import "/api/code/{projectname}/{username}/settings.js" import "/api/code/yutaro/background-gl/script.js"

テンプレートのglslのコードは glslsandbox からお借りしました。
そのままではなぜか動かないので変数名などを置き換え
次のようにそれぞれ置き換えると動く(理由は分かっていない)
time => u_time
mouse => u_mouse
resolution => u_resolution

余談
glslを勉強し始めたので、scrapboxに飾るために作った!
ユーザーごとの settings.js は試験的に便利かどうか検討中
window.____ で設定を記述できる
設定の方を確実に先に読み込ませるために別ファイルにして import
glslは完全に初心者で色々よくわかっていないのでバグが結構あるかも...


こんな感じでカードを透過させるとメニュー画面がかっこよくなるのでオススメ
style.css
.grid li.page-list-item a .header { border-top: rgba(100,255,100, 0.2) solid 3px; } .grid li.page-list-item a { background-color: rgba(0,0,0,0); }

script.js
import GlslCanvas from '/api/code/spm/GlslCanvas/script.js' const frags = ['gradation','smog','blocks','beam', 'fusion', 'mono', 'marin','neon', 'sea'] if( window.glsl_frag === undefined ) { window.glsl_frag = 'none' } const canvas = document.createElement('canvas') canvas.width = window.parent.screen.width canvas.height = window.parent.screen.height canvas.style = `position:fixed; z-index: -1; top: 0; left: 0;` $('#app-container').append(canvas) let sandbox = new GlslCanvas(canvas) function load(frag, vert = undefined ) { if ( frag === "none" ) return if ( !frag.includes('/') ) { frag = `/api/code/yutaro/background_gl/${frag}.gl` } return ( async () => { const fs = await fetch( frag , { credentials: 'same-origin'}) .then( data => data.text()) .catch( err => err ) if( fs.length === 0 ) return false; if( !vert ) { sandbox.load(fs) return false; } const vs = await fetch( vert , { credentials: 'same-origin'}) .then( data => data.text()) .catch( err => err ) if( vs.length === 0 ) sandbox.load(fs) else sandbox.load(fs, vs) return true; })() } load(window.glsl_frag, window.glsl_vert); scrapbox.PageMenu.addMenu({ title: 'glsl', image: 'https://gyazo.com/6bae1fa3ccf6ee0a396dbf23c00e742d/raw' }) frags.forEach( frag => { scrapbox.PageMenu('glsl').addItem({ title: frag, onClick: () => load(frag) }) }) let url = "/" let items = [] setInterval( () => { const path = location.pathname // ここの例外処理をちゃんと書く if ( url === path || /^\/[\w-]+\/$/.test(path) || path.includes('settings') || path.includes('stream') ) return url = path load(`/api/code${path}/frag.gl`,`/api/code${path}/vert.gl`) .then( flag => { if( !flag ) return; const pageName = path.split('/')[2] if(items.includes( pageName )) return; items.push(pageName) scrapbox.PageMenu('glsl').addItem({ title: pageName, onClick: () => load(`/api/code${path}/frag.gl`,`/api/code${path}/vert.gl`) }) }); }, 10)

gradation.gl
// Author: // Title: #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(0.); color = vec3(st.x,st.y,abs(sin(u_time))); gl_FragColor = vec4(color,1.0); }


beam.gl
#ifdef GL_ES precision mediump float; #endif #extension GL_OES_standard_derivatives : enable uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; float DEG2RAG = .0174532925199; float tri2(vec2 pos) { float a = dot(pos, vec2(sin( 60.0*DEG2RAG), cos( 60.0*DEG2RAG))); float b = dot(pos, vec2(sin(-60.0*DEG2RAG), cos(-60.0*DEG2RAG))); float c = -pos.y; float d = 0.2*cos(60.0*DEG2RAG); float u1 = a - d*0.25; float v1 = b - d*0.25; float w1 = c - d*0.25; float u2 = c + d*1.25; float v2 = b + d*1.25; float w2 = a + d*1.25; float t1 = min(u2, min(u1, v1)); float t2 = min(v2, min(w1, u1)); float t3 = min(w2, min(v1, w1)); float res = max(max(t1, t2), t3); return 0.002/abs(res); } float tri(vec2 pos) { float a = dot(pos, vec2(sin( 60.0*DEG2RAG), cos( 60.0*DEG2RAG))); float b = dot(pos, vec2(sin(-60.0*DEG2RAG), cos(-60.0*DEG2RAG))); float c = -pos.y; float result = 0.002/abs(min(min(0.05-a,0.05-b), 0.05-c)); return result; } void main() { vec2 pos = (2.0*gl_FragCoord.xy - u_resolution.xy)/max(u_resolution.x, u_resolution.y) / 16.0; //rotate & zoom mat2 rot = mat2(cos(u_time),-sin(u_time), sin(u_time), cos(u_time)); pos *= rot; float zoom = 1.0/(mod(u_time, 1.0)+1.0)*3.0-1.0; pos *= zoom; //effect vec3 result = vec3(0.0); for(int i = 0 ; i < 6 ; i++) { result += vec3(tri(pos), tri(-pos*0.5), tri2(pos)); pos /= 0.25; } gl_FragColor = vec4( mix(vec3(0.0, 0.0, 0.0), vec3(0.5, 0.0,1.0), result.x) +mix(vec3(0.0, 0.0, 0.0), vec3(0.5,0.25,0.0), result.y) +mix(vec3(0.0, 0.0, 0.0), vec3(0.0,0.5,0.1), result.z), 1.0 ); }


blocks.gl
// @lsdlive // This was my shader for the shader showdown at Outline demoparty 2018 in Nederland. // Shader showdown is a live-coding competition where two participants are // facing each other during 25 minutes. // (Round 1) // I don't have access to the code I typed at the event, so it might be // slightly different. // Original algorithm on shadertoy from fb39ca4: https://www.shadertoy.com/view/4dX3zl // I used the implementation from shane: https://www.shadertoy.com/view/MdVSDh // Thanks to shadertoy community & shader showdown paris. // This is under CC-BY-NC-SA (shadertoy default licence) #ifdef GL_ES precision mediump float; #endif uniform float u_time; uniform vec2 u_mouse; uniform vec2 u_resolution; #define iTime u_time mat2 r2d(float a) { float c = cos(a), s = sin(a); return mat2(c, s, -s, c); } vec2 path(float t) { float a = sin(t*.2 + 1.5), b = sin(t*.2); return vec2(2.*a, a*b); } float g = 0.; float de(vec3 p) { p.xy -= path(p.z); float d = -length(p.xy) + 4.;// tunnel (inverted cylinder) p.xy += vec2(cos(p.z + iTime)*sin(iTime), cos(p.z + iTime)); p.z -= 6. + iTime * 6.; d = min(d, dot(p, normalize(sign(p))) - 1.); // octahedron (LJ's formula) // I added this in the last 1-2 minutes, but I'm not sure if I like it actually! // Trick inspired by balkhan's shadertoys. // Usually, in raymarch shaders it gives a glow effect, // here, it gives a colors patchwork & transparent voxels effects. g += .015 / (.001 + d * d); return d; } void main() { vec2 uv = gl_FragCoord.xy / u_resolution.xy - .5; uv.x *= u_resolution.x / u_resolution.y; float dt = u_time * 6.; vec3 ro = vec3(0, 0, -5. + dt); vec3 ta = vec3(0, 0, dt); ro.xy += path(ro.z); ta.xy += path(ta.z); vec3 fwd = normalize(ta - ro); vec3 right = cross(fwd, vec3(0, 1, 0)); vec3 up = cross(right, fwd); vec3 rd = normalize(fwd + uv.x*right + uv.y*up); rd.xy *= r2d(sin(-ro.x / 3.14)*.3); // Raycast in 3d to get voxels. // Algorithm fully explained here in 2D (just look at dde algo): // http://lodev.org/cgtutor/raycasting.html // Basically, tracing a ray in a 3d grid space, and looking for // each voxel (think pixel with a third dimension) traversed by the ray. vec3 p = floor(ro) + .5; vec3 mask; vec3 drd = 1. / abs(rd); rd = sign(rd); vec3 side = drd * (rd * (p - ro) + .5); float t = 0., ri = 0.; for (float i = 0.; i < 1.; i += .01) { ri = i; /* // sphere tracing algorithm (for comparison) p = ro + rd * t; float d = de(p); if(d<.001) break; t += d; */ if (de(p) < 0.) break;// distance field // we test if we are inside the surface mask = step(side, side.yzx) * step(side, side.zxy); // minimum value between x,y,z, output 0 or 1 side += drd * mask; p += rd * mask; } t = length(p - ro); vec3 c = vec3(1) * length(mask * vec3(1., .5, .75)); c = mix(vec3(.2, .2, .7), vec3(.2, .1, .2), c); c += g * .4; c.r += sin(u_time)*.2 + sin(p.z*.5 - u_time * 6.);// red rings c = mix(c, vec3(.2, .1, .2), 1. - exp(-.001*t*t));// f gl_FragColor = vec4(c, 1.0); }


smog.gl
#ifdef GL_ES precision highp float; #endif uniform float u_time; uniform vec2 u_mouse; uniform vec2 u_resolution; #define iterations 4 #define formuparam2 0.89 #define volsteps 10 #define stepsize 0.190 #define zoom 3.900 #define tile 0.450 #define speed2 0.010 #define brightness 0.2 #define darkmatter 0.400 #define distfading 0.560 #define saturation 0.400 #define transverseSpeed 1.1 #define cloud 0.2 float triangle(float x, float a) { float output2 = 2.0*abs( 2.0* ( (x/a) - floor( (x/a) + 0.5) ) ) - 1.0; return output2; } float field(in vec3 p) { float strength = 7.0 + 0.03 * log(1.e-6 + fract(sin(u_time) * 4373.11)); float accum = 0.0; float prev = 0.0; float tw = 0.0; for (int i = 0; i < 4; ++i) { float mag = dot(p, p); p = abs(p) / mag + vec3(-.5, -.8 + 0.1*sin(u_time*0.2 + 2.0), -1.1+0.3*cos(u_time*0.15)); float w = exp(-float(i) / 7.); accum += w * exp(-strength * pow(abs(mag - prev), 2.3)); tw += w; prev = mag; } return max(0., 5. * accum / tw - .7); } void main() { vec2 uv2 = 2. * gl_FragCoord.xy / u_resolution.xy - 1.; vec2 uvs = uv2 * u_resolution.xy / max(u_resolution.x, u_resolution.y); float time2 = u_time*1.9; float speed = speed2; speed = 0.005 * cos(time2*0.02 + 3.1415926/4.0); //speed = 0.0; float formuparam = formuparam2; //get coords and direction vec2 uv = uvs; //mouse rotation float a_xz = 0.9; float a_yz = -.6; float a_xy = 0.9 + u_time*0.04; mat2 rot_xz = mat2(cos(a_xz),sin(a_xz),-sin(a_xz),cos(a_xz)); mat2 rot_yz = mat2(cos(a_yz),sin(a_yz),-sin(a_yz),cos(a_yz)); mat2 rot_xy = mat2(cos(a_xy),sin(a_xy),-sin(a_xy),cos(a_xy)); float v2 =1.0; vec3 dir=vec3(uv*zoom,1.); vec3 from=vec3(0.0, 0.0,0.0); from.x -= .5*(-0.5); from.y -= .5*(-0.5); vec3 forward = vec3(0.,0.,1.); from.x += transverseSpeed*(1.0)*cos(0.01*u_time) + 0.001*u_time; from.y += transverseSpeed*(1.0)*sin(0.01*u_time) + 0.001*u_time; from.z += 0.003*u_time; dir.xy*=rot_xy; forward.xy *= rot_xy; dir.xz*=rot_xz; forward.xz *= rot_xz; dir.yz*= rot_yz; forward.yz *= rot_yz; from.xy*=-rot_xy; from.xz*=rot_xz; from.yz*= rot_yz; //zoom float zooom = (time2-3311.)*speed; from += forward* zooom; float sampleShift = mod( zooom, stepsize ); float zoffset = -sampleShift; sampleShift /= stepsize; // make from 0 to 1 //volumetric rendering float s=0.24; float s3 = s + stepsize/2.0; vec3 v=vec3(0.); float t3 = 0.0; vec3 backCol2 = vec3(0.); for (int r=0; r<volsteps; r++) { vec3 p2=from+(s+zoffset)*dir;// + vec3(0.,0.,zoffset); vec3 p3=(from+(s3+zoffset)*dir )* (1.9/zoom);// + vec3(0.,0.,zoffset); p2 = abs(vec3(tile)-mod(p2,vec3(tile*2.))); // tiling fold p3 = abs(vec3(tile)-mod(p3,vec3(tile*2.))); // tiling fold #ifdef cloud t3 = field(p3); #endif float pa,a=pa=0.; for (int i=0; i<iterations; i++) { p2=abs(p2)/dot(p2,p2)-formuparam; // the magic formula //p=abs(p)/max(dot(p,p),0.005)-formuparam; // another interesting way to reduce noise float D = abs(length(p2)-pa); // absolute sum of average change if (i > 2) { a += i > 7 ? min( 12., D) : D; } pa=length(p2); } //float dm=max(0.,darkmatter-a*a*.001); //dark matter a*=a*a; // add contrast //if (r>3) fade*=1.-dm; // dark matter, don't render near // brightens stuff up a bit float s1 = s+zoffset; // need closed form expression for this, now that we shift samples float fade = pow(distfading,max(0.,float(r)-sampleShift)); //t3 += fade; v+=fade; //backCol2 -= fade; // fade out samples as they approach the camera if( r == 0 ) fade *= (1. - (sampleShift)); // fade in samples as they approach from the distance if( r == volsteps-1 ) fade *= sampleShift; v+=vec3(s1,s1*s1,s1*s1*s1*s1)*a*brightness*fade; // coloring based on distance backCol2 += mix(.4, 1., v2) * vec3(0.20 * t3 * t3 * t3, 0.4 * t3 * t3, t3 * 0.7) * fade; s+=stepsize; s3 += stepsize; } v=mix(vec3(length(v)),v,saturation); //color adjust vec4 forCol2 = vec4(v*.01,1.); #ifdef cloud backCol2 *= cloud; #endif backCol2.r *= 1.80; backCol2.g *= 0.05; backCol2.b *= 0.90; // backCol2.b = 0.5*mix(backCol2.b, backCol2.g, 0.2); // backCol2.g = 0.0; // // backCol2.bg = mix(backCol2.gb, backCol2.bg, 0.5*(cos(u_time*0.01) + 1.0)); gl_FragColor = vec4(backCol2, 1.0); }


fusion.gl
#ifdef GL_ES precision mediump float; #endif #extension GL_OES_standard_derivatives : enable uniform float u_time; uniform vec2 u_mouse; uniform vec2 u_resolution; void main( void ) { float dist= 2.7; vec2 p = gl_FragCoord.xy / u_resolution.xy * 2. - 1.; p.x *= u_resolution.x/u_resolution.y; p*=1.5; p=(p); float a = sin(atan(p.y,p.x))*cos(atan(p.y,p.x))*2.; float l = log(length(p))*1.5; float c = sin((l+cos(a*1.-sin(a*2.-u_time*5.)+u_time*3.2)+a*2.+u_time*0.5)); c*=log(abs(l*dist))/1.5; //c*=sin(l*dist); gl_FragColor = vec4((c),c*c,-c,1.0 ); }


mono.gl
#ifdef GL_ES precision mediump float; #endif #extension GL_OES_standard_derivatives : enable uniform float u_time; uniform vec2 u_mouse; uniform vec2 u_resolution; vec2 brickTile(vec2 uv, float zoom) { uv *= zoom; uv.x += step(1., mod(uv.y,2.0)) * -u_time; return fract(uv); } vec2 brickTile2(vec2 uv, float zoom) { uv *= zoom; float t = mod(uv.y,2.0) < 1. ? -u_time : u_time; uv.x += step(0., mod(uv.y,2.0)) * t; return fract(uv); } vec2 brickTile3(vec2 uv, float zoom) { uv *= zoom; float tx = mod(uv.y,2.0) < 1. ? -u_time : u_time; float ty = mod(uv.x,2.0) < 1. ? -u_time : u_time; float b = step(1.,mod(u_time,2.)); if(b < 1.) { uv.x += step(0., mod(uv.y,2.0)) * tx; } else { uv.y += step(0., mod(uv.x,2.0)) * ty; } return fract(uv); } void main( void ) { vec2 position = ( gl_FragCoord.xy / u_resolution.xy ); position.x *= u_resolution.x / u_resolution.y; //position = brickTile(position,5.); //position = brickTile2(position,10.); position = brickTile3(position,10.); float d = distance(position,vec2(.5)); float radius = 0.2; float s = smoothstep(radius,d + radius, d); vec3 color = vec3(s * 5.); color = mix(color,1.- color,sin(u_time) + 1.); gl_FragColor = vec4( color , 1.0 ); }


marin.gl
/* Iridule ~ shadertoy: iridule twitter: @iridule instagram: @the_iridule email: numinouscranium@gmail.com */ #ifdef GL_ES precision mediump float; #endif #extension GL_OES_standard_derivatives : enable uniform float u_time; uniform vec2 u_resolution; vec2 iResolution; float iTime; #define repeat(v) mod(p + 1., 2.) -1. #define un(a, b) min(a, b) mat3 rotateX(float a) { return mat3( 1.0, 0.0, 0.0, 0.0, cos(a), sin(a), 0.0, -sin(a), cos(a) ); } mat3 rotateY(float a) { return mat3( cos(a), 0.0, sin(a), 0.0, 1.0, 0.0, -sin(a), 0.0, cos(a) ); } float sphere_sdf(vec3 p, float r) { return length(p) - r; } float cube_sdf(vec3 p, float s) { return length(max(abs(p) - s, .0)); } float ring_sdf(vec3 p) { float a = sphere_sdf(p + vec3(.2, .0, .0), .1); float b = sphere_sdf(p + vec3(-.2, .0, .0), .1); float A = un(a, b); float c = sphere_sdf(p + vec3(.0, .0, .1), .1); float d = sphere_sdf(p + vec3(.0, .0, -.1), .1); float B = un(c, d); return un(A, B); } float shape_sdf(vec3 p) { vec3 v = rotateY(iTime) * p; v.y = mod(v.y + 0.2, 0.4) - 0.2; return un(ring_sdf(v), sphere_sdf(p * vec3(1., .01, 1.), .11)); } void mainImage(out vec4 O, in vec2 I) { vec2 R = iResolution.xy; vec2 uv = (2. * I - R) / R.y; vec3 o = vec3(-1., 0., iTime), d = vec3(uv, 1.), p; float t = 0.; for (int i = 0; i < 32; i++) { p = o + d * t; p = repeat(p); t += .5 * shape_sdf(p); } float l = .8 * dot(normalize(o - p), d); O = vec4(.5 * vec3(0., uv.y, uv.y) + vec3(.0, .3, 1.) * l * vec3(t * .3), 1.); } void main(void) { iResolution = u_resolution; iTime = u_time; mainImage(gl_FragColor, gl_FragCoord.xy); }

neon.gl
#ifdef GL_ES precision mediump float; #endif uniform float u_time; uniform vec2 u_resolution; void main( void ) { vec2 p = ( gl_FragCoord.xy / u_resolution.x ); float scale = 65.0*(1.5+cos(u_time/13.0 + sin(p.x)+ sin(p.y))); vec3 hue = vec3(p.x,p.y,0.0); float color = 0.0; color = (sin(p.x*scale) + sin(p.y*scale) -1.7)*4.0; gl_FragColor = vec4( color * hue, 1.0 ); }

sea.gl
#ifdef GL_ES precision mediump float; #endif uniform float u_time; uniform vec2 u_mouse; uniform vec2 u_resolution; // "Seascape" by Alexander Alekseev aka TDM - 2014 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. const int NUM_STEPS = 16; const float PI = 3.1415; const float EPSILON = 1e-3; float EPSILON_NRM = 0.; // sea const int ITER_GEOMETRY = 3; const int ITER_FRAGMENT = 5; const float SEA_HEIGHT = 0.6; const float SEA_CHOPPY = 4.0; const float SEA_SPEED = 0.8; const float SEA_FREQ = 0.16; const vec3 SEA_BASE = vec3(0.2,0.19,0.22); const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6); float SEA_TIME = 0.; mat2 octave_m = mat2(1.6,1.2,-1.2,1.6); // math mat3 fromEuler(vec3 ang) { vec2 a1 = vec2(sin(ang.x),cos(ang.x)); vec2 a2 = vec2(sin(ang.y),cos(ang.y)); vec2 a3 = vec2(sin(ang.z),cos(ang.z)); mat3 m; m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x); m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x); m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y); return m; } float hash( vec2 p ) { float h = dot(p,vec2(127.1,311.7)); return fract(sin(h)*43758.5453123); } float noise( in vec2 p ) { vec2 i = floor( p ); vec2 f = fract( p ); vec2 u = f*f*(3.0-2.0*f); return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), hash( i + vec2(1.0,0.0) ), u.x), mix( hash( i + vec2(0.0,1.0) ), hash( i + vec2(1.0,1.0) ), u.x), u.y); } // lighting float diffuse(vec3 n,vec3 l,float p) { return pow(dot(n,l) * 0.1 + 0.6,p); } float specular(vec3 n,vec3 l,vec3 e,float s) { float nrm = (s + 8.0) / (3.1415 * 8.0); return pow(max(dot(reflect(e,n),l),0.0),s) * nrm; } // sky vec3 getSkyColor(vec3 e) { e.y = max(e.y,0.0); vec3 ret; ret.x = pow(1.0-e.y,2.0); ret.y = 1.0-e.y; ret.z = 0.6+(1.0-e.y)*0.4; return ret; } // sea float sea_octave(vec2 uv, float choppy) { uv += noise(uv); vec2 wv = 1.0-abs(sin(uv)); vec2 swv = abs(cos(uv)); wv = mix(wv,swv,wv); return pow(1.0-pow(wv.x * wv.y,0.65),choppy); } float map(vec3 p) { float freq = SEA_FREQ; float amp = SEA_HEIGHT; float choppy = SEA_CHOPPY; vec2 uv = p.xz; uv.x *= 0.75; float d, h = 0.0; for(int i = 0; i < ITER_GEOMETRY; i++) { d = sea_octave((uv+SEA_TIME)*freq,choppy); d += sea_octave((uv-SEA_TIME)*freq,choppy); h += d * amp; uv *= octave_m; freq *= 1.9; amp *= 0.22; choppy = mix(choppy,1.0,0.2); } return p.y - h; } float map_detailed(vec3 p) { float freq = SEA_FREQ; float amp = SEA_HEIGHT; float choppy = SEA_CHOPPY; vec2 uv = p.xz; uv.x *= 0.75; float d, h = 0.0; for(int i = 0; i < ITER_FRAGMENT; i++) { d = sea_octave((uv+SEA_TIME)*freq,choppy); d += sea_octave((uv-SEA_TIME)*freq,choppy); h += d * amp; uv *= octave_m; freq *= 1.9; amp *= 0.22; choppy = mix(choppy,1.0,0.2); } return p.y - h; } vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) { float fresnel = 1.0 - max(dot(n,-eye),0.0); fresnel = pow(fresnel,3.0) * 0.65; vec3 reflected = getSkyColor(reflect(eye,n)); vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12; vec3 color = mix(refracted,reflected,fresnel); float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0); color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten; color += vec3(specular(n,l,eye,60.0)); return color; } // tracing vec3 getNormal(vec3 p, float eps) { vec3 n; n.y = map_detailed(p); n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y; n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y; n.y = eps; return normalize(n); } float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) { float tm = 0.0; float tx = 1000.0; float hx = map(ori + dir * tx); if(hx > 0.0) return tx; float hm = map(ori + dir * tm); float tmid = 0.0; for(int i = 0; i < NUM_STEPS; i++) { tmid = mix(tm,tx, hm/(hm-hx)); p = ori + dir * tmid; float hmid = map(p); if(hmid < 0.0) { tx = tmid; hx = hmid; } else { tm = tmid; hm = hmid; } } return tmid; } // main void main( void ) { EPSILON_NRM = 0.1 / u_resolution.x; SEA_TIME = u_time * SEA_SPEED; vec2 uv = gl_FragCoord.xy / u_resolution.xy; uv = uv * 2.0 - 1.0; uv.x *= u_resolution.x / u_resolution.y; float u_time = u_time * 0.3 + u_mouse.x*0.01; // ray vec3 ang = vec3(sin(u_time*3.0)*0.1,sin(u_time)*0.2+0.3,u_time); vec3 ori = vec3(0.0,3.5,u_time*5.0); vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15; dir = normalize(dir) * fromEuler(ang); // tracing vec3 p; heightMapTracing(ori,dir,p); vec3 dist = p - ori; vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM); vec3 light = normalize(vec3(0.0,1.0,0.8)); // color vec3 color = mix( getSkyColor(dir), getSeaColor(p,n,light,dir,dist), pow(smoothstep(0.0,-0.05,dir.y),0.3)); // post gl_FragColor = vec4(pow(color,vec3(0.75)), 1.0); }