Skip to content

Instantly share code, notes, and snippets.

@matthewjberger
Created August 24, 2024 19:33
Show Gist options
  • Save matthewjberger/b6e89845b0f06613e2de6e1c4a15ad71 to your computer and use it in GitHub Desktop.
Save matthewjberger/b6e89845b0f06613e2de6e1c4a15ad71 to your computer and use it in GitHub Desktop.
cube shader for shadertoy
#define MAX_STEPS 100
#define MAX_DIST 100.0
#define SURF_DIST 0.001
// Camera variables
vec3 cameraPos;
vec3 cameraTarget;
float cameraZoom = 5.0;
mat3 getCameraRotation(vec2 angle) {
vec2 c = cos(angle);
vec2 s = sin(angle);
return mat3(
c.y, 0.0, -s.y,
s.y * s.x, c.x, c.y * s.x,
s.y * c.x, -s.x, c.y * c.x
);
}
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 getDist(vec3 p) {
return sdBox(p, vec3(1.0));
}
float getLightDist(vec3 p, vec3 lightPos) {
return sdBox(p - lightPos, vec3(0.1)); // Small cube for light source
}
vec3 getNormal(vec3 p) {
float d = getDist(p);
vec2 e = vec2(0.001, 0);
vec3 n = d - vec3(
getDist(p - e.xyy),
getDist(p - e.yxy),
getDist(p - e.yyx));
return normalize(n);
}
float rayMarch(vec3 ro, vec3 rd, vec3 lightPos, bool isForLight) {
float dO = 0.0;
for(int i = 0; i < MAX_STEPS; i++) {
vec3 p = ro + rd * dO;
float dS = isForLight ? getLightDist(p, lightPos) : getDist(p);
dO += dS;
if(dO > MAX_DIST || abs(dS) < SURF_DIST) break;
}
return dO;
}
// Sky shader
vec3 getSkyColor(vec3 rd) {
float t = 0.5 * (rd.y + 1.0);
vec3 skyColor = mix(vec3(0.2, 0.4, 0.6), vec3(0.7, 0.9, 1.0), t);
return skyColor;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
vec3 col = vec3(0.0);
// Camera controls
vec2 mouseUV = iMouse.xy / iResolution.xy;
vec2 cameraAngle = vec2(0.0, 0.0);
if (iMouse.z > 0.0) {
cameraAngle = vec2((mouseUV.y - 0.5) * 3.14159, (mouseUV.x - 0.5) * 6.28318);
}
mat3 cameraRotation = getCameraRotation(cameraAngle);
// Adjust zoom with mouse wheel (iMouse.w)
cameraZoom = max(2.0, min(10.0, cameraZoom - 0.1 * iMouse.w));
// Camera setup
cameraPos = vec3(0.0, 0.0, cameraZoom);
cameraTarget = vec3(0.0, 0.0, 0.0);
vec3 cameraDir = normalize(cameraTarget - cameraPos);
vec3 cameraRight = normalize(cross(vec3(0.0, 1.0, 0.0), cameraDir));
vec3 cameraUp = cross(cameraDir, cameraRight);
vec3 ro = cameraPos * cameraRotation;
vec3 rd = normalize(uv.x * cameraRight + uv.y * cameraUp + cameraDir) * cameraRotation;
// Point light position (rotating around the cube)
vec3 lightPos = vec3(3.0 * sin(iTime), 2.0, 3.0 * cos(iTime));
// Check if the ray hits the main object
float d = rayMarch(ro, rd, lightPos, false);
if(d < MAX_DIST) {
vec3 p = ro + rd * d;
vec3 n = getNormal(p);
// Light calculations
vec3 l = normalize(lightPos - p);
float diff = max(dot(n, l), 0.0);
vec3 h = normalize(l - rd);
float spec = pow(max(dot(n, h), 0.0), 32.0);
// Colors
vec3 objectColor = vec3(0.5, 0.8, 0.9);
vec3 lightColor = vec3(1.0, 0.9, 0.7);
vec3 ambientColor = vec3(0.1, 0.1, 0.2);
// Combine lighting components
col = ambientColor * objectColor +
diff * objectColor * lightColor +
spec * lightColor;
// Add distance attenuation
float distanceToLight = length(lightPos - p);
col /= 1.0 + 0.1 * distanceToLight * distanceToLight;
} else {
// Check if the ray hits the light source cube
float dLight = rayMarch(ro, rd, lightPos, true);
if(dLight < MAX_DIST) {
// Light source color (white)
col = vec3(1.0);
} else {
// Background sky color
col = getSkyColor(rd);
}
}
// Gamma correction
col = pow(col, vec3(0.4545));
fragColor = vec4(col, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment