Shader code
shader_type spatial;
render_mode unshaded;
uniform vec3 light_direction = vec3(1.0, 0.0, 1.0);
uniform vec3 camera_position = vec3(0.0, 0.0, 2);
void vertex() {
UV = UV;
NORMAL = (INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz;
}
// Smoothing version Boolean
float smin( float a, float b, float k ) {
float h = max( k - abs( a - b ), 0.0 ) / k;
return min( a, b ) - h * h * h * k * ( 1.0 / 6.0 );
}
// Sine Distance Functions
float sdSphere( vec3 p, float s ) {
return length(p) - s;
}
float sdRoundedCylinder( vec3 p, float ra, float rb, float h ) {
vec2 d = vec2( length(p.xz)-2.0*ra+rb, abs(p.y) - h);
return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rb;
}
float map(vec3 p) {
// Set up large animated sphere floating up
vec3 q = p;
q.y -= TIME * 0.1;
q.y = fract(q.y * 0.5) - 0.5;
float blobUp = sdSphere(q+vec3(0.2, 0.0, 0.0), 0.2);
// Set up small animated sphere sinking down
vec3 r = p;
r.y += TIME * 0.2;
r.y = fract(r.y * 0.8) - 0.5;
float blobDown = sdSphere(r+vec3(-0.3, 0.0, 0.0), 0.1);
// Add top and bottom pools of wax
float ground = sdRoundedCylinder(p+vec3(0.0, 1.0, 0.0), 0.35, 0.4, 0.2);
float ceiling = sdRoundedCylinder(p + vec3(0.0, -2.4, 0), 0.3, 0.4, 0.2);
// Return minimum distance
return smin( ceiling, smin( ground, smin(blobUp, blobDown, 0.4), 0.4 ), 0.4 );
}
vec3 calcNormal(vec3 p) {
float epsilon = 0.001;
vec3 n;
// Sample the distance function in each axis direction
n.x = map(p + vec3(epsilon, 0.0, 0.0)) - map(p - vec3(epsilon, 0.0, 0.0));
n.y = map(p + vec3(0.0, epsilon, 0.0)) - map(p - vec3(0.0, epsilon, 0.0));
n.z = map(p + vec3(0.0, 0.0, epsilon)) - map(p - vec3(0.0, 0.0, epsilon));
return normalize(n);
}
void fragment() {
vec2 uv = UV;
uv = (uv - 0.5) * 2.0; // Set UV Origin 0,0 to center
// Fragment World Position
vec3 world_position = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
// Initial Ray Marching Setup
vec3 ro = camera_position; // Ray Origin
vec3 rd = normalize(world_position - camera_position);
vec3 col = vec3(0);
float t = 0.0; // Total distance travelled
// Ray Marching
float alpha = 1.0;
vec3 p;
for (int i = 0; i < 80; i++) {
p = ro + (rd * t); // Position along the ray
float d = map(p); // curent distance to the scene
t += d;
if ( t > 100.0 ) alpha = 0.2;
if (d < 0.001 || t > 100.0) break;
}
vec3 normal = calcNormal(p);
vec3 light_dir = normalize(light_direction);
// Calculate Wax highlight and shadow
float diff = max(dot(normal, light_dir), 0.0);
vec3 light_color = vec3(1.0, 1.0, 1.0);
vec3 diffuse = diff * light_color;
// Start with green base
col = mix(vec3(0.0, 1.0, 0.0), vec3(0.6, 1.0, 0.6), t*0.09);
// Add shading
col += vec3(dot(normal, light_dir) * 0.5);
// Add highlight
col += pow(diffuse, vec3(25.0));
// Calculate Glass highlight
vec3 view_dir = normalize(camera_position - world_position);
vec3 reflection = reflect(-normalize(light_dir), NORMAL);
float spec_intensity = pow(max(dot(view_dir, reflection), 0.0), 64.0);
vec3 specular = spec_intensity * vec3(1.0);
col += specular;
alpha += specular.x;
ALBEDO = col;
ALPHA = alpha;
}
Tags
ray marching