One of the best shaders on ShaderToy.com

Started by col, August 23, 2018, 17:09:38

Previous topic - Next topic

col

Hiya,

After giving some advice for takis76 whos trying his/her best to get into shaders I recommended going to ShaderToy.com for some inspiration. While there I saw the most famous and most gorgeous SeaScape by Alexander Alekseev. And I thought.... yeah why not port it to BMax :)

This has got to be one of the most beautiful shaders I've seen so far  :)



SuperStrict
Framework brl.system
Import brl.max2d
Import srs.shaderframework

SetGraphicsDriver GLMax2DDriver()
Local gc:TGraphics = Graphics(1200, 900)

Local sf:TShaderFramework = CreateShaderFramework(gc)
Local DefaultVertexShader:TVertexShader = sf.CreateVertexShader(vertex_source())
If Not DefaultVertexShader
Notify("Could not create vertex shader")
Return
EndIf
Local WaterPixelShader:TPixelShader = sf.CreatePixelShader(pixel_source())
If Not WaterPixelShader
Notify("Could not create pixel shader")
Return
EndIf
Local WaterShader:TShaderProgram = sf.CreateShaderProgram(DefaultVertexShader, WaterPixelShader)
If Not WaterShader
Notify("Could not create water shader")
Return
EndIf

Local resolution:TShaderUniform = WaterShader.GetShaderUniform("iResolution")
Local time:TShaderUniform = WaterShader.GetShaderUniform("iTime")
Local mouse:TShaderUniform = WaterShader.GetShaderUniform("iMouse")

Local quad:TImage = CreateImage(GraphicsWidth(), GraphicsHeight())
resolution.SetFloat2(ImageWidth(quad), ImageHeight(quad))


Global iTime:Float
While Not KeyDown(KEY_ESCAPE) And Not AppTerminate()
Cls
sf.SetShader(WaterShader)

If MouseDown(1)
mouse.SetFloat4(MouseX(), MouseY(), 1.0, 0.0)
Else If MouseDown(2)
mouse.SetFloat4(MouseX(), MouseY(), 1.0, 0.0)
EndIf

time.SetFloat(iTime)
iTime :+ (1.0 / 60.0)
DrawImage(quad, 0, 0)
sf.SetShader(Null)

SetColor 0, 0, 0
DrawText("Original shader source is by Alexander Alekseev - https://www.shadertoy.com/view/Ms2SD1", 10, 10)
Flip 1
Wend

Function vertex_source:String()
Local source:String
source :+ "#version 120~n"
source :+ "uniform vec2      iResolution;           // viewport resolution (in pixels)~n"

source :+ "varying vec4 var_color;~n"
source :+ "varying vec2 fragCoord;~n"

source :+ "void main() {~n"
source :+ "   gl_Position = ftransform();~n"
source :+ "   var_color = gl_Color;~n"
source :+ "   fragCoord = vec2(gl_MultiTexCoord0.s, 1.0 - gl_MultiTexCoord0.t) * iResolution;~n"
source :+ "}~n"
Return source
EndFunction



Function pixel_source:String()
' Original source code is available at https://www.shadertoy.com/view/Ms2SD1

Local glslSource:String

glslSource :+ "#version 120~n"
glslSource :+ "uniform vec4      iMouse;                // mouse pixel coords. xy: current (if MLB down), zw: click~n"
glslSource :+ "uniform vec2      iResolution;           // viewport resolution (in pixels)~n"
glslSource :+ "uniform float     iTime;                 // shader playback time (in seconds)~n"

glslSource :+ "varying vec4 var_color;~n"
glslSource :+ "varying vec2 fragCoord;~n"

