Orthographic blending (wip)

  • Prevent perspective from warping models near the screen edges
  • Has a depth offset for 3D model “sorting”
Shader code
shader_type spatial;
render_mode skip_vertex_transform;

global uniform float CameraDistance = 5.4;
global uniform float CameraFOV = 32.0;
global uniform bool OrthoBlendEnabled = true;

uniform vec3 tint_color : source_color = vec3(1);
uniform sampler2D albedo_texture : source_color;
uniform float ortho_blend : hint_range(0.0, 1.0) = 0.7;
uniform float depth_offset = 0.0;

vec2 get_fov(vec2 vpSize) {
    float aspect = vpSize.x / vpSize.y;
    float fov_y = radians(CameraFOV);
    float fov_x = 2.0 * atan(tan(fov_y * 0.5) * aspect);
    return vec2(fov_x, fov_y);    
}

vec4 get_ortho_vector(mat4 viewMtx, vec2 fov) {    
    vec2 size = CameraDistance * tan(fov * 0.5);
    
    mat4 ortho_matrix = mat4(
        vec4(1.0 / size.x, 0.0, 0.0, 0.0),
        vec4(0.0, 1.0 / size.y, 0.0, 0.0),
        vec4(0.0, 0.0, 0.0, 0.0),
        vec4(0.0, 0.0, 0.0, 1.0)
    ) * viewMtx;

    return vec4(
        ortho_matrix[0][0],
        ortho_matrix[1][0],
        ortho_matrix[2][0],
        ortho_matrix[3][0]
    );
}

void vertex() {
    NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
    BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz);
    TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
    mat4 CLIP_MATRIX = PROJECTION_MATRIX * VIEW_MATRIX;
    mat4 INV_CLIP_MATRIX = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX;
    vec3 local_pos = VERTEX;
    vec4 world_pos = MODEL_MATRIX * vec4(local_pos, 1.0);
    vec4 camera_pos = INV_VIEW_MATRIX[3];
    vec4 relative_pos = world_pos - camera_pos;
    vec4 clip_pos = CLIP_MATRIX * relative_pos;

    // Reconstruct FOV
    vec2 fov = get_fov(VIEWPORT_SIZE);
    vec4 ortho_vector = get_ortho_vector(VIEW_MATRIX, fov);
    float blend_amount = OrthoBlendEnabled ? ortho_blend : 0.0;

    // Apply ortho blending
    float ortho_value = dot(ortho_vector, relative_pos) * clip_pos.w;
    vec4 ortho_clip_pos = vec4(mix(clip_pos.x, ortho_value, blend_amount), clip_pos.yzw);
    vec4 final_pos = INV_CLIP_MATRIX * ortho_clip_pos;    
    final_pos += camera_pos;
    
    // Apply depth offset
    vec4 camera_direction = normalize(camera_pos - world_pos);
    vec4 depth_pos_offset = camera_direction * depth_offset;
    final_pos += depth_pos_offset;
    
    POSITION = CLIP_MATRIX * final_pos;
}

void fragment() {
    vec4 tex = texture(albedo_texture, UV);
    ALBEDO = tex.xyz * tint_color;
}
Live Preview
Tags
depth offset, ortho blending, orthogonal
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 lucasteles42

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments