Ray Marching Lava Lamp

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
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from david__dylan

2D Water Themed Background Shader

Related shaders

Ray marching ocean waves + atmosphere

X-ray Vision Effect

Ray-box setup

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments