Author Topic: Animated Backgrounds?  (Read 55937 times)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #75 on: December 13, 2019, 08:28:16 pm »
By me the sky is black as you can see on this screen shot

Here is the shader i am using:

uniform vec4 iDate; // (year, month, day, time in seconds) MLL: year/month/day not used
uniform vec3 iMouse; // mouse pixel coords. xy: current (if MLB down); if vec3 then z: click
uniform vec2 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)
uniform sampler2D nomip_colornoise_png; // texture in TU0

#define T texture(nomip_colornoise_png, (s * p.zw + ceil(s * p.x)) / 2e2).y / (s += s) * 4.0

void main() {
    vec4 p;
    vec4 d = vec4(0.8, 0.0, gl_FragCoord.xy / iResolution.y - 0.7); // MLL: was -0.8
    vec4 c = vec4(0.6, 0.7, d);
    gl_FragColor = c - d.w;

    float f, s;
    for (float t = 2e2 + sin(dot(gl_FragCoord, gl_FragCoord)); --t > 0.0; p = 0.065 * t * d) { // MLL: was =0.05
        p.xz += iTime;
        s = 1.0; // MLL: was 2.0
        f = p.w + 1.0 - T - T - T - T;
       if (f < 0.0)
            gl_FragColor += (gl_FragColor - 1.0 - 0.75 * f * c.zyxw) * f * 0.4; // MLL: added 0.75*
    }
}
« Last Edit: December 13, 2019, 08:30:04 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #76 on: December 13, 2019, 09:48:50 pm »
It gets dark only if a model is/was loaded. Otherwise, it's originally blue.

This most likely means that some texture unit does not get properly reset/cleared after the model render pass in the previous render frame before the background shader is drawn in the current render frame.

This will need some time to debug. I think I'll be able to do it tomorrow. It's near midnight here now.
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #77 on: December 13, 2019, 10:03:15 pm »
Quote
It gets dark only if a model is/was loaded. Otherwise, it's originally blue
Absolutly true!

If i start robots2 with the anilight layer, then select tinyclouds, the sky is black, else it is blue  ???
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #78 on: December 14, 2019, 03:06:34 am »
In fact, we have two shaders whose colors suffer on model loading: TinyClouds.fs and MatrixRadial.fs. I have fixed both of them.

1. TinyClouds.fs: (may not reassign built-in uniforms such as gl_FragColor)

uniform vec4 iDate; // (year, month, day, time in seconds) MLL: year/month/day not used
uniform vec3 iMouse; // mouse pixel coords. xy: current (if MLB down); if vec3 then z: click
uniform vec2 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)
uniform sampler2D nomip_colornoise_png; // texture in TU0

#define T texture(nomip_colornoise_png, (s * p.zw + ceil(s * p.x)) / 2e2).y / (s += s) * 4.0

void main() {
    vec4 p;
    vec4 d = vec4(0.8, 0.0, gl_FragCoord.xy / iResolution.y - 0.7); // MLL: was -0.8
    vec4 c = vec4(0.6, 0.7, d);
    vec4 color = c - d.w;

    float f, s;
    for (float t = 2e2 + sin(dot(gl_FragCoord, gl_FragCoord)); --t > 0.0; p = 0.065 * t * d) { // MLL: was =0.05
        p.xz += iTime;
        s = 1.0; // MLL: was 2.0
        f = p.w + 1.0 - T - T - T - T;
        if (f < 0.0)
            color += (color - 1.0 - 0.75 * f * c.zyxw) * f * 0.4; // MLL: added 0.75*
    }
    gl_FragColor = vec4(color.rgb, 1.0);
}


2. MatrixRadial.fs: (gl_FragColor alpha must always be 1.0)

Change the shader's last-but-one line to
  gl_FragColor = vec4((c * (1. - dot(g, g)) * .2 / abs((fract(f) - .5) * 8.)).rgb, 1.);


3. And Patrice, we're having problems with your recent mods. If an animated background shader is running without a model and Animate reset is on (which it usually is), then D&D'ing a model to load into the viewport freezes it at its farthest distance and makes the viewport not responsive to the mouse. To revive it, Close all and clear scene must be clicked.

Can you look into this matter?
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #79 on: December 14, 2019, 10:13:00 am »
Thank you for the shader fixes, both of them work well now.

About point 3, i do not see the same behavior than you.
The animation is freezed while loading the D&D model (seems normal to me),
and the animation listview becomes unresponsive.

I shall look at this in debug mode to understand what is going on.
And first i have to remember the purpose of "Animate reset" (i almost never use it) ;)

Added:
There is definitly a problem with the listview when using shaders.
« Last Edit: December 14, 2019, 11:33:11 am by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #80 on: December 14, 2019, 01:44:44 pm »
Patrice,

Animate reset is animation (slow motion zoom and rotation) of the model when it is reset to its [0,0] initial position on load or on clicking Reset view. (see AnimateReset video below)

Now watch how it all stalls for me in the latest OR build: (see BrokenModelLoad video below)

0. When in animated backgrounds mode, the listview selection doesn't follow the mouse click on another shader.
1. Neither does the listview remember the animated shader it was running when Reload model is clicked. It simply reverts to the default static background.
2. When an animated background is running, an attempt to drag-and-drop a model into the viewport freezes the model and background at its farthest position in the zoom sequence.
3. If the viewport is clicked at this point in time, the animated background changes to static but the model remains unmovable until Close all and clear scene. Finally, all this havoc ends up in shaders not being able to compile and link at all for some unknown reason... :(
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #81 on: December 14, 2019, 01:49:58 pm »
Now see how it all worked (listview selection of animated shaders, model D&D and animated zoom on load, and model reload with anibkgnd still staying the same) in my previous build of OR before any of your latest 2.81/2.83 mods were introduced.  ???
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #82 on: December 14, 2019, 01:54:13 pm »
I guess I'll have to do all the cleanup myself eventually because I don't think you are aware of all the pitfalls and bottlenecks there are in such a sensitive organism as modern ObjReader... :-\
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #83 on: December 14, 2019, 01:56:45 pm »
Here are a couple of fixes to apply into Main.cpp

Close to the end of gl_LoadModel
near line 1344
        // resetCurAniShader(); // PAT: 12-14-2019 done in parseAniShader
        parseAniShader(gsw_wallpaper);
        if (gl_LoadAniBackgrounds(GetDlgItem(gP.hMain, IDC_LISTBOX), gsw_wallpaper)) {
            gP.tCurAniBkgndShader.nShaderID = glsl_LoadShaderFromFile(gsw_wallpaper); // PAT: 11-25-2019 char to wchar
            if (gP.tCurAniBkgndShader.nShaderID) {
                wcscopy(gsw_shader, gsw_wallpaper);
                rAniStart = GetTickCount64() / 1000.0f;
                StartSync();
                CheckMenuItem(gR.hAniMenu, MENU_ANI_BKGND, MF_CHECKED);
            }
        }


In case MENU_ANI_BKGND
near line 2332
    case MENU_ANI_BKGND: // MLL 06-01-2019: ani backgrounds
        gP.bAniBkgnd = !gP.bAniBkgnd;
        if (gP.bAniBkgnd) {
            dwStyle = MF_CHECKED;
            // resetCurAniShader(); // PAT: 12-14-2019 done in parseAniShader
            if (lstrlen(gsw_shader) == 0) { // PAT: 11-25-2019
                wcscopy(zPath, L"voronoi.fs"); // default
            } else {
                wcscopy(zPath, gsw_shader);
            }
            parseAniShader(zPath); // PAT: 11-25-2019
            if (!gl_LoadAniBackgrounds(GetDlgItem(gP.hMain, IDC_LISTBOX), zPath)) { // PAT: 11-25-2019
                CheckMenuItem(gR.hAniMenu, MENU_ANI_BKGND, MF_UNCHECKED);
                EnableMenuItem(gR.hAniMenu, MENU_ANI_BKGND, MF_GRAYED);
                break;
            }
            gP.tCurAniBkgndShader.nShaderID = glsl_LoadShaderFromFile(zPath); // PAT: 11-25-2019 char to wchar
            rAniStart = GetTickCount64() / 1000.0f;
            StartSync();
        } else {


In case WM_NOTIFY:
near line 3016

            if ((ptNMLV->hdr.code == LVN_ITEMCHANGED) || (ptNMLV->hdr.code == NM_CLICK)) {
                // N.B. Patrice: on LMB down, list box sends both these messages one after another,
                // which means wallpaper is reloaded twice. It's fast and unnoticeable for PNGs but
                // not so in case of shaders. Comparison with static "last-used" buffer will help
                // to avoid unnecessary reloads.
                static WCHAR wasFile[MAX_PATH];
                ListView_GetItemText(hCtrl, ListView_GetCurrentLine(hCtrl), 0, &zTxt[0], MAX_PATH);
                if (*zTxt && (lstrcmpi(wasFile, zTxt) != 0)) {
                    StringCchCopy(wasFile, MAX_PATH - 1, zTxt);
                    if (gP.bAniBkgnd) { // MLL 06-01-2019: ani backgrounds
                        if (parseAniShader(zTxt)) {
                            //gP.tCurAniBkgndShader.nShaderID = glsl_LoadShaderFromFile(wcsconv(zTxt));
                            gP.tCurAniBkgndShader.nShaderID = glsl_LoadShaderFromFile(zTxt); // PAT: 11-25-2019 wchar is now the default
                            rAniStart = GetTickCount64() / 1000.0f;
                            StartSync();
                        }
                        WindowRedraw(hCtrl); // PAT: 12-14-2019
                    } else {
                        Path_Combine(gP.mt.FullName, EXEresource(), zTxt);
                        if (ZI_UpdateNamedGLTextureFromFileEx(gP.mt.FullName, gP.mt.Texture, gP.mt.Square) == 0) {
                            Mobj_setWallPaper(gP.mt.FullName);
                            gP.bRedraw = TRUE; // Redraw the OpenGL scene
                        }
                    }
                }
            }


Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #84 on: December 14, 2019, 02:01:25 pm »
Remember I am using Windows 10.

Also make a quick test with the binary attached to this post, just to make sure we are using exactly the same code.

Because i am unable to reproduce the behavior shown on your video(s) with the binary i am using.

« Last Edit: December 14, 2019, 02:05:21 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #85 on: December 14, 2019, 02:16:14 pm »
The binaries operate differently for me (I haven't yet added your fixes above). Yours doesn't freeze the listview focus. But it still freezes Animate reset on model load, and it doesn't preserve the current animated background on model load or reload simply resetting it to the default static back02.jpg at all times (except when specified explicitly in the MAT file).
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #86 on: December 14, 2019, 02:48:08 pm »
Re. Win 10

Strategically:

I know MS is quitting Win 7 support completely this coming February. I'll be moving my GTX1060 and monitors to my Win 10 box making it my main development workstation.

But I stay strongly in favor of backwards compatibility. Our product isn't an AAA computer game, after all, but a rank and file indie hobbyist model viewer despite all its merits among its compatibles.

Therefore, I'll keep the both of my Win 7 boxes (AMD/ATi Radeon and nVidia/GTX550) at ready to be constantly checking OR for backwards compatibility because I know there's gonna be millions of Win 7 fans for many years to come, with or without MS support. And I will not be considering OR builds ready for public release until they are fully functional under, and compatible with, both Win 10 and Win 7. ::)
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #87 on: December 14, 2019, 02:49:19 pm »
Here is another fix that should solve the suzanne behavior shown on your video

void gl_LoadModel(IN WCHAR* pszFilename) {

    BassCloseChannel(); // 10-09-2019 Bass.dll
    ClearMemory(&gB.playaudio, sizeof(gB.playaudio));
    gB.volume = 0.125f; // 10-09-2019 Bass.dll
    gB.loop = 0;        // 10-09-2019 Bass.dll

    if (gP.bObjectLoaded || gP.bAniBkgnd) // PAT: 12-06-2019
        gl_CloseAll();


AND in gl_CloseAll

void gl_CloseAll() { // MLL 12-20-2018: unload model and reset viewport
    RECT vr = { 0 };

    //if (gP.bObjectLoaded) { // PAT: 12-14-2017
        BassCloseChannel();
        ClearMemory(&gP.wModelPath, sizeof(gP.wModelPath));
Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1983
    • zapsolution
Re: Animated Backgrounds?
« Reply #88 on: December 14, 2019, 02:55:56 pm »
When anything works as expected by me on W10, i just assume it would work the same on Seven, but i have no way to make sure of this, except when my friend check the same code on his computer  ;)

Added:
The Galvanize.fs shader
Code: [Select]
//***************************************************************************************************
//
// Galvanize / Alcatraz
// Jochen "Virgill" Feldkoetter
//
// Intro for Nordlicht demoparty 2014      Shadertoy version
//
//***************************************************************************************************

uniform vec4 iDate; // (year, month, day, time in seconds) MLL: year/month/day not used
uniform vec3 iMouse; // mouse pixel coords. xy: current (if MLB down); if vec3 then z: click
uniform vec2 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)

int efx = 0;
int refleco = 0;
int snowo = 0;
vec4 orbitTrap = vec4(0.0);
float blend =0.0;
float d = 0.0;
float m = 0.0;
float kalitime =0.;
float depth = 0.;     
float prec =0.;
const float scene = 35.;


// Rotate
vec3 rotXaxis(vec3 p, float rad)
{
float z2 = cos(rad) * p.z - sin(rad) * p.y;
float y2 = sin(rad) * p.z + cos(rad) * p.y;
p.z = z2;
p.y = y2;
return p;
}

vec3 rotYaxis(vec3 p, float rad)
{
float x2 = cos(rad) * p.x - sin(rad) * p.z;
float z2 = sin(rad) * p.x + cos(rad) * p.z;
p.x = x2;
p.z = z2;
return p;
}

vec3 rotZaxis(vec3 p, float rad)
{
float x2 = cos(rad) * p.x - sin(rad) * p.y;
float y2 = sin(rad) * p.x + cos(rad) * p.y;
p.x = x2;
p.y = y2;
return p;
}


// noise functions
float rand1(vec2 co)
{
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float rand2(vec2 co)
{
    return fract(cos(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}




// polyomial smooth min (IQ)
float sminPoly( float a, float b, float k )
{
    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
    return mix( b, a, h ) - k*h*(1.0-h);
}


// exponential smooth min (IQ)
float smin( float a, float b, float k )
{
    float res = exp( -k*a ) + exp( -k*b );
    return -log( res )/k;
}


// length
float length2(vec2 p)
{
  return dot(p, p);
}

// worley effect
float worley(vec2 p)
{
float d = 1.;
for (int xo = -1; xo <= 1; ++xo)
for (int yo = -1; yo <= 1; ++yo)
    {
vec2 tp = floor(p) + vec2(xo, yo);
d = min(d, length2(p - tp - vec2(rand1(tp))));
}
return 3.*exp(-4.*abs(2.*d - 1.));
}

float fworley(vec2 p)
{
return sqrt(sqrt(sqrt(worley(p*32. + 4.3 + iTime*.250) * sqrt(worley(p * 64. + 5.3 + iTime * -.125)) * sqrt(sqrt(worley(p * -128. +7.3))))));
}


// menger
float NewMenger(vec3 z)
{
float Scale = 3.0;
vec3 Offset = vec3(1.0,1.0,1.0);
int Iterations = 6;
int ColorIterations = 3;

    for(int n = 0; n < 6; n++)
{
z.z*=1.+0.2*sin(iTime/4.0)+0.1;
z = abs(z);
if (z.x<z.y){ z.xy = z.yx;}
if (z.x< z.z){ z.xz = z.zx;}
if (z.y<z.z){ z.yz = z.zy;}
z = Scale*z-Offset*(Scale-1.0);
if( z.z<-0.5*Offset.z*(Scale-1.0))  z.z+=Offset.z*(Scale-1.0);

if (n<ColorIterations) orbitTrap = min(orbitTrap, (vec4(abs(z),dot(z,z))));

}
return abs(length(z) ) * pow(Scale, float(-Iterations-1));
}



// mandelbulb (Fractalforums.com)
float Mandelbulb(vec3 p)
{
float Scale = 3.0;
int Iterations = 6;
int ColorIterations = 1;
float parachute=(1.-min(1.8*abs(sin((iTime-5.0)*3.1415/scene)),1.0)); // Fallschirm
parachute = smoothstep(0.0,1.0,parachute)*35.0;
vec3 w = p;
float dr = 1.0+parachute;
float r = 0.;
    for (int i=0; i<6; ++i)
{
    r = length(w);
if (r>4.0) break;
dr*=pow(r, 7.)*8.+1.;
float x = w.x; float x2 = x*x; float x4 = x2*x2;
float y = w.y; float y2 = y*y; float y4 = y2*y2;
float z = w.z; float z2 = z*z; float z4 = z2*z2;
float k3 = x2 + z2;
float k2 = inversesqrt( pow(k3, 7.0) );
float k1 = x4 + y4 + z4 - 6.0*y2*z2 - 6.0*x2*y2 + 2.0*z2*x2;
float k4 = x2 - y2 + z2;
w =  vec3(64.0*x*y*z*(x2-z2)*k4*(x4-6.0*x2*z2+z4)*k1*k2,-16.0*y2*k3*k4*k4 + k1*k1,-8.0*y*k4*(x4*x4 - 28.0*x4*x2*z2 + 70.0*x4*z4 - 28.0*x2*z2*z4 + z4*z4)*k1*k2);
w-=p;
w = rotYaxis(w,sin(iTime*0.14));
w = rotZaxis(w,cos(iTime*0.2));
orbitTrap = min(orbitTrap, abs(vec4(p.x*w.z, p.y*w.x, 0., 0.)));
if (i>=ColorIterations+2) orbitTrap = vec4(0.0);
}
return  .5*log(r)*r/dr;
}

// kalibox (Kali / Fractalforums.com)
float Kalibox(vec3 pos)
{
float Scale = 1.84;
int Iterations = 14;
int ColorIterations = 3;
float MinRad2 = 0.34;
vec3 Trans = vec3(0.076,-1.86,0.036);
vec3 Julia = vec3(-0.66,-1.2+(kalitime/80.),-0.66);
vec4 scale = vec4(Scale, Scale, Scale, abs(Scale)) / MinRad2;
float absScalem1 = abs(Scale - 1.0);
float AbsScaleRaisedTo1mIters = pow(abs(Scale), float(1-Iterations));
    vec4 p = vec4(pos,1), p0 = vec4(Julia,1);
for (int i=0; i<14; i++)
{
p.xyz=abs(p.xyz)+Trans;
float r2 = dot(p.xyz, p.xyz);
p *= clamp(max(MinRad2/r2, MinRad2), 0.0, 1.0);
p = p*scale + p0;
if (i<ColorIterations) orbitTrap = min(orbitTrap, abs(vec4(p.xyz,r2)));
}
return (    (length(p.xyz) - absScalem1) / p.w - AbsScaleRaisedTo1mIters    );
}

// balls and cube
float Balls(vec3 pos)
{
m = length(max(abs(rotYaxis(rotXaxis(pos+vec3(0.0,-0.3,0.0),iTime),iTime*0.3))-vec3(0.35,0.35,0.35),0.0))-0.02;
m = smin (m, length(pos+vec3(0.0,-0.40,1.2+0.5*sin(0.8*iTime+0.0)))-0.4,7.4);
m = smin (m, length(pos+vec3(0.0,-0.40,-1.2-0.5*sin(0.8*iTime+0.4)))-0.4,7.4);
m = smin (m, length(pos+vec3(-1.2-0.5*sin(0.8*iTime+0.8),-0.40,0.0))-0.4,7.4);
m = smin (m, length(pos+vec3(1.2+0.5*sin(0.8*iTime+1.2),-0.40,0.0))-0.4,7.4);
m = smin (m, length(pos+vec3(0.0,-1.6+0.5*-sin(0.8*iTime+1.6),0.0))-0.4,7.4);
//m+= klang1*(0.003*cos(50.*pos.x)+0.003*cos(50.*pos.y)); //distortion
orbitTrap = vec4(length(pos)-0.8*pos.z,length(pos)-0.8*pos.y,length(pos)-0.8*pos.x,0.0)*1.0;
return m;
}

// plane
float sdPlane(in vec3 p)
{
return p.y+(0.025*sin(p.x*10.  +1.4*iTime  ))+(0.025*sin(p.z*12.3*cos(0.4-p.x)+  1.6*iTime  ))-0.05;
}

// cylinder
float sdCylinder( vec3 p, vec3 c )
{
return length(p.xz-c.xy)-c.z;
}


// scene
float map(in vec3 p)
{
orbitTrap = vec4(10.0);
d = sdPlane(p);

if (efx == 0) { // balls and cube
m = Balls(p);
}
if (efx == 1) { // milky menger
m = NewMenger(rotYaxis(rotXaxis(p-vec3(0.0,sin(iTime/0.63)+0.2,0.0),0.15*iTime),0.24*iTime));
}
if (efx == 2) { // mandelbulb
m = Mandelbulb(rotYaxis(rotXaxis(p,iTime*0.1),0.21*iTime));
}
if (efx == 3) { // kalibox
m = Kalibox(rotYaxis(rotXaxis(p,1.50),0.1*iTime));
}
if (efx == 4 || efx == 5) { // tunnel or swirl
vec3 c = vec3(2.0, 8.0, 2.0);
vec3 q = mod(p-vec3(1.0,0.1*iTime,1.0),c)-0.5*c;
float kali = Kalibox(rotYaxis(q,0.04*iTime));
m = max(kali,-sdCylinder(p,vec3(0.0,0.0,0.30+0.1*sin(iTime*0.2))) );
}
d = sminPoly (m, d, 0.04);
    return d;
}


// normal calculation
vec3 calcNormal(in vec3 p)
{
    vec3 e = vec3(0.001, 0.0, 0.0);
    vec3 nor = vec3(map(p + e.xyy) - map(p - e.xyy),  map(p + e.yxy) - map(p - e.yxy),  map(p + e.yyx) - map(p - e.yyx));
    return normalize(nor);
}

// cast
float castRay(in vec3 ro, in vec3 rd, in float maxt)
{
    float precis = prec;
    float h = precis * 2.0;
    float t = depth;

    for(int i = 0; i < 122; i++)
{
        if(abs(h) < precis || t > maxt) break;
        orbitTrap = vec4(10.0);
h = map(ro + rd * t);
        t += h;
}
    return t;
}

// softshadow (IQ)
float softshadow(in vec3 ro, in vec3 rd, in float mint, in float maxt, in float k)
{
    float sh = 1.0;
    float t = mint;
    float h = 0.0;
    for(int i = 0; i < 19; i++)  //23 gut!
{
        if(t > maxt) continue;
orbitTrap = vec4(10.0);
        h = map(ro + rd * t);
        sh = min(sh, k * h / t);
        t += h;
    }
    return sh;
}


// orbit color
vec3 BaseColor = vec3(0.2,0.2,0.2);
vec3 OrbitStrength = vec3(0.8, 0.8, 0.8);
vec4 X = vec4(0.5, 0.6, 0.6, 0.2);
vec4 Y = vec4(1.0, 0.5, 0.1, 0.7);
vec4 Z = vec4(0.8, 0.7, 1.0, 0.3);
vec4 R = vec4(0.7, 0.7, 0.5, 0.1);
vec3 getColor()
{
orbitTrap.w = sqrt(orbitTrap.w);
vec3 orbitColor = X.xyz*X.w*orbitTrap.x + Y.xyz*Y.w*orbitTrap.y + Z.xyz*Z.w*orbitTrap.z + R.xyz*R.w*orbitTrap.w;
vec3 color = mix(BaseColor,3.0*orbitColor,OrbitStrength);
return color;
}

// particles (Andrew Baldwin)
float snow(vec3 direction)
{
float help = 0.0;
const mat3 p = mat3(13.323122,23.5112,21.71123,21.1212,28.7312,11.9312,21.8112,14.7212,61.3934);
vec2 uvx = vec2(direction.x,direction.z)+vec2(1.,iResolution.y/iResolution.x)*gl_FragCoord.xy / iResolution.xy;
float acc = 0.0;
float DEPTH = direction.y*direction.y-0.3;
float WIDTH =0.1;
float SPEED = 0.1;
for (int i=0;i<10;i++)
{
float fi = float(i);
vec2 q = uvx*(1.+fi*DEPTH);
q += vec2(q.y*(WIDTH*mod(fi*7.238917,1.)-WIDTH*.5),SPEED*iTime/(1.+fi*DEPTH*.03));
vec3 n = vec3(floor(q),31.189+fi);
vec3 m = floor(n)*.00001 + fract(n);
vec3 mp = (31415.9+m)/fract(p*m);
vec3 r = fract(mp);
vec2 s = abs(mod(q,1.)-.5+.9*r.xy-.45);
float d = .7*max(s.x-s.y,s.x+s.y)+max(s.x,s.y)-.01;
float edge = .04;
acc += smoothstep(edge,-edge,d)*(r.x/1.0);
help = acc;
}
return help;
}

void main()
{
   
    if (iTime >=0. && iTime <=35. ) {efx=4; refleco=0; snowo=0;}
    if (iTime >35. && iTime <=70. ) {efx=0; refleco=1; snowo=1;}
    if (iTime >70. && iTime <=105.) {efx=1; refleco=0; snowo=1;}
    if (iTime >105.&& iTime <=140.) {efx=3; refleco=0; snowo=1;}
    if (iTime >140.&& iTime <=175.) {efx=2; refleco=0; snowo=1;} 
    if (iTime >175.&& iTime <=210.) {efx=4; refleco=0; snowo=0;}   
    if (iTime >210.&& iTime <=245.) {efx=5; refleco=0; snowo=0;} 

blend=min(2.0*abs(sin((iTime+0.0)*3.1415/scene)),1.0);
    if (iTime >245.) blend = 0.;
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec2 p = uv * 2.0 - 1.0;
p.x *= iResolution.x / iResolution.y;
float theta = sin(iTime*0.03) * 3.14 * 2.0;
    float x = 3.0 * cos(theta)+0.007*rand1(gl_FragCoord.xy);
    float z = 3.0 * sin(theta)+0.007*rand2(gl_FragCoord.xy);
vec3 ro; // camera

if (efx==0) {
prec = 0.001;
ro = vec3(x*0.2+1.0, 5.0, z*2.0-3.); // camera balls and cube 
}
if (efx==1) {
prec = 0.002;
ro = vec3(x*1.2, 7.0, z*2.0);  // camera menger
}
if (efx==2) {
prec = 0.002;
ro = vec3(x*1.0, 6.2, z*2.8);  // camera mandelbulb
depth =4.;
}
if (efx==3) {
kalitime = 40.;
prec = 0.002;
ro = vec3(x*1.7, 2.6, 2.0); // camera kalibox
}
if (efx==4) {
//time = iTime -2.5;
prec = 0.002;
kalitime = iTime-15.0;
ro = vec3(0.0, 8.0, 0.0001);    // camera tunnel
}
if (efx==5) {
prec = 0.004;
kalitime = 210.+175.;
ro = vec3(0, 3.8, 0.0001);    // camera swirl
}


vec3 ta = vec3(0.0, 0.25, 0.0);
    vec3 cw = normalize(ta - ro);
    vec3 cp = vec3(0.0, 1.0, 0.0);
    vec3 cu = normalize(cross(cw, cp));
    vec3 cv = normalize(cross(cu, cw));
vec3 rd = normalize(p.x * cu + p.y * cv + 7.5 * cw);

// render:
    vec3 col = vec3(0.0);
    float t = castRay(ro, rd, 12.0);
vec3 pos = ro + rd *t;
vec3 nor = calcNormal(pos);
vec3 lig;
if (efx==4 || efx ==5 )  lig = normalize(vec3(-0.4*sin(iTime*0.15), 1.0, 0.5));
else if (efx==3)   lig = normalize(vec3(-0.1*sin(iTime*0.2), 0.2, 0.4*sin(iTime*0.1)));
else lig = normalize(vec3(-0.4, 0.7, 0.5));
float dif = clamp(dot(lig, nor), 0.0, 1.0);
float spec = pow(clamp(dot(reflect(rd, nor), lig), 0.0, 1.0), 16.0);
float sh;
if (efx == 1 || efx == 5) sh = softshadow(pos, lig, 0.02, 20.0, 7.0);
vec3 color = getColor();
col = ((0.8*dif+ spec) + 0.35*color);
if (efx !=1 && efx != 5) sh = softshadow(pos, lig, 0.02, 20.0, 7.0);
col = col*clamp(sh, 0.0, 1.0);


// reflections:
if (refleco == 1) {
    vec3 col2 = vec3(0.0);
vec3 ro2 = pos-rd/t;
vec3 rd2 = reflect(rd,nor);
    float t2 = castRay(ro2, rd2, 7.0);
vec3 pos2 = vec3(0.0);
if (t2<7.0) {
pos2 = ro2 + rd2* t2;
}
    vec3 nor2 = calcNormal(pos2);
float dif2 = clamp(dot(lig, nor2), 0.0, 1.0);
float spec2 = pow(clamp(dot(reflect(rd2, nor2), lig), 0.0, 1.0), 16.0);
col+= 0.22*vec3(dif2*color+spec2);
}

// postprocessing
float klang1=0.75;
vec2 uv2=-0.3+2.*gl_FragCoord.xy/iResolution.xy;
col-=0.20*(1.-klang1)*rand1(uv2.xy*iTime);
col*=.9+0.20*(1.-klang1)*sin(10.*iTime+uv2.x*iResolution.x);
col*=.9+0.20*(1.-klang1)*sin(10.*iTime+uv2.y*iResolution.y);
float Scr=1.-dot(uv2,uv2)*0.15;
vec2 uv3=gl_FragCoord.xy/iResolution.xy;
float worl = fworley(uv3 * iResolution.xy / 2100.);
worl *= exp(-length2(abs(2.*uv3 - 1.)));
worl *= abs(1.-0.6*dot(2.*uv3-1.,2.*uv3-1.));
if (efx==4) col += vec3(0.4*worl,0.35*worl,0.25*worl);
if (efx==5)  col += vec3(0.2*worl);
float g2 = (blend/2.)+0.39;
float g1 = ((1.-blend)/2.);
if (uv3.y >=g2+0.11) col*=0.0;
if (uv3.y >=g2+0.09) col*=0.4;
if (uv3.y >=g2+0.07) {if (mod(uv3.x-0.06*iTime,0.18)<=0.16) col*=0.5;}
if (uv3.y >=g2+0.05) {if (mod(uv3.x-0.04*iTime,0.12)<=0.10) col*=0.6;}
if (uv3.y >=g2+0.03) {if (mod(uv3.x-0.02*iTime,0.08)<=0.06) col*=0.7;}
if (uv3.y >=g2+0.01) {if (mod(uv3.x-0.01*iTime,0.04)<=0.02) col*=0.8;}
if (uv3.y <=g1+0.10) {if (mod(uv3.x+0.01*iTime,0.04)<=0.02) col*=0.8;}
if (uv3.y <=g1+0.08) {if (mod(uv3.x+0.02*iTime,0.08)<=0.06) col*=0.7;}
if (uv3.y <=g1+0.06) {if (mod(uv3.x+0.04*iTime,0.12)<=0.10) col*=0.6;}
if (uv3.y <=g1+0.04) {if (mod(uv3.x+0.06*iTime,0.18)<=0.16) col*=0.5;}
if (uv3.y <=g1+0.02) col*=0.4;
if (uv3.y <=g1+0.00) col*=0.0;

if (snowo == 1) gl_FragColor = (vec4(col*1.0*Scr-1.6*snow(cv), 1.0)*blend)*vec4(1.0, 0.93, 1.0, 1.0);
else gl_FragColor = vec4(col*1.0*Scr, 1.0)*blend;
}

« Last Edit: December 14, 2019, 03:54:56 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animated Backgrounds?
« Reply #89 on: December 14, 2019, 04:12:16 pm »
Your shader is beautiful but very heavy; with Turbo off and under FXAA, my GPU is 75%+ full-screen...

Here's another one from your list:

FractalFlythrough.fs

Code: [Select]
/*
Fractal Flythrough
------------------

Moving a camera through a fractal object. It's a work in progress.

I was looking at one of Dr2's shaders that involved moving a camera through a set of way points (set
out on the XZ plane), and thought it'd be cool to do a similar 3D version. The idea was to create a
repetitive kind of fractal object, give the open space nodes a set random direction, create some
spline points, then run a smooth camera through them. Simple... right? It always seems simple in my
head, but gets progressively harder when I try it in a shader. :)

I've run into that classic up-vector, camera flipping problem... At least, I think that's the problem?
Anyway, I'm hoping the solution is simple, and that someone reading this will be able to point me in
the right direction.

For now, I've set up a set of 16 random looping points that the camera seems reasonably comfortable
with. Just for the record, the general setup works nicely, until the camera loops back on itself in
the YZ plane. I'm guessing that increasing the number of way points may eradicate some of the
    intermittent camera spinning, but I figured I'd leave things alone and treat it as a feature. :)

By the way, I was thankful to have Otavio Good's spline setup in his "Alien Beacon" shader as a
reference. On a side note, that particular shader is one of my all time favorites on this site.

The rendering materials are slightly inspired by the Steampunk genre. Timber, granite, brass, etc.
It needs spinning turbines, gears, rivots, and so forth, but that stuff's expensive. Maybe later.
Tambako Jaguar did a really cool shader in the Steampunk aesthetic. The link is below.

Besides camera path, there's a whole bunch of improvements I'd like to make to this. I've relied on
occlusion to mask the fact that there are no shadows. I'm hoping to free up some cycles, so I can put
them back in. I'd also like to add extra detail, but that also slows things down. As for the comments,
they're very rushed, but I'll tidy those up as well.

References:

Alien Beacon - Otavio Good
https://www.shadertoy.com/view/ld2SzK

    Steampunk Turbine - TambakoJaguar
    https://www.shadertoy.com/view/lsd3zf

    // The main inspiration for this shader.
Mandelmaze in Daylight - dr2
    https://www.shadertoy.com/view/MdVGRc
*/

uniform vec4 iDate; // (year, month, day, time in seconds) MLL: year/month/day not used
uniform vec3 iMouse; // mouse pixel coords. xy: current (if MLB down); if vec3 then z: click
uniform vec2 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)
uniform sampler2D metal_jpg;

const float FAR = 50.0; // Far plane.

// Used to identify individual scene objects. In this case, there are only three: The metal framework, the gold
// and the timber.
float objID = 0.; // Wood = 1., Metal = 2., Gold = 3..

// Simple hash function.
float hash( float n ){ return fract(cos(n)*45758.5453); }

// Tri-Planar blending function. Based on an old Nvidia writeup:
// GPU Gems 3 - Ryan Geiss: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch01.html
vec3 tex3D(sampler2D t, in vec3 p, in vec3 n ){
    n = max(abs(n), 0.001);
    n /= dot(n, vec3(1));
vec3 tx = texture(t, p.yz).xyz;
    vec3 ty = texture(t, p.zx).xyz;
    vec3 tz = texture(t, p.xy).xyz;

    // Textures are stored in sRGB (I think), so you have to convert them to linear space
    // (squaring is a rough approximation) prior to working with them... or something like that. :)
    // Once the final color value is gamma corrected, you should see correct looking colors.
    return (tx*tx*n.x + ty*ty*n.y + tz*tz*n.z);
}

// Common formula for rounded squares, for all intended purposes.
float lengthN(in vec2 p, in float n){ p = pow(abs(p), vec2(n)); return pow(p.x + p.y, 1.0/n); }

// The camera path: There are a few spline setups on Shadertoy, but this one is a slight variation of
// Otavio Good's spline setup in his "Alien Beacon" shader: https://www.shadertoy.com/view/ld2SzK
//
// Spline point markers ("cp" for camera point). The camera visits each point in succession, then loops
// back to the first point, when complete, in order to repeat the process. In case it isn't obvious, each
// point represents an open space juncture in the object that links to the previous and next point.
// Of course, running a camera in a straight line between points wouldn't produce a smooth camera effect,
// so we apply the Catmull-Rom equation to the line segment.
vec3 cp[16];

void setCamPath(){
    // The larger fractal object has nodes in a 4x4x4 grid.
    // The smaller one in a 2x2x2 grid. The following points
    // map a path to various open areas throughout the object.
    const float sl = 2.*.96;
    const float bl = 4.*.96;

    cp[0] = vec3(0, 0, 0);
    cp[1] = vec3(0, 0, bl);
    cp[2] = vec3(sl, 0, bl);
    cp[3] = vec3(sl, 0, sl);
    cp[4] = vec3(sl, sl, sl);
    cp[5] = vec3(-sl, sl, sl);
    cp[6] = vec3(-sl, 0, sl);
    cp[7] = vec3(-sl, 0, 0);

    cp[8] = vec3(0, 0, 0);
    cp[9] = vec3(0, 0, -bl);
    cp[10] = vec3(0, bl, -bl);
    cp[11] = vec3(-sl, bl, -bl);
    cp[12] = vec3(-sl, 0, -bl);
    cp[13] = vec3(-sl, 0, 0);
    cp[14] = vec3(-sl, -sl, 0);
    cp[15] = vec3(0, -sl, 0);

    // Tighening the radius a little, so that the camera doesn't hit the walls.
    // I should probably hardcode this into the above... Done.
    //for(int i=0; i<16; i++) cp[i] *= .96;
}

// Standard Catmull-Rom equation. The equation takes in the line segment end points (p1 and p2), the
// points on either side (p0 and p3), the current fractional distance (t) along the segment, then
// returns the the smooth (cubic interpolated) position. The end result is a smooth transition
// between points... Look up a diagram on the internet. That should make it clearer.
vec3 Catmull(vec3 p0, vec3 p1, vec3 p2, vec3 p3, float t){
    return (((-p0 + p1*3. - p2*3. + p3)*t*t*t + (p0*2. - p1*5. + p2*4. - p3)*t*t + (-p0 + p2)*t + p1*2.)*.5);
}

// Camera path. Determine the segment number (segNum), and how far - timewise - we are along it (segTime).
// Feed the segment, the appropriate adjoining segments, and the segment time into the Catmull-Rom
// equation to produce a camera position. The process is pretty simple, once you get the hang of it.
vec3 camPath(float t){
    const int aNum = 16;

    t = fract(t/float(aNum))*float(aNum); // Repeat every 16 time units.

    // Segment number. Range: [0, 15], in this case.
    float segNum = floor(t);
    // Segment portion. Analogous to how far we are alone the individual line segment. Range: [0, 1].
    float segTime = t - segNum;


    if (segNum == 0.) return Catmull(cp[aNum-1], cp[0], cp[1], cp[2], segTime);

    for(int i=1; i<aNum-2; i++){
        if (segNum == float(i)) return Catmull(cp[i-1], cp[i], cp[i+1], cp[i+2], segTime);
    }

    if (segNum == float(aNum-2)) return Catmull(cp[aNum-3], cp[aNum-2], cp[aNum-1], cp[0], segTime);
    if (segNum == float(aNum-1)) return Catmull(cp[aNum-2], cp[aNum-1], cp[0], cp[1], segTime);

    return vec3(0);
}

// Smooth minimum function. There are countless articles, but IQ explains it best here:
// http://iquilezles.org/www/articles/smin/smin.htm
float sminP( float a, float b, float s ){
    float h = clamp( 0.5+0.5*(b-a)/s, 0.0, 1.0 );
    return mix( b, a, h ) - s*h*(1.0-h);
}

// Creating the scene geometry.
//
// There are two intertwined fractal objects. One is a gold and timber lattice, spread out in a 4x4x4
// grid. The second is some metallic tubing spread out over a 2x2x2 grid. Each are created by combining
// repeat objects with various operations. All of it is pretty standard.
//
// The code is a little fused together, in order to save some cycles, but if you're interested in the
// process, I have a "Menger Tunnel" example that's a little easier to decipher.
float map(in vec3 q){

///////////

    // The grey section. I have another Menger example, if you'd like to look into that more closely.
    // Layer one.
  vec3 p = abs(fract(q/4.)*4. - 2.);
  float tube = min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - 4./3. - .015;// + .05;


    // Layer two.
    p = abs(fract(q/2.)*2. - 1.);
  //d = max(d, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.);// + .025
  tube = max(tube, sminP(max(p.x, p.y), sminP(max(p.y, p.z), max(p.x, p.z), .05), .05) - 2./3.);// + .025

///////
    // The gold and timber paneling.
    //
    // A bit of paneling, using a combination of repeat objects. We're doing it here in layer two, just
    // to save an extra "fract" call. Very messy, but saves a few cycles... maybe.

    //float panel = sminP(length(p.xy),sminP(length(p.yz),length(p.xz), 0.25), 0.125)-0.45; // EQN 1
    //float panel = sqrt(min(dot(p.xy, p.xy),min(dot(p.yz, p.yz),dot(p.xz, p.xz))))-0.5; // EQN 2
    //float panel = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.5; // EQN 3
    float panel = sminP(max(p.x, p.y),sminP(max(p.y, p.z),max(p.x, p.z), .125), .125)-0.5; // EQN 3

    // Gold strip. Probably not the best way to do this, but it gets the job done.
    // Identifying the gold strip region, then edging it out a little... for whatever reason. :)
    float strip = step(p.x, .75)*step(p.y, .75)*step(p.z, .75);
    panel -= (strip)*.025;

    // Timber bulge. Just another weird variation.
    //float bulge = (max(max(p.x, p.y), p.z) - .55);//length(p)-1.;//
    //panel -= bulge*(1.-step(p.x, .75)*step(p.y, .75)*step(p.z, .75))*bulge*.25;

    // Repeat field entity two, which is just an abstract object repeated every half unit.
    p = abs(fract(q*2.)*.5 - .25);
    float pan2 = min(p.x, min(p.y,p.z))-.05;

    // Combining the two entities above.
    panel = max(abs(panel), abs(pan2)) - .0425;
/////////

    // Layer three. 3D space is divided by three.
    p = abs(fract(q*1.5)/1.5 - 1./3.);
  tube = max(tube, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - 2./9. + .025); // + .025

    // Layer three. 3D space is divided by two, instead of three, to give some variance.
    p = abs(fract(q*3.)/3. - 1./6.);
  tube = max(tube, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - 1./9. - .035); //- .025

    // Object ID: Equivalent to: if(tube<panel)objID=2; else objID = 1.; //etc.
    //
    // By the way, if you need to identify multiple objects, you're better off doing it in a seperate pass,
    // after the raymarching function. Having multiple "if" statements in a distance field equation can
    // slow things down considerably.

    //objID = 2. - step(tube, panel) + step(panel, tube)*(strip);
    objID = 1.+ step(tube, panel) + step(panel, tube)*(strip)*2.;
    //objID = 1. + step(panel, tube)*(strip) + step(tube, panel)*2.;

    return min(panel, tube);
}

float trace(in vec3 ro, in vec3 rd){
    float t = 0.0, h;
    for(int i = 0; i < 92; i++){
        h = map(ro+rd*t);
        // Note the "t*b + a" addition. Basically, we're putting less emphasis on accuracy, as
        // "t" increases. It's a cheap trick that works in most situations... Not all, though.
        if(abs(h)<0.001*(t*.25 + 1.) || t>FAR) break; // Alternative: 0.001*max(t*.25, 1.)
        t += h*.8;
    }

    return t;
}


// The reflections are pretty subtle, so not much effort is being put into them. Only eight iterations.
float refTrace(vec3 ro, vec3 rd){
    float t = 0.0;
    for(int i=0; i<16; i++){
        float d = map(ro + rd*t);
        if (d < 0.0025*(t*.25 + 1.) || t>FAR) break;
        t += d;
    }
    return t;
}



/*
// Tetrahedral normal, to save a couple of "map" calls. Courtesy of IQ.
vec3 calcNormal(in vec3 p){

    // Note the slightly increased sampling distance, to alleviate artifacts due to hit point inaccuracies.
    vec2 e = vec2(0.0025, -0.0025);
    return normalize(e.xyy * map(p + e.xyy) + e.yyx * map(p + e.yyx) + e.yxy * map(p + e.yxy) + e.xxx * map(p + e.xxx));
}
*/

// Standard normal function. It's not as fast as the tetrahedral calculation, but more symmetrical. Due to
// the intricacies of this particular scene, it's kind of needed to reduce jagged effects.
vec3 calcNormal(in vec3 p) {
const vec2 e = vec2(0.005, 0);
return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx)));
}

// I keep a collection of occlusion routines... OK, that sounded really nerdy. :)
// Anyway, I like this one. I'm assuming it's based on IQ's original.
float calcAO(in vec3 pos, in vec3 nor){
float sca = 2.0, occ = 0.0;
    for( int i=0; i<5; i++ ){
        float hr = 0.01 + float(i)*0.5/4.0;
        float dd = map(nor * hr + pos);
        occ += (hr - dd)*sca;
        sca *= 0.7;
    }
    return clamp( 1.0 - occ, 0.0, 1.0 );
}


// Texture bump mapping. Four tri-planar lookups, or 12 texture lookups in total. I tried to
// make it as concise as possible. Whether that translates to speed, or not, I couldn't say.
vec3 texBump( sampler2D tx, in vec3 p, in vec3 n, float bf){
    const vec2 e = vec2(0.001, 0);

    // Three gradient vectors rolled into a matrix, constructed with offset greyscale texture values.
    mat3 m = mat3( tex3D(tx, p - e.xyy, n), tex3D(tx, p - e.yxy, n), tex3D(tx, p - e.yyx, n));

    vec3 g = vec3(0.299, 0.587, 0.114)*m; // Converting to greyscale.
    g = (g - dot(tex3D(tx,  p , n), vec3(0.299, 0.587, 0.114)) )/e.x; g -= n*dot(n, g);

    return normalize( n + g*bf ); // Bumped normal. "bf" - bump factor.
}


void main(){
// Screen coordinates.
vec2 u = (gl_FragCoord - iResolution.xy*0.5)/iResolution.y;

    float speed = iTime*0.35 + 8.;

    // Initiate the camera path spline points. Kind of wasteful not making this global, but I wanted
    // it self contained... for better or worse. I'm not really sure what the GPU would prefer.
    setCamPath();

// Camera Setup.
    vec3 ro = camPath(speed); // Camera position, doubling as the ray origin.
    vec3 lk = camPath(speed + .5);  // "Look At" position.
    vec3 lp = camPath(speed + .5) + vec3(0, .25, 0); // Light position, somewhere near the moving camera.

    // Using the above to produce the unit ray-direction vector.
    float FOV = 1.57; // FOV - Field of view.
    vec3 fwd = normalize(lk-ro);
    vec3 rgt = normalize(vec3(fwd.z, 0, -fwd.x));
    vec3 up = (cross(fwd, rgt));

        // Unit direction ray.
    vec3 rd = normalize(fwd + FOV*(u.x*rgt + u.y*up));

    // Raymarch the scene.
    float t = trace(ro, rd);

    // Initialize the scene color.
    vec3 col = vec3(0);

    // Scene hit, so color the pixel. Technically, the object should always be hit, so it's tempting to
    // remove this entire branch... but I'll leave it, for now.
    if(t<FAR){
        // This looks a little messy and haphazard, but it's really just some basic lighting, and application
        // of the following material properties: Wood = 1., Metal = 2., Gold = 3..

        float ts = 1.;  // Texture scale.

        // Global object ID. It needs to be saved just after the raymarching equation, since other "map" calls,
        // like normal calculations will give incorrect results. Found that out the hard way. :)
        float saveObjID = objID;

        vec3 pos = ro + rd*t; // Scene postion.
        vec3 nor = calcNormal(pos); // Normal.
        vec3 sNor = nor;

        // Apply some subtle texture bump mapping to the panels and the metal tubing.
        nor = texBump(metal_jpg, pos*ts, nor, 0.002); // + step(saveObjID, 1.5)*0.002

        // Reflected ray. Note that the normal is only half bumped. It's fake, but it helps
        // taking some of the warping effect off of the reflections.
        vec3 ref = reflect(rd, normalize(sNor*.5 + nor*.5));

col = tex3D(metal_jpg, pos*ts, nor); // Texture pixel at the scene postion.

        vec3  li = lp - pos; // Point light.
        float lDist = max(length(li), .001); // Surface to light distance.
        float atten = 1./(1.0 + lDist*0.125 + lDist*lDist*.05); // Light attenuation.
        li /= lDist; // Normalizing the point light vector.

        float occ = calcAO( pos, nor ); // Occlusion.

        float dif = clamp(dot(nor, li), 0.0, 1.0); // Diffuse.
        dif = pow(dif, 4.)*2.;
        float spe = pow(max(dot(reflect(-li, nor), -rd), 0.), 8.); // Object specular.
        float spe2 = spe*spe; // Global specular.

        float refl = .35; // Reflection coefficient. Different for different materials.

        // Reflection color. Mostly fake.
        // Cheap reflection: Not entirely accurate, but the reflections are pretty subtle, so not much
        // effort is being put in.
        float rt = refTrace(pos + ref*0.1, ref); // Raymarch from "sp" in the reflected direction.
        float rSaveObjID = objID; // IDs change with reflection. Learned that the hard way. :)
        vec3 rsp = pos + ref*rt; // Reflected surface hit point.
        vec3 rsn = calcNormal(rsp); // Normal at the reflected surface. Too costly to bump reflections.
        vec3 rCol = tex3D(metal_jpg, rsp*ts, rsn); // Texel at "rsp."
        vec3 rLi = lp-rsp;
        float rlDist = max(length(rLi), 0.001);
        rLi /= rlDist;
        float rDiff = max(dot(rsn, rLi), 0.); // Diffuse light at "rsp."
        rDiff = pow(rDiff, 4.)*2.;
        float rAtten = 1./(1. + rlDist*0.125 + rlDist*rlDist*.05);

        if(rSaveObjID>1.5 && rSaveObjID<2.5){
            rCol = vec3(1)*dot(rCol, vec3(.299, .587, .114))*.7 + rCol*.15;//*.7+.2
            //rDiff *= 1.35;
        }
        if(rSaveObjID>2.5){
             //float rc = dot(rCol, vec3(.299, .587, .114));
             vec3 rFire = pow(vec3(1.5, 1, 1)*rCol, vec3(8, 2, 1.5));//*.5+rc*.5;
             rCol = min(mix(vec3(1.5, .9, .375), vec3(.75, .375, .3), rFire), 2.)*.5 + rCol;
        }

        rCol *= (rDiff + .35)*rAtten; // Reflected color. Not accurate, but close enough.

        // Grey metal inner tubing.
        if(saveObjID>1.5 && saveObjID<2.5){
            // Grey out the limestone wall color.
            col = vec3(1)*dot(col, vec3(.299, .587, .114))*.7 + col*.15;

            refl = .5;
            //dif *= 1.35;
            //spe2 *= 1.35;
        }

        // Gold trimming properties. More effort should probably be put in here.
        // I could just write "saveObjID == 3.," but I get a little paranoid where floats are concerned. :)
        if(saveObjID>2.5){
            // For the screen image, we're interested in the offset height and depth positions. Ie: pOffs.zy.

            // Pixelized dot pattern shade.
            //float c = dot(col, vec3(.299, .587, .114));

            vec3 fire = pow(vec3(1.5, 1, 1)*col, vec3(8, 2, 1.5));//*.5+c*.5;
            col = min(mix(vec3(1, .9, .375), vec3(.75, .375, .3), fire), 2.)*.5 + col;//

            refl = .65;
            //dif *= 1.5;
            //spe2 *= 1.5;
        }


        // Combining everything together to produce the scene color.
        col = col*(dif + .35  + vec3(.35, .45, .5)*spe) + vec3(.7, .9, 1)*spe2 + rCol*refl;
        col *= occ*atten; // Applying occlusion.
    }

    // Applying some very slight fog in the distance. This is technically an inside scene...
    // Or is it underground... Who cares, it's just a shader. :)
    col = mix(min(col, 1.), vec3(0), 1.-exp(-t*t/FAR/FAR*20.));//smoothstep(0., FAR-20., t)
    //col = mix(min(col, 1.), vec3(0), smoothstep(0., FAR-35., t));//smoothstep(0., FAR-20., t)

    // Done.
    gl_FragColor = vec4(sqrt(max(col, 0.)), 1.0);
}
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)