This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/modes/shaders/armature_sphere_frag.glsl
Clément Foucault 8c2a6f957a Armature: "Raytrace" bones endpoint spheres.
Here is how it works:
We render a high poly disc that we orient & scale towards the camera so that
it covers the same pixel of the sphere it's supposed to represent.

Then the pixel shader raytrace the sphere (effectively starting from
the poly disc depth) and outputs the depth to gl_FragDepth.

This approach has many benefit:
- high quality obviously: per pixel accurate depth!
- compatible with MSAA: since the sphere horizon is delimited by polygons,
  we get the coverage computed by the rasterizer. However we still gets
  aliasing if the sphere intersect directly other meshes.
- virtually no overdraw: there is no backface to shade but we still get
  overdraw because by little triangle [gpus rasterize pixel by groups of 4].
- allows early depth test: since the poly disc is set at the nearest depth
  we can output, we can use GL_ARB_conservative_depth to enable early depth
  test and discard pixels that are already behind geometry.
- can draw outline pretty easily without geometry shader.
2018-05-02 20:49:38 +02:00

75 lines
2.3 KiB
GLSL

#extension GL_ARB_conservative_depth : enable
uniform mat4 ViewMatrixInverse;
uniform mat4 ProjectionMatrix;
flat in vec3 solidColor;
flat in mat4 sphereMatrix;
in vec3 viewPosition;
#ifdef GL_ARB_conservative_depth
/* Saves a lot of overdraw! */
layout(depth_greater) out float gl_FragDepth;
#endif
out vec4 fragColor;
#define cameraPos ViewMatrixInverse[3].xyz
float get_depth_from_view_z(float z)
{
if (ProjectionMatrix[3][3] == 0.0) {
z = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
}
else {
z = z * ProjectionMatrix[2][2] / (1.0 - ProjectionMatrix[3][2]);
}
return z * 0.5 + 0.5;
}
void main()
{
const float sphere_radius = 0.05;
bool is_perp = (ProjectionMatrix[3][3] == 0.0);
vec3 ray_ori_view = (is_perp) ? vec3(0.0) : viewPosition.xyz;
vec3 ray_dir_view = (is_perp) ? viewPosition : vec3(0.0, 0.0, -1.0);
/* Single matrix mul without branch. */
vec4 mul_vec = (is_perp) ? vec4(ray_dir_view, 0.0) : vec4(ray_ori_view, 1.0);
vec3 mul_res = (sphereMatrix * mul_vec).xyz;
/* Reminder :
* sphereMatrix[3] is the view space origin in sphere space (sph_ori -> view_ori).
* sphereMatrix[2] is the view space Z axis in sphere space. */
/* convert to sphere local space */
vec3 ray_ori = (is_perp) ? sphereMatrix[3].xyz : mul_res;
vec3 ray_dir = (is_perp) ? mul_res : -sphereMatrix[2].xyz;
float ray_len = length(ray_dir);
ray_dir /= ray_len;
/* Line to sphere intersect */
const float sphere_radius_sqr = sphere_radius * sphere_radius;
float b = dot(ray_ori, ray_dir);
float c = dot(ray_ori, ray_ori) - sphere_radius_sqr;
float h = b * b - c;
float t = -sqrt(max(0.0, h)) - b;
/* Compute dot product for lighting */
vec3 p = ray_dir * t + ray_ori; /* Point on sphere */
vec3 n = normalize(p); /* Normal is just the point in sphere space, normalized. */
vec3 l = normalize(sphereMatrix[2].xyz); /* Just the view Z axis in the sphere space. */
float col = clamp(dot(n, l), 0.0, 1.0);
/* 2x2 dither pattern to smooth the lighting. */
float dither = (0.5 + dot(vec2(ivec2(gl_FragCoord.xy) & ivec2(1)), vec2(1.0, 2.0))) * 0.25;
dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */
fragColor = vec4(col * solidColor + dither, 1.0);
t /= ray_len;
gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z);
}