SyntaxBomb - Indie Coders

Languages & Coding => BlitzMax / BlitzMax NG => Topic started by: col on August 23, 2018, 17:09:38

Title: One of the best shaders on ShaderToy.com
Post by: col on August 23, 2018, 17:09:38
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 (https://www.shadertoy.com/view/Ms2SD1). 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
Title: Re: One of the best shaders on ShaderToy.com
Post by: LT on August 23, 2018, 20:00:46
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.

Title: Re: One of the best shaders on ShaderToy.com
Post by: 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.
Title: Re: One of the best shaders on ShaderToy.com
Post by: Naughty Alien on August 24, 2018, 07:29:47
..show the pix mannn :)
Title: Re: One of the best shaders on ShaderToy.com
Post by: col on August 24, 2018, 09:16:07
Quote..show the pix mannn :)

I tried to upload a .gif but it looks like a .png will have to do :)
Title: Re: One of the best shaders on ShaderToy.com
Post by: Steve Elliott on August 24, 2018, 09:25:49
Quote
I tried to upload a .gif but it looks like a .png will have to do :)

How about an exe?  ;D
Title: Re: One of the best shaders on ShaderToy.com
Post by: col on August 24, 2018, 09:43:05
QuoteHow about an exe?  ;D
Done ;)
Title: Re: One of the best shaders on ShaderToy.com
Post by: Steve Elliott on August 24, 2018, 09:50:40
Cheers col.  Yes it's very impressive - and whizzes along!
Title: Re: One of the best shaders on ShaderToy.com
Post by: Naughty Alien on August 24, 2018, 10:18:47
..very nice..so this is attached to some specific renderer or OGL/DX directly from BMX?
Title: Re: One of the best shaders on ShaderToy.com
Post by: Derron on August 24, 2018, 10:27:25
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
Title: Re: One of the best shaders on ShaderToy.com
Post by: col on August 24, 2018, 11:16:09
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.
Title: Re: One of the best shaders on ShaderToy.com
Post by: LT on August 24, 2018, 15:40:05
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.  :(
Title: Re: One of the best shaders on ShaderToy.com
Post by: LT on August 24, 2018, 15:50:45
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?
Title: Re: One of the best shaders on ShaderToy.com
Post by: Steve Elliott on August 24, 2018, 15:55:00
My virus checker scanned it and passed it as safe.
Title: Re: One of the best shaders on ShaderToy.com
Post by: LT on August 24, 2018, 15:59:46
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!  :/
Title: Re: One of the best shaders on ShaderToy.com
Post by: col on August 24, 2018, 16:15:56
QuoteMade a cursory glance at the code and it appears to use geo shaders.
Can you show me where? :P

It's just 1 x OpenGL vertex and pixel shader version 1.2 - very low requirement :)
Title: Re: One of the best shaders on ShaderToy.com
Post by: LT on August 24, 2018, 21:29:07
Quote from: col on August 24, 2018, 16:15:56It's just 1 x OpenGL vertex and pixel shader version 1.2 - very low requirement :)
Well then, I don't know why it doesn't work for me.

EDIT: Coincidentally, I just received back a notice from Avast that the .exe file is clean and I can now run it.  Same result, though, I get an error message saying it can't create the vertex shader.  Strange!

EDIT 2: The other examples work fine, but they're using DX because I'm testing on a Win32 machine.
Title: Re: One of the best shaders on ShaderToy.com
Post by: LT on August 24, 2018, 22:41:18
Found the problem.  In three places, the use of ...

glGetProgramiv(_Id, GL_INFO_LOG_LENGTH, Varptr infoLength)
or
glGetShaderiv(Id, GL_INFO_LOG_LENGTH, Varptr infoLength)

... results in infoLength = 1 because it's returning the NULL character, even though it compiled fine.

Instead of ...

If infoLength > 0

You should probably only call glGet* if the compile status right above it is GL_FALSE.

So anyway, it's working fine for me now and looks cool.  :)
Title: Re: One of the best shaders on ShaderToy.com
Post by: col on August 24, 2018, 23:03:35
Good catch! Nice one! Thanks.

I'm glad it's working for you now.
Don't you just love those OpenGL drivers. It's almost as though it has something to say but then decides... naaah.

I've tweaked that bug in the repo to still allow warnings/errors only when more than one character is output.
Thanks again for looking in to it at your end  8)
Title: Re: One of the best shaders on ShaderToy.com
Post by: Henri on August 25, 2018, 08:52:46
Nicely done ocean, very realistic. And good feedback from LT.

@Avast
My trust in Avast practices isn't that great after I learned that they acquired CCleaner (program I've used a lot) and turned it to something shady https://betanews.com/2018/06/28/avast-ruining-ccleaner/ (https://betanews.com/2018/06/28/avast-ruining-ccleaner/)

-Henri
Title: Re: One of the best shaders on ShaderToy.com
Post by: BasicBoy on January 04, 2019, 18:00:06
Quote from: col on August 23, 2018, 17:09:38
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 (https://www.shadertoy.com/view/Ms2SD1). 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  :)

And here it is running under.... BBC Basic! (I never thought I'd see this, me being of little faith...)





BasicBoy.
--
Title: Re: One of the best shaders on ShaderToy.com
Post by: Steve Elliott on January 04, 2019, 18:23:36
That looks great  :D