glslSource :+ "/*~n"
glslSource :+ " * ~qSeascape~q by Alexander Alekseev aka TDM - 2014~n"
glslSource :+ " * License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.~n"
glslSource :+ " * Contact: tdmaav@gmail.com~n"
glslSource :+ " */~n"
glslSource :+ "~n"
glslSource :+ "const int NUM_STEPS = 8;~n"
glslSource :+ "const float PI = 3.141592;~n"
glslSource :+ "const float EPSILON = 1e-3;~n"
glslSource :+ "#define EPSILON_NRM (0.1 / iResolution.x)~n"
glslSource :+ "~n"
glslSource :+ "// sea~n"
glslSource :+ "const int ITER_GEOMETRY = 3;~n"
glslSource :+ "const int ITER_FRAGMENT = 5;~n"
glslSource :+ "const float SEA_HEIGHT = 0.6;~n"
glslSource :+ "const float SEA_CHOPPY = 4.0;~n"
glslSource :+ "const float SEA_SPEED = 0.8;~n"
glslSource :+ "const float SEA_FREQ = 0.16;~n"
glslSource :+ "const vec3 SEA_BASE = vec3(0.1,0.19,0.22);~n"
glslSource :+ "const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);~n"
glslSource :+ "#define SEA_TIME (1.0 + iTime * SEA_SPEED)~n"
glslSource :+ "const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);~n"
glslSource :+ "~n"
glslSource :+ "// math~n"
glslSource :+ "mat3 fromEuler(vec3 ang) {~n"
glslSource :+ "    vec2 a1 = vec2(sin(ang.x),cos(ang.x));~n"
glslSource :+ "    vec2 a2 = vec2(sin(ang.y),cos(ang.y));~n"
glslSource :+ "    vec2 a3 = vec2(sin(ang.z),cos(ang.z));~n"
glslSource :+ "    mat3 m;~n"
glslSource :+ "    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);~n"
glslSource :+ "    m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);~n"
glslSource :+ "    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);~n"
glslSource :+ "    return m;~n"
glslSource :+ "}~n"
glslSource :+ "float hash( vec2 p ) {~n"
glslSource :+ " float h = dot(p,vec2(127.1,311.7));~n"
glslSource :+ "    return fract(sin(h)*43758.5453123);~n"
glslSource :+ "}~n"
glslSource :+ "float noise( in vec2 p ) {~n"
glslSource :+ "    vec2 i = floor( p );~n"
glslSource :+ "    vec2 f = fract( p );~n"
glslSource :+ " vec2 u = f*f*(3.0-2.0*f);~n"
glslSource :+ "    return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),~n"
glslSource :+ "                     hash( i + vec2(1.0,0.0) ), u.x),~n"
glslSource :+ "                mix( hash( i + vec2(0.0,1.0) ),~n"
glslSource :+ "                     hash( i + vec2(1.0,1.0) ), u.x), u.y);~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "// lighting~n"
glslSource :+ "float diffuse(vec3 n,vec3 l,float p) {~n"
glslSource :+ "    return pow(dot(n,l) * 0.4 + 0.6,p);~n"
glslSource :+ "}~n"
glslSource :+ "float specular(vec3 n,vec3 l,vec3 e,float s) {~n"
glslSource :+ "    float nrm = (s + 8.0) / (PI * 8.0);~n"
glslSource :+ "    return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "// sky~n"
glslSource :+ "vec3 getSkyColor(vec3 e) {~n"
glslSource :+ "    e.y = max(e.y,0.0);~n"
glslSource :+ "    return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4);~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "// sea~n"
glslSource :+ "float sea_octave(vec2 uv, float choppy) {~n"
glslSource :+ "    uv += noise(uv);~n"
glslSource :+ "    vec2 wv = 1.0-abs(sin(uv));~n"
glslSource :+ "    vec2 swv = abs(cos(uv));~n"
glslSource :+ "    wv = mix(wv,swv,wv);~n"
glslSource :+ "    return pow(1.0-pow(wv.x * wv.y,0.65),choppy);~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "float map(vec3 p) {~n"
glslSource :+ "    float freq = SEA_FREQ;~n"
glslSource :+ "    float amp = SEA_HEIGHT;~n"
glslSource :+ "    float choppy = SEA_CHOPPY;~n"
glslSource :+ "    vec2 uv = p.xz; uv.x *= 0.75;~n"
glslSource :+ "~n"
glslSource :+ "    float d, h = 0.0;~n"
glslSource :+ "    for(int i = 0; i < ITER_GEOMETRY; i++) {~n"
glslSource :+ "    d = sea_octave((uv+SEA_TIME)*freq,choppy);~n"
glslSource :+ "    d += sea_octave((uv-SEA_TIME)*freq,choppy);~n"
glslSource :+ "        h += d * amp;~n"
glslSource :+ "    uv *= octave_m; freq *= 1.9; amp *= 0.22;~n"
glslSource :+ "        choppy = mix(choppy,1.0,0.2);~n"
glslSource :+ "    }~n"
glslSource :+ "    return p.y - h;~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "float map_detailed(vec3 p) {~n"
glslSource :+ "    float freq = SEA_FREQ;~n"
glslSource :+ "    float amp = SEA_HEIGHT;~n"
glslSource :+ "    float choppy = SEA_CHOPPY;~n"
glslSource :+ "    vec2 uv = p.xz; uv.x *= 0.75;~n"
glslSource :+ "~n"
glslSource :+ "    float d, h = 0.0;~n"
glslSource :+ "    for(int i = 0; i < ITER_FRAGMENT; i++) {~n"
glslSource :+ "    d = sea_octave((uv+SEA_TIME)*freq,choppy);~n"
glslSource :+ "    d += sea_octave((uv-SEA_TIME)*freq,choppy);~n"
glslSource :+ "        h += d * amp;~n"
glslSource :+ "    uv *= octave_m; freq *= 1.9; amp *= 0.22;~n"
glslSource :+ "        choppy = mix(choppy,1.0,0.2);~n"
glslSource :+ "    }~n"
glslSource :+ "    return p.y - h;~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {~n"
glslSource :+ "    float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0);~n"
glslSource :+ "    fresnel = pow(fresnel,3.0) * 0.65;~n"
glslSource :+ "~n"
glslSource :+ "    vec3 reflected = getSkyColor(reflect(eye,n));~n"
glslSource :+ "    vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;~n"
glslSource :+ "~n"
glslSource :+ "    vec3 color = mix(refracted,reflected,fresnel);~n"
glslSource :+ "~n"
glslSource :+ "    float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);~n"
glslSource :+ "    color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;~n"
glslSource :+ "~n"
glslSource :+ "    color += vec3(specular(n,l,eye,60.0));~n"
glslSource :+ "~n"
glslSource :+ "    return color;~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "// tracing~n"
glslSource :+ "vec3 getNormal(vec3 p, float eps) {~n"
glslSource :+ "    vec3 n;~n"
glslSource :+ "    n.y = map_detailed(p);~n"
glslSource :+ "    n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;~n"
glslSource :+ "    n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;~n"
glslSource :+ "    n.y = eps;~n"
glslSource :+ "    return normalize(n);~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {~n"
glslSource :+ "    float tm = 0.0;~n"
glslSource :+ "    float tx = 1000.0;~n"
glslSource :+ "    float hx = map(ori + dir * tx);~n"
glslSource :+ "    if(hx > 0.0) return tx;~n"
glslSource :+ "    float hm = map(ori + dir * tm);~n"
glslSource :+ "    float tmid = 0.0;~n"
glslSource :+ "    for(int i = 0; i < NUM_STEPS; i++) {~n"
glslSource :+ "        tmid = mix(tm,tx, hm/(hm-hx));~n"
glslSource :+ "        p = ori + dir * tmid;~n"
glslSource :+ "    float hmid = map(p);~n"
glslSource :+ " if(hmid < 0.0) {~n"
glslSource :+ "        tx = tmid;~n"
glslSource :+ "            hx = hmid;~n"
glslSource :+ "        } else {~n"
glslSource :+ "            tm = tmid;~n"
glslSource :+ "            hm = hmid;~n"
glslSource :+ "        }~n"
glslSource :+ "    }~n"
glslSource :+ "    return tmid;~n"
glslSource :+ "}~n"
glslSource :+ "~n"
glslSource :+ "// main~n"
glslSource :+ "void main() {~n"
glslSource :+ " vec2 uv = fragCoord.xy / iResolution.xy;~n"
glslSource :+ "    uv = uv * 2.0 - 1.0;~n"
glslSource :+ "    uv.x *= iResolution.x / iResolution.y;~n"
glslSource :+ "    float time = iTime * 0.3 + iMouse.x*0.01;~n"
glslSource :+ "~n"
glslSource :+ "    // ray~n"
glslSource :+ "    vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);~n"
glslSource :+ "    vec3 ori = vec3(0.0,3.5,time*5.0);~n"
glslSource :+ "    vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;~n"
glslSource :+ "    dir = normalize(dir) * fromEuler(ang);~n"
glslSource :+ "~n"
glslSource :+ "    // tracing~n"
glslSource :+ "    vec3 p;~n"
glslSource :+ "    heightMapTracing(ori,dir,p);~n"
glslSource :+ "    vec3 dist = p - ori;~n"
glslSource :+ "    vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);~n"
glslSource :+ "    vec3 light = normalize(vec3(0.0,1.0,0.8)); ~n"
glslSource :+ "~n"
glslSource :+ "    // color~n"
glslSource :+ "    vec3 color = mix(~n"
glslSource :+ "    getSkyColor(dir),~n"
glslSource :+ "    getSeaColor(p,n,light,dir,dist),~n"
glslSource :+ "    pow(smoothstep(0.0,-0.05,dir.y),0.3));~n"
glslSource :+ "~n"
glslSource :+ "    // post~n"
glslSource :+ " gl_FragColor = vec4(pow(color,vec3(0.75)), 1.0);~n"
glslSource :+ "}~n"
Return glslSource
EndFunction
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

LT

Afraid it doesn't work for me.  It gives me an error: Unhandled Exception:Invalid vertex shader ...on this line.

Local WaterShader:TShaderProgram = sf.CreateShaderProgram(DefaultVertexShader, WaterPixelShader)

Both DefaultVertexShader and WaterPixelShader are Null, for some reason.


col

#2
Does it work when you visit the shadertoy website?

If so then the error may be caused if you have a hybrid GPU setup in your pc/laptop - such as an Intel/NVidia (integrated and high performance) arrangement - you should be able to set the preferred GPU in a control panel setting to the more powerful one. Max2D doesn't take multiple GPUs into account and will use the default one.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Naughty Alien


col

Quote..show the pix mannn :)

I tried to upload a .gif but it looks like a .png will have to do :)
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Steve Elliott

