uniform sampler2D tDiffuse;
uniform float iTime;
uniform vec2 iResolution;
uniform vec2 iMouse;
varying vec2 sv;
//https://www.xvideos.com/video52507323/great_ass_walking
// Good reference video for a walking ass, shaking of the ass while walking
#define MAX_STEPS 200; //Dosnt work, rewrite manualy
#define SURFACE_DIST 0.0001;
#define MAX_DIST 5.0;
#define MIN_DIST 0.2;
#define pi acos(-1.)
#define TAU 2.0 * pi
#define time 5.5 * iTime
#define s1 sin(time)
#define s2 sin(time + pi)
#define c1 cos(time)
#define walking1 sign(s1)* pow(abs(s1), 0.6)
#define walking2 sign(s2)* pow(abs(s2), 0.6)
#define floorTime floor(0.5 + time/pi)
#define walking3 (2.0 * floorTime + sign(c1)*sign(s1)*abs(s1))
#define shakeCount 15.5
#define shakeFrec 0.5
#define shakePartLeft (pi + shakeCount * fract(shakeFrec * time/pi + 0.5*pi)) //pi + ???
#define shakePartRight (pi + shakeCount * fract(shakeFrec * time/pi + pi))
#define shakingStabilityLeft (0.5 * sign(c1)*pow(abs(c1), 0.1) + 0.5)
#define shakingStabilityRight (0.5 * sign(s1)*pow(abs(s1), 0.1) + 0.5)
#define shakefuncLeft sin(shakePartLeft)/shakePartLeft// * shakingStabilityLeft
#define shakefuncRight sin(shakePartRight)/shakePartRight
#define skinCol1 vec3(232.0,204.0,185.0) / 255.0
#define skinCol2 vec3(238.0, 195.0, 186.0) / 255.0
#define skinCol3 vec3(212.0, 174.0, 146.0) / 255.0
#define skinCol4 vec3(175.0, 133.0, 105.0) / 255.0
#define subsurface_scale 1.4
#define subsurface_frequency 800.2
#define skin_scale 0.3
#define skin_frequency 580.0
#define base_skin_amt .83
#define subsurface_color1 vec3(0.639, 0.058, 0)
#define subsurface_color2 vec3(0.400, 0.168, 0.05)
#define subsurface_color3 vec3(0.556, 0.118, 0.12)
#define subsurface_color4 vec3(0.639, 0.058, 0.25)
#define subsurface_color5 vec3(0.639, 0.058, 0.25)
#define surface_col 0.9 * vec3(1.0, 1.0, 1.0)
#define base_skin_color mix(skinCol2, skinCol4, 0.5)
vec2 hash( vec2 p ) // replace this by something better
{
p = vec2( dot(p,vec2(127.1,311.7)),
dot(p,vec2(269.5,183.3)) );
return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}
float hash13(vec3 p)
{
p = fract(p * vec3(3.131, 5.411, 4.321));
p += dot(p.yzx, p + 51.23);
return fract(p.x*p.y*p.z);
}
vec3 hash33(vec3 p)
{
p = fract(p * vec3(3.131, 5.411, 4.321));
p.xy += dot(p.yzx, p + 51.23);
p.z = dot(p.xy, vec2(2.13, 5.21));
return fract(p*p);
}
float noise( in vec2 p )
{
const float K1 = 0.366025404; // (sqrt(3)-1)/2;
const float K2 = 0.211324865; // (3-sqrt(3))/6;
vec2 i = floor( p + (p.x+p.y)*K1 );
vec2 a = p - i + (i.x+i.y)*K2;
vec2 o = step(a.yx,a.xy);
vec2 b = a - o + K2;
vec2 c = a - 1.0 + 2.0*K2;
vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
return dot( n, vec3(70.0) );
}
float n_noise(in vec2 p)
{
return 0.5 + 0.5 * noise(p);
}
mat2 Rot(float a)
{
float s = sin(a);
float c = cos(a);
return mat2(c, -s, s, c);
}
float smoothAbs( float x, float n )
{
return sqrt(x*x+n);
}
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
float sdFold(vec2 p, vec2 a, vec2 b)
{
vec2 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba * h );
}
float sdEllipsoid( vec3 p, vec3 r )
{
float k0 = length(p/r);
float k1 = length(p/(r*r));
return k0*(k0-1.0)/k1;
}
float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
{
vec3 pa = p - a, ba = b - a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h ) - r;
}
float smoothMin( float d1, float d2, float k )
{
float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
return mix( d2, d1, h ) - k*h*(1.0-h);
}
// float sinc( float x, float k )
// {
// float a = pi*((k*x-1.0);
// return sin(a)/a;
// }
///sign(sin(x)) * pow(abs(sin(x)), 0.3)
float map( in vec3 pos)
{
//x mirroring coord
vec3 posAbsX = pos;
posAbsX.x = smoothAbs(posAbsX.x, 0.0001);
float walkingPosLeft = 0.1 + walking1;
float walkingPosRight = 0.1 + walking2;
// ass
float assMod = 1.15 + 0.15 * smoothstep(-0.0, -0.25, posAbsX.y);
vec3 assSizeMod = vec3(assMod,1.0,assMod);
vec3 assSizeModLeft = assSizeMod * (1.0 + 0.05 * walkingPosLeft);
vec3 assSizeModRight = assSizeMod* (1.0 + 0.05 * walkingPosRight);
float shakeAmp = 0.12 * smoothstep(0.15, -0.15, posAbsX.y);
float assOffsetLeft = 0.12 - shakeAmp * shakefuncLeft;//sin(shakePart)/shakePart;// + 0.0 * shakePart;
vec3 assCenLeft = vec3(assOffsetLeft, 0.0, -0.07);
vec3 assDimLeft = assSizeModLeft * vec3(0.15, 0.25, 0.2);
float assLeft = sdEllipsoid(pos - assCenLeft, assDimLeft);
float assOffsetRight = 0.12 - shakeAmp * shakefuncRight;
vec3 assCenRight = vec3(-assOffsetRight, 0.0, -0.07);
vec3 assDimRight = assSizeModRight * vec3(0.15, 0.25, 0.2);
float assRight = sdEllipsoid(pos - assCenRight, assDimRight);
float ass = smoothMin(assLeft, assRight, 0.01);
// back
vec3 backCen = vec3(0.08, 0.0, 0.0);
vec3 backA = vec3(0.0, 0.0, 0.0);
vec3 backB = vec3(0.0, 0.8, 0.0);
float backThickness = 0.15 + 0.24 * smoothstep(0.3, 1.5, posAbsX.y);
float back = sdCapsule(posAbsX - backCen, backA, backB, backThickness);
// belley
vec3 belleyCen = vec3(0.0, 0.35, 0.05);
vec3 belleyDim = vec3(0.14, 0.25, 0.1);
float belley = sdEllipsoid(pos - belleyCen, belleyDim);
back = smoothMin(back, belley, 0.08);
// legs
vec3 leftLegCen = vec3(-0.16, 0.0, 0.0);
vec3 rightLegCen = vec3(0.16, 0.0, 0.0);
float legOffsetAmp = 0.3;
float moveLegLeft = legOffsetAmp * walkingPosLeft;
float moveLegRight = legOffsetAmp * walkingPosRight;
vec3 legLeftA = vec3(0.0, -0.1, 0.0);
vec3 legLeftB = vec3(0.0, -0.8, moveLegLeft);
vec3 legRightA = vec3(0.0, -0.1, 0.0);
vec3 legRightB = vec3(0.0, -0.8, moveLegRight);
float legThickness = 0.125 + 0.04 * smoothstep(-0.6, -0.25 , posAbsX.y) + 0.00 * smoothstep(-0.3, -0.1, posAbsX.y) * smoothstep(0.18, .8, posAbsX.x);
float leftLeg = sdCapsule(pos - leftLegCen, legLeftA, legLeftB, legThickness);
float rightLeg = sdCapsule(pos - rightLegCen, legRightA, legRightB, legThickness);
float legs = min(leftLeg, rightLeg);
return smoothMin(smoothMin(ass, back, 0.08), legs, 0.08);
}
// --- analytically box-filtered checkerboard ---
float checkersTextureGradBox( in vec2 p, in vec2 ddx, in vec2 ddy, float f)
{
p *= f;
// filter kernel
vec2 w = max(abs(ddx), abs(ddy)) + 0.1;
// analytical integral (box filter)
vec2 i = 2.0*(abs(fract((p-0.5*w)/2.0)-0.5)-abs(fract((p+0.5*w)/2.0)-0.5))/w;
// xor pattern
return 0.5 - 0.5*i.x*i.y;
}
//https://www.shadertoy.com/view/XlcSz2
// --- unfiltered checkerboard ---
float checkersTexture( in vec2 p , float f)
{
vec2 q = floor(p * f);
return mod( q.x+q.y, 2.0 ); // xor pattern
}
vec2 texCoords( in vec3 pos)
{
vec4 sc0 = vec4( 0.0, 0.0, 0.0, 1.0);
vec3 q = normalize( pos - sc0.xyz);
return vec2( atan(q.x,q.z), acos(q.y )) * sc0.w;
}
vec2 texCoords2(in vec3 pos)
{
return vec2(pos.x, pos.y);
}
vec3 SkinCol(vec2 uv)
{
float subsurface_radius = subsurface_scale / 2.0;
float subsurface_distance = n_noise(uv * subsurface_frequency);
float subsurface = 1.0 - min(1.0, subsurface_distance / subsurface_radius);
float skin_value = n_noise(uv * skin_frequency) * skin_scale;
vec3 col = subsurface_color5 * subsurface;
col = mix(col, base_skin_color, base_skin_amt);
col = mix(col, surface_col, skin_value);
// float subsurface_radious = subsurface_scale * 0.5;
// vec3 col = vec3(1.0);
return col;
}
vec3 DebugUV(vec2 uv)
{
vec3 col = vec3(uv.x,uv.y, 0.0);
//col = vec3(0.5);
if((uv.x < 0.05 && uv.x > -0.05) || (uv.x > 0.95 && uv.x < 1.05) || (uv.y < 0.05 && uv.y > -0.05) || (uv.y > 0.95 && uv.y < 1.05))
{
col = vec3(1,1,1);
}
return col;
}
float hair(vec3 p, vec3 i, float t)
{
float h = hash13(i);
float dir = dot(p , hash33(i) * 2. - 1.);
return sin(dir * (5. + sin(h * 431.52) * 3.) + t);
}
const vec2 o = vec2(1.,0.);
float hairNoise(vec3 p, float t)
{
vec3 i = floor(p);
vec3 f = smoothstep(0.,1.,p-i);
return
mix(
mix(
mix(hair(p,i,t),hair(p,i+o.xyy,t),f.x),
mix(hair(p,i+o.yxy,t),hair(p,i+o.xxy,t),f.x),
f.y),
mix(
mix(hair(p,i+o.yyx,t),hair(p,i+o.xyx,t),f.x),
mix(hair(p,i+o.yxx,t),hair(p,i+o.xxx,t),f.x),
f.y),
f.z);
}
float fbmCarpet(vec3 p, float t)
{
float res = 0.;
float noiseMod = 0.0;
for (float i = 1.; i < 3.; i += 1.0)
{
noiseMod += i;
res += hairNoise(p*noiseMod,t*noiseMod) / noiseMod;
}
return res * .25 + .5;
}
vec3 GroundCol(vec2 uv)
{
//uv.x -= 3.2 * sv.y;
vec3 p = vec3(uv * 8., .125);
float noise = fbmCarpet(p, .5);
vec3 col = mix(vec3(0.01), vec3(.3, .2, .5), noise);
//col = DebugUV(uv);
return col;
}
//https://www.shadertoy.com/view/MdlXz8
vec3 WallCol(vec2 uv)
{
vec2 p = mod(uv*TAU, TAU)-250.0;
vec2 i = vec2(p);
float c = 1.0;
float inten = .005;
for (int n = 0; n < 5; n++)
{
float t = 0.05 * time * (1.0 - (3.5 / float(n+1)));
i = p + vec2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x));
c += 1.0/length(vec2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten)));
}
c /= 5.0;
c = 1.17-pow(c, 1.4);
vec3 col = vec3(pow(abs(c), 8.0));
col = clamp(col + vec3(0.0, 0.35, 0.5), 0.0, 1.0);
return col;
}
vec3 BackgroundCol(vec2 uv)
{
uv.xy += vec2(1.25,-0.2);
uv.y /= 0.6 * pow(abs(uv.x), mix(0.45, 2.35, step(uv.x,0.0)));
uv.x /= mix(0.6, 0.5, step(uv.x,0.0)) * pow(abs(uv.x), 0.45);
vec2 sv = uv;
vec2 groundUV = uv;
groundUV *= 10.;
//TODO: solve singularity on the ground. aspect ratio 10 : 2
groundUV.x -= mix(5.2, -2.2, step(groundUV.x, 0.0)) * sv.y;
groundUV.x -= sign(groundUV.x) * 0.5 * walking3;
uv *= 10.;
uv.x -= sign(uv.x) * 0.5 * walking3;
vec3 col = WallCol( 0.1 * uv);
vec3 groundCol = GroundCol(groundUV);
col = mix(col, groundCol, step(sv.y, -0.8));
return col;
}
float castRay( in vec3 ro, in vec3 rd)
{
float tmin = MIN_DIST;
float tmax = MAX_DIST;
float surfDistMin = SURFACE_DIST;
float t = tmin;
for( int i=0; i<100; i++ )
{
float h = map( ro+rd*t);
//abs increases stability non euklidian mapping after the reymarch steps into
//the sdf. the "* t" increases the mistake for farther objects.
if( abs(h)<surfDistMin * t && t<tmax ) break;
t += 0.99 * h;
}
return t;
}
vec3 calcNormal( in vec3 pos)
{
vec2 e = vec2(0.0005,0.0);
return normalize( vec3(
map( pos + e.xyy) - map( pos - e.xyy),
map( pos + e.yxy) - map( pos - e.yxy),
map( pos + e.yyx) - map( pos - e.yyx) ) );
}
float getLight(vec3 pos, vec3 lightPos)
{
vec3 lightDir = normalize(lightPos - pos);
vec3 normal = calcNormal(pos);
float diffuseLight = clamp(dot(normal, lightDir), 0. , 1.);
float surfDistMin = SURFACE_DIST;
//shadows
//raymarch to light pos if hit its shadow
float distToHit = castRay(pos + normal * surfDistMin, lightDir);
//if distToHit less then lightPos - pos then dif *= 0.1;
diffuseLight = mix(diffuseLight, 0.5 * diffuseLight, step(distToHit, length(lightPos - pos)));
return diffuseLight;
}
//Returns the RayDirection for a pixel given the ray origin, the look at vector and a zoom factor.
vec3 cameraRayDirection(vec2 uv, vec3 rayOrigin, vec3 lookAt, float zoom)
{
vec3 forwardDir = normalize(lookAt - rayOrigin);
vec3 rightDir = normalize(cross(vec3(0, 1, 0), forwardDir));
vec3 upDir = cross(forwardDir, rightDir);
vec3 centerOfScreen = rayOrigin + forwardDir * zoom;
vec3 intersectionOfScreen = centerOfScreen + uv.x * rightDir + uv.y * upDir;
return intersectionOfScreen - rayOrigin;
}
vec3 render(vec2 uv)
{
vec3 rayOrigin = normalize(vec3(-1.4, -0.6, -2.5));
//rayOrigin = normalize(vec3(-1.0, - 1.0, -2.5));
//rayOrigin = normalize(vec3(0.0, 0.0, -1.0)); //look from back
// rayOrigin.yz *= Rot( -iMouse.y * pi + 1.0);
// rayOrigin.xz *= Rot( -iMouse.x * 2.0 * pi + pi);
vec3 lookAt = vec3(0, 0, 0);
vec3 lightPos = vec3(-5.0, 6.0, -5.0);
vec3 rayDirection = cameraRayDirection(uv, rayOrigin, lookAt, 1.);
float dist = castRay(rayOrigin, rayDirection);
vec3 pos = rayOrigin + rayDirection * dist;
float light = getLight(pos, lightPos);
vec2 uvw = texCoords2(pos);
vec3 foldCol = vec3(0.1, 0.1, 0.1);
vec3 skinColor = SkinCol(uvw);
float fold = max(sdFold(pos.zy, vec2(-0.0, -0.0), vec2(-1.0, -0.9)), sdSphere(pos+vec3(0.0,0.2,0.2), 0.2));
float foldFact = step(fold, 0.003);
vec3 lightCol = light * skinColor;
float maxDist = MAX_DIST;
//dist negative for to far fields
vec3 background = BackgroundCol(uv);
vec3 finalCol = mix(lightCol, background, step(maxDist, dist));;
return finalCol;
}
void main()
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = (sv - 0.5) * iResolution.xy / iResolution.y;
vec2 uvVig = sv;
// Time varying pixel color
vec3 col = render(uv);
uvVig.xy *= 1.0 - uvVig.yx;
float vig = uvVig.x*uvVig.y * 15.0; // multiply with sth for intensity
vig = pow(vig, 0.25); // change pow for modifying the extend of the vignette
gl_FragColor = vec4(col * vig ,1.0);
}