Skip to content

Instantly share code, notes, and snippets.

@CharStiles
Created January 22, 2025 23:23
Show Gist options
  • Save CharStiles/a9206b677a555b6c050833cba7f36546 to your computer and use it in GitHub Desktop.
Save CharStiles/a9206b677a555b6c050833cba7f36546 to your computer and use it in GitHub Desktop.
#ifdef GL_ES
precision highp float;
#endif
uniform float time;
uniform vec2 resolution;
uniform vec2 mouse;
uniform vec3 spectrum;
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform sampler2D texture3;
uniform sampler2D prevFrame;
uniform sampler2D prevPass;
varying vec3 v_normal;
varying vec2 v_texcoord;
float rand(vec2 co){
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}
// Same, but mirror every second cell at the diagonal as well
vec2 pModGrid2(inout vec2 p, vec2 size) {
vec2 c = floor((p + size*0.5)/size);
p = mod(p + size*0.5, size) - size*0.5;
p *= mod(c,vec2(2))*2. - vec2(1);
p -= size/2.;
if (p.x > p.y) p.xy = p.yx;
return floor(c/2.);
}
vec2 pModMirror2(inout vec2 p, vec2 size) {
vec2 halfsize = size*0.5;
vec2 c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
p *= mod(c,vec2(2))*2. - vec2(1);
return c;
}
void pR(inout vec2 p, float a) {
p = cos(a)*p + sin(a)*vec2(p.y, -p.x);
}
// Maximum/minumum elements of a vector
float vmax(vec2 v) {
return max(v.x, v.y);
}
float vmax(vec3 v) {
return max(max(v.x, v.y), v.z);
}
float vmax(vec4 v) {
return max(max(v.x, v.y), max(v.z, v.w));
}
// Box: correct distance to corners
float fBox(vec3 p, vec3 b) {
vec3 d = abs(p) - b;
return length(max(d, vec3(0))) + vmax(min(d, vec3(0)));
}
// Smooth minimum function for rounding
// Smooth minimum function for rounding
float smin(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);
}
// Smooth maximum function for rounding
float smax(float a, float b, float k) {
return -smin(-a, -b, k);
}
// Rounded box function
float fBoxRound(vec3 p, vec3 b, float r) {
vec3 q = abs(p) - b + vec3(r);
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - r;
}
// Domain repetition with offset
vec3 opRep(vec3 p, vec3 c) {
return mod(p + 0.5 * c, c) - 0.5 * c;
}
// Box SDF
float sdBox(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
float scene(vec3 p) {
float result = 1e10;
// Create infinite grid with smoother transitions
vec3 cell = floor(p / vec3(20.0, 40.0, 10.0));
vec3 localPos = opRep(p, vec3(40.0, 30.0, 40.0));
// Soften the rotation variation
float rotAngle = sin(dot(cell.xz, vec2(12.9898, 78.233))) * 3.14159;
pR(localPos.xz, rotAngle);
// Smooth height variation
float baseHeight = 15.0 + 10.0 * (0.5 + 0.5 * sin(dot(cell.xz, vec2(0.3, 0.7))));
// Main tower with rounded edges
float tower = fBoxRound(localPos * 0.95, vec3(4.0, baseHeight, 4.0),.1);
// Smoother bridges
float bridgeThickness = 2.5; // Slightly thicker
float bridgeLength = 10.0;
float bridgeX = fBoxRound(localPos - vec3(bridgeLength, baseHeight * 0.7, 0.0),
vec3(bridgeLength, bridgeThickness, bridgeThickness),2.);
float bridgeZ = fBoxRound(localPos - vec3(0.0, baseHeight * 0.4, bridgeLength),
vec3(bridgeThickness, bridgeThickness, bridgeLength),2.2);
// Connected structures with gradual blending
vec3 offsetPos = localPos;
float finalTower = tower;
for (int i = 0; i < 3; i++) {
float blend = float(i) * 0.333;
float h = baseHeight * (0.5 + 0.3 * sin(dot(cell.xz + float(i), vec2(1.1, 0.9))));
// Smooth position offset
vec2 offset = vec2(
8.0 * sin(dot(cell.xz + float(i), vec2(0.5, 0.7))),
8.0 * sin(dot(cell.xz + float(i), vec2(0.9, 0.3)))
);
offsetPos.xz += offset;
float smallTower = fBoxRound(offsetPos * (0.95 + float(i) * 0.02), vec3(3.0, h, 3.0),1.);
finalTower = smin(finalTower, smallTower, 4.0 + float(i)); // Progressive smoothing
}
// Combine elements with varying smooth factors
result = smin(finalTower, smin(bridgeX, bridgeZ, 3.0), 2.0);
// Architectural details with softer edges
vec3 windowPos = localPos;
windowPos.y = mod(windowPos.y + time * 2.0, 5.0) - 2.5;
float windows = sdBox(windowPos * 1.1, vec3(2.0, 0.5, 0.5));
result = smax(result, -windows, 0.8);
return result * 0.9; // Slightly scale down the entire SDF for smoother results
}
vec3 estimateNormal(vec3 p) {
float d = 0.001;
return normalize(vec3(
scene(p + vec3(d, 0, 0)) - scene(p - vec3(d, 0, 0)),
scene(p + vec3(0, d, 0)) - scene(p - vec3(0, d, 0)),
scene(p + vec3(0, 0, d)) - scene(p - vec3(0, 0, d))
));
}
vec4 lighting(vec3 ray, vec3 rd, vec2 id){
vec3 norm = estimateNormal(ray);
vec3 light = vec3(1., 0., 0.);
float dif = max(dot(norm, light), 0.0); // Add max to prevent negative values
vec4 retCol = vec4(dif);
// Add ambient light to prevent pure black
float ambient = 0.9621;
retCol += vec4(ambient);
vec3 lightRayDir = normalize(light - ray);
return retCol * vec4(norm, 1.0) + rand(ray.xy);
}
vec4 trace(vec3 rayO, vec3 dir) {
vec3 ray = rayO;
float dist = 0.0;
float totalDist = 0.0;
float glow = 0.0;
// Adaptive stepping for smoother results
float precis = 0.001;
float t = precis * 2.0;
for(int i = 0; i < 128; ++i) {
dist = scene(ray);
// Accumulate glow based on how close we are to the surface
glow += max(0.0, 0.05 - dist) * 0.5;
// Adaptive step size
float step = max(dist * 0.8, precis);
totalDist += step;
ray += dir * step;
// Enhanced hit detection with smooth transition
if(dist < precis * totalDist) {
vec4 retCol = vec4(1.0 - (totalDist /100.)); // Smoother distance falloff
vec4 lit = lighting(ray, dir, dir.xy);
// Blend between lit surface and atmosphere
float fade = smoothstep(0.0, 100.0, totalDist);
vec4 atmosColor = vec4(0.6, 0.7, 0.8, 1.0);
return mix(lit * retCol, atmosColor,1.- fade) +glow*glow + (rand(ray.xy)-0.25);
}
// Distance-based early termination
if(totalDist > 200.0) break;
}
return vec4(0);//glow ; // Sky color with subtle glow
}
//
// vec4 trace(vec3 rayO, vec3 dir){
// vec3 ray = rayO;
// float dist = 0.;
// float totalDist = 0.;
//
// for(int i = 0; i < 128; ++i){
// dist = scene(ray);
// totalDist += dist;
// ray += dist * dir;
//
// if(dist < 0.01){
// vec4 retCol = 1.0 - (vec4(totalDist) / 5.0);
// return lighting(ray, dir,dir.xy) * retCol + rand(ray.xy );
// }
// }
// return vec4(0.0);
//}
void main() {
vec2 uv = (2.0 * gl_FragCoord.xy - resolution.xy) / min(resolution.x, resolution.y);
// Camera setup
float camHeight = 3.0 + 20.0 * tan(time * 0.2);
vec3 ro = vec3(15.0 * cos(time * 0.2), camHeight, 20.0 * sin(time * 0.2));
vec3 lookAt = vec3(0.0, 20.0, 0.0);
vec3 forward = normalize(lookAt - ro);
vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), forward));
vec3 up = cross(forward, right);
vec3 rd = normalize(forward + right * uv.x + up * uv.y);
vec4 col = trace(ro, rd);
// Output final color
gl_FragColor = col.gggg ;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment