diff --git a/src/shaders/fragment.frag b/src/shaders/fragment.frag index adf3e97..0c4596b 100644 --- a/src/shaders/fragment.frag +++ b/src/shaders/fragment.frag @@ -57,18 +57,69 @@ float noise(vec2 p, float scale, int a) hash( i + vec2(1.), a), u.x), u.y); } -// Hexagonal prism, circumcircle variant +float sdHexPrism( vec3 p, vec2 h ) +{ + const vec3 k = vec3(-0.8660254, 0.5, 0.57735); + p = abs(p); + p.xy -= 2.0*min(dot(k.xy, p.xy), 0.0)*k.xy; + vec2 d = vec2( + length(p.xy-vec2(clamp(p.x,-k.z*h.x,k.z*h.x), h.x))*sign(p.y-h.x), + p.z-h.y ); + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + float fHexagonCircumcircle(vec3 p, vec2 h) { vec3 q = abs(p); return max(q.y - h.y, max(q.x * sqrt(3.) * 0.5 + q.z * 0.5, q.z) - h.x); - //this is mathematically equivalent to this line, but less efficient: - //return max(q.y - h.y, max(dot(vec2(cos(PI/3), sin(PI/3)), q.zx), q.z) - h.x); } -float sdHex(vec3 pos, vec2 id, float angle) { - pos.xz *= rot2D(0.1); - float d1 = fHexagonCircumcircle(pos, vec2(0.86, 1.)); - return d1; +float hexPylon(vec3 p, vec2 h) {//float r, float ht){ + + //vec3 p = vec3(p.x, p.z, p2.y); + vec3 b = vec3(h.x, h.y, h.x); + + // Hexagon. + p.xz = abs(p.xz); + p.xz = vec2(p.x*.866025 + p.z*.5, p.z); + // The ".015" is a subtle rounding factor. Zero gives sharp edges, + // and larger numbers give a more rounded look. + return length(max(abs(p) - b + .015, 0.)) - .015; +} + +#define zclamp(a) max(a,0.0) //Clamp negative values at zero +float DF_RoundedHex( vec3 p, vec2 h) //float width, float height) +{ + float width = h.x; + float height = h.y; + //Modified version (smooth edges) of the exagon prism found here: + //https://iquilezles.org/articles/distfunctions + float smoothRadius = 0.05; + width -= smoothRadius*2.0; + + //Hexagon prism constructed using X,Y,Z symmetry. + //Only quadrant 1 needs to be solved, but the joining diagonal to quadrant IV is also + //required for distance blending (see db). + p = abs(p); + + //Hexagonal edge distances : + //Note : [.8666,0.5] = [sin(PI/3,cos(PI/3)] -> Hexagon edges rotation coeff (60 degrees). + float da = (p.x*0.866025+p.z*0.5)-width; //quadrant I diagonal edge distance + float db = (p.x*0.866025-p.z*0.5)-width; //quadrant IV diagonal edge distance (needed for blending) + float dc = p.z-width; //upper distance + + vec3 d = zclamp(vec3(da,db,dc)); + //Note: this is not an euclidian length, therefore this operation slightly distorts our distance field. + //Yet, it is harmless to convergence, and does the smoothing job quite well. + float dw = length(d)-smoothRadius; //hexagonal part smoothness (blending at 60 deg) + float dh = p.y-height; + + //Now that we have xz distance(dw) and y distance (dh), we can compute the distance + //for the given isovalue (the smoothing radius). + //Note : internal distance (maxX,maxY,maxZ) is also used to genereate internal signed dist, + // helping convergence when overstepping (very frequent with domain repetition). + float externalDistance = length(zclamp(vec2(dh,dw)))-smoothRadius; //Smoothed, unsigned + float internalDistance = max(max(da,dc),dh); //Sharp, signed. + return min(externalDistance,internalDistance); } float getScaledFFT(int index, float scale, float offset) { @@ -135,16 +186,17 @@ vec3 mapScene(vec3 p) { // Use axial coordinates as a stable hex ID float distFromCenter = hexDistance(hex.axial); - int fftIndex = int(clamp(distFromCenter * 1.0, 0.0, 511.0)); // tweak 15.0 to taste + int fftIndex = int(clamp(distFromCenter +1.0, 0.0, 511.0)); // tweak 15.0 to taste float fftVal = fft_output[fftIndex]; float hexHeight = 1.0 + fftVal * 1.0; // Rotate individual hex tiles if needed vec3 r = hex.local; + //r.yz *= rot2D(1.0); r.xz *= rot2D(0.5); - float d1 = fHexagonCircumcircle(r, vec2(hexRadius, hexHeight)); + float d1 = fHexagonCircumcircle(vec3(r.x,(r.y-hexHeight/2),r.z), vec2(hexRadius, hexHeight/2)); d = min(d,d1); return vec3(d, 0.0, 0.0); @@ -156,13 +208,27 @@ vec3 mapScene(vec3 p) { float rayMarch(vec3 ro, vec3 rd, int a) { vec3 d; - float t = 0.; // total distance travelled + float t = 0.,ad,tmax=100.; // total distance travelled + const float tolerance = 0.00001; + const float Z_REPEAT_DIST = 1.; + // Raymarching - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 80; i++) { d = mapScene(ro + rd * t); // Get distance to objects + ad = abs(d.x); + if (ad < tolerance*(t*0.125 + 1.0) || t > tmax) break; t += d.x; // "march" the ray - if (d.x < 1e-3 || t > 500.) break; } + t -= Z_REPEAT_DIST*15.; + + for( int i=0; i<80; i++ ) + { + d = mapScene(ro + rd * t); // get distance to objects + ad = abs(d.x); + if (ad < tolerance*(t*0.00125) || t > tmax) break; + t += min(d.x, Z_REPEAT_DIST/5.0); // "march" the ray + } + if (ad >= tmax) t= - 1.0; return t; } @@ -179,7 +245,7 @@ float getLight(vec3 p, vec3 lightPos, float intensity, float shadow, vec3 n, flo vec3 l = no(lightPos - p); float len = length( lightPos - p ); // Distance from the light to the surface point. float dif = cl(dot(n, l)*intensity, 0., intensity) * 1.0 / (1.0 + atte*len), - d = rayMarch(p+n*.0025, l, 1); + d = rayMarch(p+n*.025, l, 1); if(ds&&d>f)" - "x=-m-l;" - "else if(s>f)" - "m=-x-l;" - "f=sqrt(3.)*(x+m*.5);" - "i=1.5*m;" + "float f=sqrt(3.)/3.*v.x-1./3.*v.z,m=2./3.*v.z,x=round(f),l=round(m),a=round(-f-m),d=abs(x-f),p=abs(l-m);" + "f=abs(a+f+m);" + "if(d>p&&d>f)" + "x=-l-a;" + "else if(p>f)" + "l=-x-a;" + "f=sqrt(3.)*(x+l*.5);" + "m=1.5*l;" "HexData r;" - "r.local=v-vec3(f,0,i);" - "r.axial=vec2(x,m);" + "r.local=v-vec3(f,0,m);" + "r.axial=vec2(x,l);" "return r;" "}" "struct HexData{vec3 local;vec2 axial;};" - "float t(vec2 v)" + "float s(vec2 v)" "{" - "float f=v.x,m=v.y;" - "return max(abs(f),max(abs(m),abs(-f-m)));" + "float m=v.x,f=v.y;" + "return max(abs(m),max(abs(f),abs(-m-f)));" "}" - "vec3 x(vec3 v)" + "vec3 p(vec3 v)" "{" "float f=1e9;" "HexData m=t(vec3(v.x,v.y-10.,v.z));" + "float l=1.+H[int(clamp(s(m.axial)+1.,0.,511.))];" "v=m.local;" "v.xz*=s();" - "float x=s(v,vec2(.83,1.+H[int(clamp(t(m.axial),0.,511.))]));" - "f=min(f,x);" + "l=s(vec3(v.x,v.y-l/2,v.z),vec2(.83,l/2));" + "f=min(f,l);" "return vec3(f,0,0);" "}" - "float s(vec3 v,vec3 f,int m)" + "float p(vec3 v,vec3 f,int m)" "{" "vec3 l;" - "float i=0.;" - "for(int r=0;r<100;r++)" + "float x=0.,r;" + "for(int m=0;m<80;m++)" "{" - "l=x(v+f*i);" - "i+=l.x;" - "if(l.x<.001||i>5e2)" + "l=p(v+f*x);" + "r=abs(l.x);" + "if(r<1e-5*(x*.125+1.)||x>1e2)" "break;" + "x+=l.x;" "}" - "return i;" + "x-=15.;" + "for(int m=0;m<80;m++)" + "{" + "l=p(v+f*x);" + "r=abs(l.x);" + "if(r1e2)" + "break;" + "x+=min(l.x,.2);" + "}" + "if(r>=1e2)" + "x=-1.;" + "return x;" "}" - "vec3 w(vec3 v)" + "vec3 x(vec3 v)" "{" - "vec2 f=vec2(.01,0);" - "return s(x(v).x-vec3(x(v-f.xyy).x,x(v-f.yxy).x,x(v-f.yyx)));" + "vec2 m=vec2(.01,0);" + "return s(p(v).x-vec3(p(v-m.xyy).x,p(v-m.yxy).x,p(v-m.yyx)));" "}" - "float s(vec3 v,vec3 f,float m,float l,vec3 x,float i)" + "float p(vec3 v,vec3 f,float m,float l,vec3 x,float y)" "{" - "vec3 y=s(f-v);" - "m=s(dot(x,y)*m,0.,m)/(1.+i*length(f-v));" - "if(s(v+x*.0025,y,1)