Quote
I tried to upload a .gif but it looks like a .png will have to do :)

How about an exe?  ;D
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

col

https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Steve Elliott

Cheers col.  Yes it's very impressive - and whizzes along!
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

Naughty Alien

..very nice..so this is attached to some specific renderer or OGL/DX directly from BMX?

Derron

it is "basic" BlitzMax (openGL, DX9) and Col's module to ease the pain talking to the shader stuff. As said it is not DX11 ready for now.

Also I am afraid that it wont work with Brucey's sdl.mod yet (android/iOS/raspberry) - same to say for the render2texture module. Col is surely aware of it. But life has more interesting things here and there. So no excuse needed.

bye
Ron

col

As Derron says, I'm not doing anything special at all. I'm just setting up the shader stuff is about as far as credit goes for me. You could just as easily run this in MiniB3D, and any other renderer that supports shaders.

All credit rightly goes to the original shader author who clearly has some great math skills. Everything you see is being created in real-time in the pixel shader alone - amazing.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

LT

Quote from: col on August 24, 2018, 07:09:26
Does it work when you visit the shadertoy website?

If so then the error may be caused if you have a hybrid GPU setup in your pc/laptop - such as an Intel/NVidia (integrated and high performance) arrangement - you should be able to set the preferred GPU in a control panel setting to the more powerful one. Max2D doesn't take multiple GPUs into account and will use the default one.

Yes, the website link worked.  I have a dedicated Nvidia graphics card.  Also, I couldn't run the .exe - Avast wouldn't let me.  :(

LT

Quote from: col on August 24, 2018, 11:16:09You could just as easily run this in MiniB3D, and any other renderer that supports shaders.
Made a cursory glance at the code and it appears to use geo shaders.  OpenGL version requirement?

Steve Elliott

My virus checker scanned it and passed it as safe.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

LT

Quote from: Steve Elliott on August 24, 2018, 15:55:00
My virus checker scanned it and passed it as safe.
Avast won't let me run it and actually sent it automatically for interrogation.  It didn't even ask me!  :/