Depth based Tilt-shift

Updated to 4.3 (look at comment regarding POSITION in vertex() for lower versions)

Tilt-shift is an effect that blurs out parts of the image far from the plane of focus, creating a miniaturization effect. You can fake this effect by just blurring out top and bottom of the screen, but this fails if you want to: focus on a tall object that overlaps the blurred parts of the image, when camera is looking top-down (blur based on height), and if left right parts of image should be blurred (when going through a canyon).

This doc explains focal planes: Tilt Shifting and Focal Planes

This shader is a screen shader that reads depth from a quad applied over the camera. You will need to follow instructions from godot docs on how to set up one: Full screen quad

If your camera moves, you will also need to update the focal point of the shader through code, either to follow your moving object or where camera is pointing:

func _process(delta):
    mesh_instance_3d.mesh.material.set_shader_parameter(&"focal_point", global_position)

Note: Doesn’t blur objects with transparency, but this is an engine issue

Models from KayKit-City-Builder-Bits-1.0

Shader code
shader_type spatial;
render_mode unshaded;
uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
varying mat4 CAMERA;
/** Focal point of camera in world space
 * Change this in code to follow where camera is looking at, or follow player position
 */
uniform vec3 focal_point = vec3(0.0);
/** Depth of field, the width of focal plane in meters
 */
uniform float DoF = 5.0;
/** Maximum amount of blur based off of distance from focal plane
 */
uniform float blur_cap: hint_range(0.0,8.0) = 2.0;
/** How quickly blur occurs away from focal plane
 * Bigger number is slower, smaller number is faster
 */
uniform float blur_rate = 2.0;
/** Multiples y vector of focal plane to make it less or more vertical
 * Value of 1.0 is no change (focal plane is perpendicular to camera), 0.0 will make focal plane vertical regardless of camera angle (perpendicular to floor since y vector is now 0).
 * Focal plane is typically perpendicular to camera view, but a more vertical focal plane may sometimes look better if we want background to blur consistently regardless of distance to plane.
 * Example use case: Tall buildings show up focused in background because they are at same depth as focal plane, and while this is correct we may not personally like the look so we set value closer to 0.0.
 */
uniform float vertical_bias = 1.0;

void vertex() {
	//4.2 and lower
	//POSITION = vec4(VERTEX, 1.0);
	//
	//4.3 and higher
	POSITION = vec4(VERTEX.xy, 1.0, 1.0);
	//
	CAMERA = INV_VIEW_MATRIX;
}

float PlanePointDist(vec3 pn, vec3 pp, vec3 p){
	float d = -(pn.x * pp.x + pn.y * pp.y + pn.z * pp.z);
	float a = abs((pn.x * p.x + pn.y * p.y + pn.z * p.z + d));
    float b = sqrt(pn.x * pn.x + pn.y * pn.y + pn.z * pn.z);
	return a/b;
}

void fragment() {
	float depth = textureLod(depth_texture, SCREEN_UV, 0.0).r;
	vec4 upos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth, 1.0);
	vec4 world = CAMERA * upos;
	vec3 world_position = world.xyz / world.w;
	vec3 focal_plane_normal = focal_point - CAMERA_POSITION_WORLD;
	focal_plane_normal.y *= vertical_bias;
	float dist_to_plane = PlanePointDist(focal_plane_normal, focal_point, world_position);
	float blur_amount = clamp((dist_to_plane-DoF)/blur_rate, 0.0, blur_cap);
	vec4 color = textureLod(screen_texture, SCREEN_UV, blur_amount);
	ALBEDO = color.xyz;
}
Tags
camera, depth, screen, tilt-shift
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from kidcolt

Extrude 2D Texture in 3D

Related shaders

Depth-based Edge Detection with Sobel Operator – Screenspace

Depth-Based Outline

Per object depth-based outline

Subscribe
Notify of
guest

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Irrwisch
3 months ago

Hey, your shader looks really nice, but I can’t get it to work.

It’s showing up in the Editor, but not in game. And also it looks wrong:

comment image

I tried setting the focal point to my globalPosition of my character too

Last edited 3 months ago by Irrwisch