From 9516921c05bd9fee5c94942eb8e38f47ba7e4351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 2 Dec 2019 01:40:58 +0100 Subject: Overlay Engine: Refactor & Cleanup This is the unification of all overlays into one overlay engine as described in T65347. I went over all the code making it more future proof with less hacks and removing old / not relevent parts. Goals / Acheivements: - Remove internal shader usage (only drw shaders) - Remove viewportSize and viewportSizeInv and put them in gloabl ubo - Fixed some drawing issues: Missing probe option and Missing Alt+B clipping of some shader - Remove old (legacy) shaders dependancy (not using view UBO). - Less shader variation (less compilation time at first load and less patching needed for vulkan) - removed some geom shaders when I could - Remove static e_data (except shaders storage where it is OK) - Clear the way to fix some anoying limitations (dithered transparency, background image compositing etc...) - Wireframe drawing now uses the same batching capabilities as workbench & eevee (indirect drawing). - Reduced complexity, removed ~3000 Lines of code in draw (also removed a lot of unused shader in GPU). - Post AA to avoid complexity and cost of MSAA. Remaining issues: - ~~Armature edits, overlay toggles, (... others?) are not refreshing viewport after AA is complete~~ - FXAA is not the best for wires, maybe investigate SMAA - Maybe do something more temporally stable for AA. - ~~Paint overlays are not working with AA.~~ - ~~infront objects are difficult to select.~~ - ~~the infront wires sometimes goes through they solid counterpart (missing clear maybe?) (toggle overlays on-off when using infront+wireframe overlay in solid shading)~~ Note: I made some decision to change slightly the appearance of some objects to simplify their drawing. Namely the empty arrows end (which is now hollow/wire) and distance points of the cameras/spots being done by lines. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D6296 --- .../engines/overlay/shaders/antialiasing_frag.glsl | 135 +++++++++++ .../engines/overlay/shaders/antialiasing_vert.glsl | 11 + .../engines/overlay/shaders/armature_dof_vert.glsl | 33 +++ .../shaders/armature_envelope_outline_vert.glsl | 164 ++++++++++++++ .../shaders/armature_envelope_solid_frag.glsl | 25 +++ .../shaders/armature_envelope_solid_vert.glsl | 55 +++++ .../shaders/armature_shape_outline_geom.glsl | 116 ++++++++++ .../shaders/armature_shape_outline_vert.glsl | 48 ++++ .../overlay/shaders/armature_shape_solid_frag.glsl | 11 + .../overlay/shaders/armature_shape_solid_vert.glsl | 37 +++ .../shaders/armature_sphere_outline_vert.glsl | 104 +++++++++ .../shaders/armature_sphere_solid_frag.glsl | 76 +++++++ .../shaders/armature_sphere_solid_vert.glsl | 87 ++++++++ .../overlay/shaders/armature_stick_frag.glsl | 13 ++ .../overlay/shaders/armature_stick_vert.glsl | 90 ++++++++ .../overlay/shaders/armature_wire_vert.glsl | 18 ++ .../engines/overlay/shaders/depth_only_vert.glsl | 14 ++ .../overlay/shaders/edit_curve_handle_geom.glsl | 114 ++++++++++ .../overlay/shaders/edit_curve_handle_vert.glsl | 18 ++ .../overlay/shaders/edit_curve_point_vert.glsl | 29 +++ .../overlay/shaders/edit_curve_wire_vert.glsl | 31 +++ .../overlay/shaders/edit_lattice_point_vert.glsl | 32 +++ .../overlay/shaders/edit_lattice_wire_vert.glsl | 38 ++++ .../overlay/shaders/edit_mesh_analysis_frag.glsl | 8 + .../overlay/shaders/edit_mesh_analysis_vert.glsl | 35 +++ .../overlay/shaders/edit_mesh_common_lib.glsl | 76 +++++++ .../overlay/shaders/edit_mesh_facefill_frag.glsl | 7 + .../overlay/shaders/edit_mesh_facefill_vert.glsl | 23 ++ .../engines/overlay/shaders/edit_mesh_frag.glsl | 46 ++++ .../engines/overlay/shaders/edit_mesh_geom.glsl | 88 ++++++++ .../overlay/shaders/edit_mesh_normal_vert.glsl | 53 +++++ .../overlay/shaders/edit_mesh_skin_root_vert.glsl | 25 +++ .../engines/overlay/shaders/edit_mesh_vert.glsl | 97 ++++++++ .../overlay/shaders/edit_particle_point_vert.glsl | 19 ++ .../overlay/shaders/edit_particle_strand_vert.glsl | 42 ++++ .../draw/engines/overlay/shaders/extra_frag.glsl | 13 ++ .../overlay/shaders/extra_groundline_vert.glsl | 30 +++ .../overlay/shaders/extra_loose_point_frag.glsl | 18 ++ .../overlay/shaders/extra_loose_point_vert.glsl | 20 ++ .../engines/overlay/shaders/extra_point_vert.glsl | 30 +++ .../draw/engines/overlay/shaders/extra_vert.glsl | 227 +++++++++++++++++++ .../engines/overlay/shaders/extra_wire_frag.glsl | 31 +++ .../engines/overlay/shaders/extra_wire_vert.glsl | 40 ++++ .../draw/engines/overlay/shaders/facing_frag.glsl | 9 + .../draw/engines/overlay/shaders/facing_vert.glsl | 12 + .../draw/engines/overlay/shaders/grid_frag.glsl | 248 +++++++++++++++++++++ .../draw/engines/overlay/shaders/grid_vert.glsl | 52 +++++ .../draw/engines/overlay/shaders/image_frag.glsl | 34 +++ .../draw/engines/overlay/shaders/image_vert.glsl | 21 ++ .../overlay/shaders/motion_path_line_geom.glsl | 47 ++++ .../overlay/shaders/motion_path_line_vert.glsl | 96 ++++++++ .../overlay/shaders/motion_path_point_vert.glsl | 58 +++++ .../overlay/shaders/outline_detect_frag.glsl | 86 +++++++ .../overlay/shaders/outline_expand_frag.glsl | 51 +++++ .../shaders/outline_lightprobe_grid_vert.glsl | 31 +++ .../overlay/shaders/outline_prepass_frag.glsl | 18 ++ .../overlay/shaders/outline_prepass_geom.glsl | 54 +++++ .../overlay/shaders/outline_prepass_vert.glsl | 29 +++ .../overlay/shaders/outline_resolve_frag.glsl | 21 ++ .../engines/overlay/shaders/paint_face_vert.glsl | 24 ++ .../engines/overlay/shaders/paint_point_vert.glsl | 32 +++ .../overlay/shaders/paint_texture_frag.glsl | 23 ++ .../overlay/shaders/paint_texture_vert.glsl | 19 ++ .../overlay/shaders/paint_vertcol_frag.glsl | 28 +++ .../overlay/shaders/paint_vertcol_vert.glsl | 27 +++ .../engines/overlay/shaders/paint_weight_frag.glsl | 106 +++++++++ .../engines/overlay/shaders/paint_weight_vert.glsl | 20 ++ .../engines/overlay/shaders/paint_wire_vert.glsl | 38 ++++ .../engines/overlay/shaders/particle_frag.glsl | 16 ++ .../engines/overlay/shaders/particle_vert.glsl | 68 ++++++ .../engines/overlay/shaders/sculpt_mask_vert.glsl | 20 ++ .../overlay/shaders/volume_velocity_vert.glsl | 117 ++++++++++ .../engines/overlay/shaders/wireframe_frag.glsl | 20 ++ .../engines/overlay/shaders/wireframe_geom.glsl | 61 +++++ .../engines/overlay/shaders/wireframe_vert.glsl | 144 ++++++++++++ 75 files changed, 3857 insertions(+) create mode 100644 source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/facing_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/facing_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/grid_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/grid_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/image_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/image_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/particle_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/particle_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl create mode 100644 source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl (limited to 'source/blender/draw/engines/overlay/shaders') diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl new file mode 100644 index 00000000000..98f69abe89f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl @@ -0,0 +1,135 @@ + +uniform sampler2D colorTex; +uniform sampler2D depthTex; +uniform sampler2D lineTex; + +in vec2 uvs; + +out vec4 fragColor; + +#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ + +/** + * We want to know how much a pixel is covered by a line. + * We replace the square pixel with acircle of the same area and try to find the intersection area. + * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment + * The formula for the area uses inverse trig function and is quite complexe. Instead, + * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius. + */ +#define DISC_RADIUS (M_1_SQRTPI * 1.05) +#define LINE_SMOOTH_START (0.5 - DISC_RADIUS) +#define LINE_SMOOTH_END (0.5 + DISC_RADIUS) + +/** + * Returns coverage of a line onto a sample that is distance_to_line (in pixels) far from the line. + * line_kernel_size is the inner size of the line with 100% coverage. + */ +float line_coverage(float distance_to_line, float line_kernel_size) +{ + return smoothstep(LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size); +} +vec4 line_coverage(vec4 distance_to_line, float line_kernel_size) +{ + return smoothstep(LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size); +} + +vec2 decode_line_dir(vec2 dir) +{ + return dir * 2.0 - 1.0; +} + +float decode_line_dist(float dist) +{ + return (dist - 0.1) * 4.0 - 2.0; +} + +float neighbor_dist(vec3 line_dir_and_dist, vec2 ofs) +{ + float dist = decode_line_dist(line_dir_and_dist.z); + vec2 dir = decode_line_dir(line_dir_and_dist.xy); + + bool is_line = line_dir_and_dist.z != 0.0; + bool dir_horiz = abs(dir.x) > abs(dir.y); + bool ofs_horiz = (ofs.x != 0); + + if (!is_line || (ofs_horiz != dir_horiz)) { + dist += 1e10; /* No line. */ + } + else { + dist += dot(ofs, -dir); + } + return dist; +} + +void neighbor_blend( + float line_coverage, float line_depth, vec4 line_color, inout float frag_depth, inout vec4 col) +{ + line_color *= line_coverage; + if (line_coverage > 0.0 && line_depth < frag_depth) { + /* Alpha over. */ + col = col * (1.0 - line_color.a) + line_color; + frag_depth = line_depth; + } + else { + /* Alpha under. */ + col = col + line_color * (1.0 - col.a); + } +} + +void main() +{ + ivec2 center_texel = ivec2(gl_FragCoord.xy); + const float line_kernel = 0.0; + + fragColor = texelFetch(colorTex, center_texel, 0); + + float depth = texelFetch(depthTex, center_texel, 0).r; + + float dist_raw = texelFetch(lineTex, center_texel, 0).b; + float dist = decode_line_dist(dist_raw); + + /* TODO Opti: use textureGather */ + vec4 neightbor_col0 = texelFetchOffset(colorTex, center_texel, 0, ivec2(1, 0)); + vec4 neightbor_col1 = texelFetchOffset(colorTex, center_texel, 0, ivec2(-1, 0)); + vec4 neightbor_col2 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, 1)); + vec4 neightbor_col3 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, -1)); + + vec3 neightbor_line0 = texelFetchOffset(lineTex, center_texel, 0, ivec2(1, 0)).rgb; + vec3 neightbor_line1 = texelFetchOffset(lineTex, center_texel, 0, ivec2(-1, 0)).rgb; + vec3 neightbor_line2 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, 1)).rgb; + vec3 neightbor_line3 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, -1)).rgb; + + vec4 depths; + depths.x = texelFetchOffset(depthTex, center_texel, 0, ivec2(1, 0)).r; + depths.y = texelFetchOffset(depthTex, center_texel, 0, ivec2(-1, 0)).r; + depths.z = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, 1)).r; + depths.w = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, -1)).r; + + vec4 line_dists; + line_dists.x = neighbor_dist(neightbor_line0, vec2(1, 0)); + line_dists.y = neighbor_dist(neightbor_line1, vec2(-1, 0)); + line_dists.z = neighbor_dist(neightbor_line2, vec2(0, 1)); + line_dists.w = neighbor_dist(neightbor_line3, vec2(0, -1)); + + vec4 coverage = line_coverage(line_dists, line_kernel); + + if (dist_raw > 0.0) { + fragColor *= line_coverage(dist, line_kernel); + } + + /* We dont order fragments but use alpha over/alpha under based on current minimum frag depth. */ + neighbor_blend(coverage.x, depths.x, neightbor_col0, depth, fragColor); + neighbor_blend(coverage.y, depths.y, neightbor_col1, depth, fragColor); + neighbor_blend(coverage.z, depths.z, neightbor_col2, depth, fragColor); + neighbor_blend(coverage.w, depths.w, neightbor_col3, depth, fragColor); + +#if 1 + /* Fix aliasing issue with really dense meshes and 1 pixel sized lines. */ + if (dist_raw > 0.0 && line_kernel < 0.45) { + vec4 lines = vec4(neightbor_line0.z, neightbor_line1.z, neightbor_line2.z, neightbor_line3.z); + /* Count number of line neighbors. */ + float blend = dot(vec4(0.25), step(0.001, lines)); + fragColor = mix(fragColor, fragColor / fragColor.a, blend); + } +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl new file mode 100644 index 00000000000..4f3c36c7bd7 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl @@ -0,0 +1,11 @@ + +out vec2 uvs; + +void main() +{ + int v = gl_VertexID % 3; + float x = float((v & 1) << 2); + float y = float((v & 2) << 1); + gl_Position = vec4(x - 1.0, y - 1.0, 1.0, 1.0); + uvs = vec2(x, y) * 0.5; +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl new file mode 100644 index 00000000000..371229f23ab --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl @@ -0,0 +1,33 @@ + +/* ---- Instantiated Attrs ---- */ +in vec2 pos; + +/* ---- Per instance Attrs ---- */ +/* Assumed to be in world coordinate already. */ +in vec4 color; +in mat4 inst_obmat; + +flat out vec4 finalColor; + +vec3 sphere_project(float ax, float az) +{ + float sine = 1.0 - ax * ax - az * az; + float q3 = sqrt(max(0.0, sine)); + + return vec3(-az * q3, 0.5 - sine, ax * q3) * 2.0; +} + +void main() +{ + mat4 model_mat = inst_obmat; + model_mat[0][3] = model_mat[1][3] = model_mat[2][3] = 0.0; + model_mat[3][3] = 1.0; + + vec2 amin = vec2(inst_obmat[0][3], inst_obmat[1][3]); + vec2 amax = vec2(inst_obmat[2][3], inst_obmat[3][3]); + + vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x), + pos.y * abs((pos.y > 0.0) ? amax.y : amin.y)); + gl_Position = ViewProjectionMatrix * (model_mat * vec4(final_pos, 1.0)); + finalColor = color; +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl new file mode 100644 index 00000000000..e3cc8d582d8 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl @@ -0,0 +1,164 @@ + +/* ---- Instantiated Attrs ---- */ +in vec2 pos0; +in vec2 pos1; +in vec2 pos2; + +/* ---- Per instance Attrs ---- */ +/* Assumed to be in world coordinate already. */ +in vec4 headSphere; +in vec4 tailSphere; +in vec4 outlineColorSize; +in vec3 xAxis; + +flat out vec4 finalColor; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy; +} + +vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2) +{ + vec2 dir = normalize(v2 - v0); + dir = vec2(dir.y, -dir.x); + return dir; +} + +mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs) +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz : -ViewMatrixInverse[2].xyz; + + /* Sphere center distance from the camera (persp) in world space. */ + float cam_dist = length(cam_ray); + + /* Compute view aligned orthonormal space. */ + vec3 z_axis = cam_ray / cam_dist; + vec3 x_axis = normalize(cross(bone_vec, z_axis)); + vec3 y_axis = cross(z_axis, x_axis); + z_ofs = 0.0; + + if (is_persp) { + /* For perspective, the projected sphere radius + * can be bigger than the center disc. Compute the + * max angular size and compensate by sliding the disc + * towards the camera and scale it accordingly. */ + const float half_pi = 3.1415926 * 0.5; + float rad = sphere.w; + /* Let be : + * V the view vector origin. + * O the sphere origin. + * T the point on the target circle. + * We compute the angle between (OV) and (OT). */ + float a = half_pi - asin(rad / cam_dist); + float cos_b = cos(a); + float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0)); + + x_axis *= sin_b; + y_axis *= sin_b; + z_ofs = -rad * cos_b; + } + + return mat3(x_axis, y_axis, z_axis); +} + +struct Bone { + vec3 vec; + float sinb; +}; + +bool bone_blend_starts(vec3 p, Bone b) +{ + /* we just want to know when the head sphere starts interpolating. */ + return dot(p, b.vec) > -b.sinb; +} + +vec3 get_outline_point(vec2 pos, + vec4 sph_near, + vec4 sph_far, + mat3 mat_near, + mat3 mat_far, + float z_ofs_near, + float z_ofs_far, + Bone b) +{ + /* Compute outline position on the nearest sphere and check + * if it penetrates the capsule body. If it does, put this + * vertex on the farthest sphere. */ + vec3 wpos = mat_near * vec3(pos * sph_near.w, z_ofs_near); + if (bone_blend_starts(wpos, b)) { + wpos = sph_far.xyz + mat_far * vec3(pos * sph_far.w, z_ofs_far); + } + else { + wpos += sph_near.xyz; + } + return wpos; +} + +void main() +{ + float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz); + float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz); + // float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz); + // float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz); + + vec4 sph_near, sph_far; + if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) { + sph_near = tailSphere; + sph_far = headSphere; + } + else { + sph_near = headSphere; + sph_far = tailSphere; + } + + vec3 bone_vec = (sph_far.xyz - sph_near.xyz) + 1e-8; + + Bone b; + float bone_lenrcp = 1.0 / max(1e-8, sqrt(dot(bone_vec, bone_vec))); + b.sinb = (sph_far.w - sph_near.w) * bone_lenrcp * sph_near.w; + b.vec = bone_vec * bone_lenrcp; + + float z_ofs_near, z_ofs_far; + mat3 mat_near = compute_mat(sph_near, bone_vec, z_ofs_near); + mat3 mat_far = compute_mat(sph_far, bone_vec, z_ofs_far); + + vec3 wpos0 = get_outline_point( + pos0, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b); + vec3 wpos1 = get_outline_point( + pos1, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b); + vec3 wpos2 = get_outline_point( + pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b); + + vec4 pos_4d = vec4(wpos1, 1.0); +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(pos_4d.xyz); +#endif + + vec4 V = ViewMatrix * pos_4d; + float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0; + + vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0); + vec4 p1 = ProjectionMatrix * V; + vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0); + + /* compute position from 3 vertex because the change in direction + * can happen very quicky and lead to very thin edges. */ + vec2 ss0 = proj(p0); + vec2 ss1 = proj(p1); + vec2 ss2 = proj(p2); + vec2 edge_dir = compute_dir(ss0, ss1, ss2); + + float line_thickness = 2.0 * sizePixel; + bool outer = ((gl_VertexID & 1) == 1); + vec2 t = outlineColorSize.w * line_thickness * sizeViewportInv.xy; + t *= pres_fac; + t = (outer) ? t : vec2(0.0); + + gl_Position = p1; + gl_Position.xy += t * edge_dir; + + finalColor = vec4(outlineColorSize.rgb, 1.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl new file mode 100644 index 00000000000..d0a8e48657e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl @@ -0,0 +1,25 @@ + +uniform float alpha = 0.6; +uniform bool isDistance; + +flat in vec3 finalStateColor; +flat in vec3 finalBoneColor; +in vec3 normalView; + +out vec4 fragColor; + +void main() +{ + float n = normalize(normalView).z; + if (isDistance) { + n = 1.0 - clamp(-n, 0.0, 1.0); + fragColor = vec4(1.0, 1.0, 1.0, 0.2) * n; + } + else { + /* Smooth lighting factor. */ + const float s = 0.2; /* [0.0-0.5] range */ + float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0); + fragColor.rgb = mix(finalStateColor, finalBoneColor, fac); + fragColor.a = alpha; + } +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl new file mode 100644 index 00000000000..620b3f2527c --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl @@ -0,0 +1,55 @@ + +/* ---- Instantiated Attrs ---- */ +in vec3 pos; + +/* ---- Per instance Attrs ---- */ +/* Assumed to be in world coordinate already. */ +in vec4 headSphere; +in vec4 tailSphere; +in vec3 xAxis; +in vec3 stateColor; +in vec3 boneColor; + +flat out vec3 finalStateColor; +flat out vec3 finalBoneColor; +out vec3 normalView; + +void main() +{ + vec3 bone_vec = tailSphere.xyz - headSphere.xyz; + float bone_len = max(1e-8, sqrt(dot(bone_vec, bone_vec))); + float bone_lenrcp = 1.0 / bone_len; +#ifdef SMOOTH_ENVELOPE + float sinb = (tailSphere.w - headSphere.w) * bone_lenrcp; +#else + const float sinb = 0.0; +#endif + + vec3 y_axis = bone_vec * bone_lenrcp; + vec3 z_axis = normalize(cross(xAxis, -y_axis)); + vec3 x_axis = cross(y_axis, z_axis); /* cannot trust xAxis to be orthogonal. */ + + vec3 sp, nor; + nor = sp = pos.xyz; + + /* In bone space */ + bool is_head = (pos.z < -sinb); + sp *= (is_head) ? headSphere.w : tailSphere.w; + sp.z += (is_head) ? 0.0 : bone_len; + + /* Convert to world space */ + mat3 bone_mat = mat3(x_axis, y_axis, z_axis); + sp = bone_mat * sp.xzy + headSphere.xyz; + nor = bone_mat * nor.xzy; + + normalView = mat3(ViewMatrix) * nor; + + finalStateColor = stateColor; + finalBoneColor = boneColor; + + vec4 pos_4d = vec4(sp, 1.0); + gl_Position = ViewProjectionMatrix * pos_4d; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(pos_4d.xyz); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl new file mode 100644 index 00000000000..bd05c7f3532 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl @@ -0,0 +1,116 @@ + +layout(lines_adjacency) in; +layout(triangle_strip, max_vertices = 6) out; + +in vec4 pPos[]; +in vec3 vPos[]; +in vec2 ssPos[]; +in vec2 ssNor[]; +in vec4 vColSize[]; + +flat out vec4 finalColor; + +vec2 compute_dir(vec2 v0, vec2 v1) +{ + vec2 dir = normalize(v1 - v0); + dir = vec2(-dir.y, dir.x); + return dir; +} + +void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp) +{ + float fac = dot(-hidden_dir, edge_dir); + edge_dir *= (fac < 0.0) ? -1.0 : 1.0; + + vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0); + gl_Position = pPos[1]; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance); +#endif + EmitVertex(); + gl_Position.xy += t * edge_dir; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance); +#endif + EmitVertex(); + + t = thick * (is_persp ? abs(vPos[2].z) : 1.0); + gl_Position = pPos[2]; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance); +#endif + EmitVertex(); + gl_Position.xy += t * edge_dir; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance); +#endif + EmitVertex(); +} + +void emit_corner(const int e, vec2 thick, bool is_persp) +{ + vec2 corner_dir = ssNor[e]; + vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0); + + gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0); +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[e].gl_ClipDistance); +#endif + EmitVertex(); +} + +void main(void) +{ + finalColor = vec4(vColSize[0].rgb, 1.0); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0); + vec3 v10 = vPos[0] - vPos[1]; + vec3 v12 = vPos[2] - vPos[1]; + vec3 v13 = vPos[3] - vPos[1]; + + vec3 n0 = cross(v12, v10); + vec3 n3 = cross(v13, v12); + + float fac0 = dot(view_vec, n0); + float fac3 = dot(view_vec, n3); + + /* If one of the face is perpendicular to the view, + * consider it and outline edge. */ + if (abs(fac0) > 1e-5 && abs(fac3) > 1e-5) { + /* If both adjacent verts are facing the camera the same way, + * then it isn't an outline edge. */ + if (sign(fac0) == sign(fac3)) { + return; + } + } + + /* Don't outline if concave edge. */ + if (dot(n0, v13) > 0.0001) { + return; + } + + float line_thickness = 2.0 * sizePixel; + vec2 thick = vColSize[0].w * (line_thickness * sizeViewportInv.xy); + vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]); + + vec2 hidden_point; + /* Take the farthest point to compute edge direction + * (avoid problems with point behind near plane). + * If the chosen point is parallel to the edge in screen space, + * choose the other point anyway. + * This fixes some issue with cubes in orthographic views.*/ + if (vPos[0].z < vPos[3].z) { + hidden_point = (abs(fac0) > 1e-5) ? ssPos[0] : ssPos[3]; + } + else { + hidden_point = (abs(fac3) > 1e-5) ? ssPos[3] : ssPos[0]; + } + vec2 hidden_dir = normalize(hidden_point - ssPos[1]); + + emit_corner(1, thick, is_persp); + emit_edge(edge_dir, hidden_dir, thick, is_persp); + emit_corner(2, thick, is_persp); + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl new file mode 100644 index 00000000000..cd9368a997a --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl @@ -0,0 +1,48 @@ + +/* ---- Instantiated Attrs ---- */ +in vec3 pos; +in vec3 snor; + +/* ---- Per instance Attrs ---- */ +in vec4 color; +in mat4 inst_obmat; + +out vec4 pPos; +out vec3 vPos; +out vec2 ssPos; +out vec2 ssNor; +out vec4 vColSize; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy; +} + +void main() +{ + vec4 bone_color, state_color; + mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color); + + vec4 worldPosition = model_mat * vec4(pos, 1.0); + vec4 viewpos = ViewMatrix * worldPosition; + + vPos = viewpos.xyz; + pPos = ProjectionMatrix * viewpos; + + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attribute. */ + mat3 normal_mat = transpose(inverse(mat3(model_mat))); + /* TODO FIX: there is still a problem with this vector + * when the bone is scaled or in persp mode. But it's + * barelly visible at the outline corners. */ + ssNor = normalize(normal_world_to_view(normal_mat * snor).xy); + + ssPos = proj(pPos); + + vColSize = bone_color; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(worldPosition.xyz); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl new file mode 100644 index 00000000000..39963344dd8 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl @@ -0,0 +1,11 @@ + +uniform float alpha = 0.6; + +in vec4 finalColor; + +out vec4 fragColor; + +void main() +{ + fragColor = vec4(finalColor.rgb, alpha); +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl new file mode 100644 index 00000000000..8284bd43adc --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl @@ -0,0 +1,37 @@ + +/* ---- Instantiated Attrs ---- */ +in vec3 pos; +in vec3 nor; + +/* ---- Per instance Attrs ---- */ +in mat4 inst_obmat; + +out vec4 finalColor; + +void main() +{ + vec4 bone_color, state_color; + mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color); + + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attribute. */ + mat3 normal_mat = transpose(inverse(mat3(model_mat))); + vec3 normal = normalize(normal_world_to_view(normal_mat * nor)); + + /* Do lighting at an angle to avoid flat shading on front facing bone. */ + const vec3 light = vec3(0.1, 0.1, 0.8); + float n = dot(normal, light); + + /* Smooth lighting factor. */ + const float s = 0.2; /* [0.0-0.5] range */ + float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0); + finalColor.rgb = mix(state_color.rgb, bone_color.rgb, fac); + finalColor.a = 1.0; + + vec4 worldPosition = model_mat * vec4(pos, 1.0); + gl_Position = ViewProjectionMatrix * worldPosition; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(worldPosition.xyz); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl new file mode 100644 index 00000000000..9dd4c444116 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl @@ -0,0 +1,104 @@ + +/* ---- Instantiated Attrs ---- */ +in vec2 pos0; +in vec2 pos1; + +/* ---- Per instance Attrs ---- */ +in mat4 inst_obmat; + +flat out vec4 finalColor; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy; +} + +vec2 compute_dir(vec2 v0, vec2 v1, vec2 c) +{ + vec2 dir = normalize(v1 - v0); + dir = vec2(dir.y, -dir.x); + /* The model matrix can be scaled negativly. + * Use projected sphere center to determine + * the outline direction. */ + vec2 cv = c - v0; + dir = (dot(dir, cv) > 0.0) ? -dir : dir; + return dir; +} + +void main() +{ + vec4 bone_color, state_color; + mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color); + + mat4 model_view_matrix = ViewMatrix * model_mat; + mat4 sphereMatrix = inverse(model_view_matrix); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + /* This is the local space camera ray (not normalize). + * In perspective mode it's also the viewspace position + * of the sphere center. */ + vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0); + cam_ray = mat3(sphereMatrix) * cam_ray; + + /* Sphere center distance from the camera (persp) in local space. */ + float cam_dist = length(cam_ray); + + /* Compute view aligned orthonormal space. */ + vec3 z_axis = cam_ray / cam_dist; + vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis)); + vec3 y_axis = cross(z_axis, x_axis); + float z_ofs = 0.0; + + if (is_persp) { + /* For perspective, the projected sphere radius + * can be bigger than the center disc. Compute the + * max angular size and compensate by sliding the disc + * towards the camera and scale it accordingly. */ + const float half_pi = 3.1415926 * 0.5; + const float rad = 0.05; + /* Let be (in local space): + * V the view vector origin. + * O the sphere origin. + * T the point on the target circle. + * We compute the angle between (OV) and (OT). */ + float a = half_pi - asin(rad / cam_dist); + float cos_b = cos(a); + float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0)); + + x_axis *= sin_b; + y_axis *= sin_b; + z_ofs = -rad * cos_b; + } + + /* Camera oriented position (but still in local space) */ + vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs; + vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs; + + vec4 V = model_view_matrix * vec4(cam_pos0, 1.0); + vec4 p0 = ProjectionMatrix * V; + vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0)); + vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0); + + vec2 ssc = proj(c); + vec2 ss0 = proj(p0); + vec2 ss1 = proj(p1); + vec2 edge_dir = compute_dir(ss0, ss1, ssc); + + bool outer = ((gl_VertexID & 1) == 1); + + vec2 t = bone_color.w * (2.0 * sizeViewportInv.xy); + t *= (is_persp) ? abs(V.z) : 1.0; + t = (outer) ? t : vec2(0.0); + + gl_Position = p0; + gl_Position.xy += t * edge_dir; + + finalColor = vec4(bone_color.rgb, 1.0); + +#ifdef USE_WORLD_CLIP_PLANES + vec4 worldPosition = model_mat * vec4(cam_pos0, 1.0); + world_clip_planes_calc_clip_distance(worldPosition.xyz); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl new file mode 100644 index 00000000000..94f339c4561 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl @@ -0,0 +1,76 @@ + +uniform float alpha = 0.4; + +flat in vec3 finalStateColor; +flat in vec3 finalBoneColor; +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. */ + + /* Smooth lighting factor. */ + const float s = 0.2; /* [0.0-0.5] range */ + float fac = clamp((dot(n, l) * (1.0 - s)) + s, 0.0, 1.0); + fragColor.rgb = mix(finalStateColor, finalBoneColor, fac); + + /* 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(fragColor.rgb + dither, alpha); + + t /= ray_len; + gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z); +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl new file mode 100644 index 00000000000..e6fa29ce851 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl @@ -0,0 +1,87 @@ + +/* ---- Instantiated Attrs ---- */ +in vec2 pos; + +/* ---- Per instance Attrs ---- */ +in vec4 color; +in mat4 inst_obmat; + +flat out vec3 finalStateColor; +flat out vec3 finalBoneColor; +flat out mat4 sphereMatrix; +out vec3 viewPosition; + +/* Sphere radius */ +const float rad = 0.05; + +void main() +{ + vec4 bone_color, state_color; + mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color); + + mat4 model_view_matrix = ViewMatrix * model_mat; + sphereMatrix = inverse(model_view_matrix); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + /* This is the local space camera ray (not normalize). + * In perspective mode it's also the viewspace position + * of the sphere center. */ + vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0); + cam_ray = mat3(sphereMatrix) * cam_ray; + + /* Sphere center distance from the camera (persp) in local space. */ + float cam_dist = length(cam_ray); + + /* Compute view aligned orthonormal space. */ + vec3 z_axis = cam_ray / cam_dist; + vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis)); + vec3 y_axis = cross(z_axis, x_axis); + + float z_ofs = -rad - 1e-8; /* offset to the front of the sphere */ + if (is_persp) { + /* For perspective, the projected sphere radius + * can be bigger than the center disc. Compute the + * max angular size and compensate by sliding the disc + * towards the camera and scale it accordingly. */ + const float half_pi = 3.1415926 * 0.5; + /* Let be (in local space): + * V the view vector origin. + * O the sphere origin. + * T the point on the target circle. + * We compute the angle between (OV) and (OT). */ + float a = half_pi - asin(rad / cam_dist); + float cos_b = cos(a); + float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0)); +#if 1 + /* Instead of choosing the biggest circle in screenspace, + * we choose the nearest with the same angular size. This + * permit us to leverage GL_ARB_conservative_depth in the + * fragment shader. */ + float minor = cam_dist - rad; + float major = cam_dist - cos_b * rad; + float fac = minor / major; + sin_b *= fac; +#else + z_ofs = -rad * cos_b; +#endif + x_axis *= sin_b; + y_axis *= sin_b; + } + + /* Camera oriented position (but still in local space) */ + vec3 cam_pos = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs; + + vec4 pos_4d = vec4(cam_pos, 1.0); + vec4 V = model_view_matrix * pos_4d; + gl_Position = ProjectionMatrix * V; + viewPosition = V.xyz; + + finalStateColor = state_color.xyz; + finalBoneColor = bone_color.xyz; + +#ifdef USE_WORLD_CLIP_PLANES + vec4 worldPosition = model_mat * pos_4d; + world_clip_planes_calc_clip_distance(worldPosition.xyz); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl new file mode 100644 index 00000000000..ba89619e051 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl @@ -0,0 +1,13 @@ + +noperspective in float colorFac; +flat in vec4 finalWireColor; +flat in vec4 finalInnerColor; + +out vec4 fragColor; + +void main() +{ + float fac = smoothstep(1.0, 0.2, colorFac); + fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac); + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl new file mode 100644 index 00000000000..99bdbfea2be --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl @@ -0,0 +1,90 @@ + +/* ---- Instantiated Attrs ---- */ +in vec2 pos; /* bone aligned screen space */ +in uint flag; + +#define COL_WIRE 1u /* (1 << 0) */ +#define COL_HEAD 2u /* (1 << 1) */ +#define COL_TAIL 4u /* (1 << 2) */ +#define COL_BONE 8u /* (1 << 3) */ + +#define POS_HEAD 16u /* (1 << 4) */ +#define POS_TAIL 32u /* (1 << 5) */ /* UNUSED */ +#define POS_BONE 64u /* (1 << 6) */ + +/* ---- Per instance Attrs ---- */ +in vec3 boneStart; +in vec3 boneEnd; +in vec4 wireColor; /* alpha encode if we do wire. If 0.0 we dont. */ +in vec4 boneColor; /* alpha encode if we do bone. If 0.0 we dont. */ +in vec4 headColor; /* alpha encode if we do head. If 0.0 we dont. */ +in vec4 tailColor; /* alpha encode if we do tail. If 0.0 we dont. */ + +#define do_wire (wireColor.a > 0.0) +#define is_head bool(flag & POS_HEAD) +#define is_bone bool(flag & POS_BONE) + +noperspective out float colorFac; +flat out vec4 finalWireColor; +flat out vec4 finalInnerColor; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy; +} + +void main() +{ + finalInnerColor = ((flag & COL_HEAD) != 0u) ? headColor : tailColor; + finalInnerColor = ((flag & COL_BONE) != 0u) ? boneColor : finalInnerColor; + finalWireColor = (do_wire) ? wireColor : finalInnerColor; + /* Make the color */ + colorFac = ((flag & COL_WIRE) == 0u) ? ((flag & COL_BONE) != 0u) ? 1.0 : 2.0 : 0.0; + + vec4 boneStart_4d = vec4(boneStart, 1.0); + vec4 boneEnd_4d = vec4(boneEnd, 1.0); + vec4 v0 = ViewMatrix * boneStart_4d; + vec4 v1 = ViewMatrix * boneEnd_4d; + + /* Clip the bone to the camera origin plane (not the clip plane) + * to avoid glitches if one end is behind the camera origin (in persp). */ + float clip_dist = (ProjectionMatrix[3][3] == 0.0) ? + -1e-7 : + 1e20; /* hardcoded, -1e-8 is giving gliches. */ + vec3 bvec = v1.xyz - v0.xyz; + vec3 clip_pt = v0.xyz + bvec * ((v0.z - clip_dist) / -bvec.z); + if (v0.z > clip_dist) { + v0.xyz = clip_pt; + } + else if (v1.z > clip_dist) { + v1.xyz = clip_pt; + } + + vec4 p0 = ProjectionMatrix * v0; + vec4 p1 = ProjectionMatrix * v1; + + float h = (is_head) ? p0.w : p1.w; + + vec2 x_screen_vec = normalize(proj(p1) - proj(p0) + 1e-8); + vec2 y_screen_vec = vec2(x_screen_vec.y, -x_screen_vec.x); + + /* 2D screen aligned pos at the point */ + vec2 vpos = pos.x * x_screen_vec + pos.y * y_screen_vec; + vpos *= (ProjectionMatrix[3][3] == 0.0) ? h : 1.0; + vpos *= (do_wire) ? 1.0 : 0.5; + + if (finalInnerColor.a > 0.0) { + float stick_size = sizePixel * 5.0; + gl_Position = (is_head) ? p0 : p1; + gl_Position.xy += stick_size * (vpos * sizeViewportInv.xy); + gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */ + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance((is_head ? boneStart_4d : boneEnd_4d).xyz); +#endif + } + else { + gl_Position = vec4(0.0); + } +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl new file mode 100644 index 00000000000..4e207b96016 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl @@ -0,0 +1,18 @@ + +in vec3 color; +in vec3 pos; + +flat out vec4 finalColor; + +void main() +{ + finalColor.rgb = color; + finalColor.a = 1.0; + + vec3 worldPosition = point_object_to_world(pos); + gl_Position = point_world_to_ndc(worldPosition); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(worldPosition); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl new file mode 100644 index 00000000000..7a3af0f3b61 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl @@ -0,0 +1,14 @@ + +in vec3 pos; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl new file mode 100644 index 00000000000..b6576ba7a21 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl @@ -0,0 +1,114 @@ + +/* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */ +#define ACTIVE_NURB 1 << 2 +#define EVEN_U_BIT 1 << 3 + +layout(lines) in; +layout(triangle_strip, max_vertices = 10) out; + +uniform bool showCurveHandles; + +flat in int vertFlag[]; + +out vec4 finalColor; + +void output_line(vec2 offset, vec4 color) +{ + finalColor = color; + + gl_Position = gl_in[0].gl_Position; + gl_Position.xy += offset * gl_in[0].gl_Position.w; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance); +#endif + EmitVertex(); + + gl_Position = gl_in[1].gl_Position; + gl_Position.xy += offset * gl_in[1].gl_Position.w; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance); +#endif + EmitVertex(); +} + +void main() +{ + vec4 v1 = gl_in[0].gl_Position; + vec4 v2 = gl_in[1].gl_Position; + + int is_active_nurb = (vertFlag[1] & ACTIVE_NURB); + int color_id = (vertFlag[1] >> 4); + + /* Don't output any edges if we don't show handles */ + if (!showCurveHandles && (color_id < 5)) { + return; + } + + bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERT_SELECTED) != 0); + + vec4 inner_color; + if (color_id == 0) { + inner_color = (edge_selected) ? colorHandleSelFree : colorHandleFree; + } + else if (color_id == 1) { + inner_color = (edge_selected) ? colorHandleSelAuto : colorHandleAuto; + } + else if (color_id == 2) { + inner_color = (edge_selected) ? colorHandleSelVect : colorHandleVect; + } + else if (color_id == 3) { + inner_color = (edge_selected) ? colorHandleSelAlign : colorHandleAlign; + } + else if (color_id == 4) { + inner_color = (edge_selected) ? colorHandleSelAutoclamp : colorHandleAutoclamp; + } + else { + bool is_selected = (((vertFlag[1] & vertFlag[0]) & VERT_SELECTED) != 0); + bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0); + if (is_u_segment) { + inner_color = (is_selected) ? colorNurbSelUline : colorNurbUline; + } + else { + inner_color = (is_selected) ? colorNurbSelVline : colorNurbVline; + } + } + + vec4 outer_color = (is_active_nurb != 0) ? + mix(colorActiveSpline, + inner_color, + 0.25) /* Minimize active color bleeding on inner_color. */ + : + vec4(inner_color.rgb, 0.0); + + vec2 v1_2 = (v2.xy / v2.w - v1.xy / v1.w); + vec2 offset = sizeEdge * 4.0 * sizeViewportInv.xy; /* 4.0 is eyeballed */ + + if (abs(v1_2.x * sizeViewport.x) < abs(v1_2.y * sizeViewport.y)) { + offset.y = 0.0; + } + else { + offset.x = 0.0; + } + + /* draw the transparent border (AA). */ + if (is_active_nurb != 0) { + offset *= 0.75; /* Don't make the active "halo" appear very thick. */ + output_line(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0)); + } + + /* draw the outline. */ + output_line(offset, outer_color); + + /* draw the core of the line. */ + output_line(vec2(0.0), inner_color); + + /* draw the outline. */ + output_line(-offset, outer_color); + + /* draw the transparent border (AA). */ + if (is_active_nurb != 0) { + output_line(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0)); + } + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl new file mode 100644 index 00000000000..a2b0d072719 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl @@ -0,0 +1,18 @@ + +in vec3 pos; +in int data; + +flat out int vertFlag; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + vertFlag = data; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl new file mode 100644 index 00000000000..aca40bba171 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl @@ -0,0 +1,29 @@ + +in vec3 pos; +in int data; + +out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + if ((data & VERT_SELECTED) != 0) { + if ((data & VERT_ACTIVE) != 0) { + finalColor = colorEditMeshActive; + } + else { + finalColor = colorVertexSelect; + } + } + else { + finalColor = colorVertex; + } + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + gl_PointSize = sizeVertex * 2.0; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl new file mode 100644 index 00000000000..5dd8e579db3 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl @@ -0,0 +1,31 @@ + +uniform float normalSize; + +in vec3 pos; +in vec3 nor; +in vec3 tan; +in float rad; + +flat out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 final_pos = pos; + + float flip = (gl_InstanceID != 0) ? -1.0 : 1.0; + + if (gl_VertexID % 2 == 0) { + final_pos += normalSize * rad * (flip * nor - tan); + } + + vec3 world_pos = point_object_to_world(final_pos); + gl_Position = point_world_to_ndc(world_pos); + + finalColor = colorWireEdit; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl new file mode 100644 index 00000000000..06d34c22ba1 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl @@ -0,0 +1,32 @@ + +in vec3 pos; +in int data; + +out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + if ((data & VERT_SELECTED) != 0) { + finalColor = colorVertexSelect; + } + else if ((data & VERT_ACTIVE) != 0) { + finalColor = colorEditMeshActive; + } + else { + finalColor = colorVertex; + } + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + /* Small offset in Z */ + gl_Position.z -= 3e-4; + + gl_PointSize = sizeVertex * 2.0; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl new file mode 100644 index 00000000000..efa6ca72feb --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl @@ -0,0 +1,38 @@ + +uniform sampler1D weightTex; + +in vec3 pos; +in float weight; + +out vec4 finalColor; + +#define no_active_weight 666.0 + +vec3 weight_to_rgb(float t) +{ + if (t == no_active_weight) { + /* No weight. */ + return colorWire.rgb; + } + if (t > 1.0 || t < 0.0) { + /* Error color */ + return vec3(1.0, 0.0, 1.0); + } + else { + return texture(weightTex, t).rgb; + } +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + finalColor = vec4(weight_to_rgb(weight), 1.0); + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl new file mode 100644 index 00000000000..8d96c0e418f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl @@ -0,0 +1,8 @@ +out vec4 fragColor; + +in vec4 weightColor; + +void main() +{ + fragColor = weightColor; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl new file mode 100644 index 00000000000..b89a3f407f9 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl @@ -0,0 +1,35 @@ + +in vec3 pos; +in float weight; + +uniform sampler1D weightTex; + +out vec4 weightColor; + +vec3 weight_to_rgb(float t) +{ + if (t < 0.0) { + /* Minimum color, grey */ + return vec3(0.25, 0.25, 0.25); + } + else if (t > 1.0) { + /* Error color */ + return vec3(1.0, 0.0, 1.0); + } + else { + return texture(weightTex, t).rgb; + } +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + weightColor = vec4(weight_to_rgb(weight), 1.0); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl new file mode 100644 index 00000000000..b79bae45f23 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl @@ -0,0 +1,76 @@ + +uniform bool selectFaces = true; +uniform bool selectEdges = true; + +vec4 EDIT_MESH_edge_color_outer(int edge_flag, int face_flag, float crease, float bweight) +{ + vec4 color = vec4(0.0); + color = ((edge_flag & EDGE_FREESTYLE) != 0) ? colorEdgeFreestyle : color; + color = ((edge_flag & EDGE_SHARP) != 0) ? colorEdgeSharp : color; + color = (crease > 0.0) ? vec4(colorEdgeCrease.rgb, crease) : color; + color = (bweight > 0.0) ? vec4(colorEdgeBWeight.rgb, bweight) : color; + color = ((edge_flag & EDGE_SEAM) != 0) ? colorEdgeSeam : color; + return color; +} + +vec4 EDIT_MESH_edge_color_inner(int edge_flag) +{ + vec4 color = colorWireEdit; + vec4 color_select = (selectEdges) ? colorEdgeSelect : mix(colorEdgeSelect, colorWireEdit, .45); + color = ((edge_flag & EDGE_SELECTED) != 0) ? color_select : color; + color = ((edge_flag & EDGE_ACTIVE) != 0) ? colorEditMeshActive : color; + + color.a = (selectEdges || (edge_flag & (EDGE_SELECTED | EDGE_ACTIVE)) != 0) ? 1.0 : 0.4; + return color; +} + +vec4 EDIT_MESH_edge_vertex_color(int vertex_flag) +{ + vec4 color = colorWireEdit; + vec4 color_select = (selectEdges) ? colorEdgeSelect : mix(colorEdgeSelect, colorWireEdit, .45); + + bool edge_selected = (vertex_flag & (VERT_ACTIVE | VERT_SELECTED)) != 0; + color = (edge_selected) ? color_select : color; + + color.a = (selectEdges || edge_selected) ? 1.0 : 0.4; + return color; +} + +vec4 EDIT_MESH_vertex_color(int vertex_flag) +{ + if ((vertex_flag & VERT_ACTIVE) != 0) { + return vec4(colorEditMeshActive.xyz, 1.0); + } + else if ((vertex_flag & VERT_SELECTED) != 0) { + return colorVertexSelect; + } + else { + return colorVertex; + } +} + +vec4 EDIT_MESH_face_color(int face_flag) +{ + vec4 color = colorFace; + vec4 color_active = mix(colorFaceSelect, colorEditMeshActive, 0.5); + color = ((face_flag & FACE_FREESTYLE) != 0) ? colorFaceFreestyle : color; + color = ((face_flag & FACE_SELECTED) != 0) ? colorFaceSelect : color; + color = ((face_flag & FACE_ACTIVE) != 0) ? color_active : color; + color.a *= ((face_flag & (FACE_FREESTYLE | FACE_SELECTED | FACE_ACTIVE)) == 0 || selectFaces) ? + 1.0 : + 0.5; + return color; +} + +vec4 EDIT_MESH_facedot_color(float facedot_flag) +{ + if (facedot_flag < 0.0f) { + return vec4(colorEditMeshActive.xyz, 1.0); + } + else if (facedot_flag > 0.0f) { + return colorFaceDot; + } + else { + return colorVertex; + } +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl new file mode 100644 index 00000000000..a8371958ec2 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl @@ -0,0 +1,7 @@ +flat in vec4 faceColor; +out vec4 FragColor; + +void main() +{ + FragColor = faceColor; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl new file mode 100644 index 00000000000..df37c6fb0bc --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl @@ -0,0 +1,23 @@ + +uniform ivec4 dataMask = ivec4(0xFF); + +in vec3 pos; +in ivec4 data; + +flat out vec4 faceColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + ivec4 data_m = data & dataMask; + + faceColor = EDIT_MESH_face_color(data_m.x); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl new file mode 100644 index 00000000000..1fe20d1cb1f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl @@ -0,0 +1,46 @@ + +#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ + +/** + * We want to know how much a pixel is covered by a line. + * We replace the square pixel with acircle of the same area and try to find the intersection area. + * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment + * The formula for the area uses inverse trig function and is quite complexe. Instead, + * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius. + */ +#define DISC_RADIUS (M_1_SQRTPI * 1.05) +#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS) +#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS) + +uniform sampler2D depthTex; +uniform float alpha = 1.0; + +flat in vec4 finalColorOuter_f; +in vec4 finalColor_f; +noperspective in float edgeCoord_f; + +out vec4 FragColor; + +bool test_occlusion() +{ + return gl_FragCoord.z > texelFetch(depthTex, ivec2(gl_FragCoord.xy), 0).r; +} + +void main() +{ + float dist = abs(edgeCoord_f) - max(sizeEdge - 0.5, 0.0); + float dist_outer = dist - max(sizeEdge, 1.0); +#ifdef USE_SMOOTH_WIRE + float mix_w = smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, dist); + float mix_w_outer = smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, dist_outer); +#else + float mix_w = step(0.5, dist); + float mix_w_outer = step(0.5, dist_outer); +#endif + /* Line color & alpha. */ + FragColor = mix(finalColorOuter_f, finalColor_f, 1.0 - mix_w * finalColorOuter_f.a); + /* Line edges shape. */ + FragColor.a *= 1.0 - (finalColorOuter_f.a > 0.0 ? mix_w_outer : mix_w); + + FragColor.a *= test_occlusion() ? alpha : 1.0; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl new file mode 100644 index 00000000000..92252bbd223 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl @@ -0,0 +1,88 @@ + +layout(lines) in; +layout(triangle_strip, max_vertices = 4) out; + +in vec4 finalColor[2]; +in vec4 finalColorOuter[2]; +in int selectOveride[2]; + +flat out vec4 finalColorOuter_f; +out vec4 finalColor_f; +noperspective out float edgeCoord_f; + +void do_vertex(vec4 color, vec4 pos, float coord, vec2 offset) +{ + finalColor_f = color; + edgeCoord_f = coord; + gl_Position = pos; + /* Multiply offset by 2 because gl_Position range is [-1..1]. */ + gl_Position.xy += offset * 2.0 * pos.w; + /* Correct but fails due to an AMD compiler bug, see: T62792. + * Do inline instead. */ +#if 0 + world_clip_planes_set_clip_distance(gl_in[i].gl_ClipDistance); +#endif + EmitVertex(); +} + +void main() +{ + vec2 ss_pos[2]; + + /* Clip line against near plane to avoid deformed lines. */ + vec4 pos0 = gl_in[0].gl_Position; + vec4 pos1 = gl_in[1].gl_Position; + vec2 pz_ndc = vec2(pos0.z / pos0.w, pos1.z / pos1.w); + bvec2 clipped = lessThan(pz_ndc, vec2(-1.0)); + if (all(clipped)) { + /* Totally clipped. */ + return; + } + + vec4 pos01 = pos0 - pos1; + float ofs = abs((pz_ndc.y + 1.0) / (pz_ndc.x - pz_ndc.y)); + if (clipped.y) { + pos1 += pos01 * ofs; + } + else if (clipped.x) { + pos0 -= pos01 * (1.0 - ofs); + } + + ss_pos[0] = pos0.xy / pos0.w; + ss_pos[1] = pos1.xy / pos1.w; + + vec2 line = ss_pos[0] - ss_pos[1]; + line = abs(line) * sizeViewport.xy; + + finalColorOuter_f = finalColorOuter[0]; + float half_size = sizeEdge; + /* Enlarge edge for flag display. */ + half_size += (finalColorOuter_f.a > 0.0) ? max(sizeEdge, 1.0) : 0.0; + +#ifdef USE_SMOOTH_WIRE + /* Add 1 px for AA */ + half_size += 0.5; +#endif + + vec3 edge_ofs = vec3(half_size * sizeViewportInv.xy, 0.0); + + bool horizontal = line.x > line.y; + edge_ofs = (horizontal) ? edge_ofs.zyz : edge_ofs.xzz; + +#ifdef USE_WORLD_CLIP_PLANES + /* Due to an AMD glitch, this line was moved out of the `do_vertex` + * function (see T62792). */ + world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance); +#endif + do_vertex(finalColor[0], pos0, half_size, edge_ofs.xy); + do_vertex(finalColor[0], pos0, -half_size, -edge_ofs.xy); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance); +#endif + vec4 final_color = (selectOveride[0] == 0) ? finalColor[1] : finalColor[0]; + do_vertex(final_color, pos1, half_size, edge_ofs.xy); + do_vertex(final_color, pos1, -half_size, -edge_ofs.xy); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl new file mode 100644 index 00000000000..2a00160836b --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl @@ -0,0 +1,53 @@ + +uniform float normalSize; +uniform sampler2D depthTex; +uniform float alpha = 1.0; + +in vec3 pos; +in vec3 lnor; +in vec3 vnor; +in vec4 norAndFlag; + +flat out vec4 finalColor; + +bool test_occlusion() +{ + vec3 ndc = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5; + return (ndc.z - 0.00035) > texture(depthTex, ndc.xy).r; +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 nor; + /* Select the right normal by cheking if the generic attrib is used. */ + if (!all(equal(lnor, vec3(0)))) { + nor = lnor; + finalColor = colorLNormal; + } + else if (!all(equal(vnor, vec3(0)))) { + nor = vnor; + finalColor = colorVNormal; + } + else { + nor = norAndFlag.xyz; + finalColor = colorNormal; + } + + vec3 n = normalize(normal_object_to_world(nor)); + + vec3 world_pos = point_object_to_world(pos); + + if (gl_VertexID == 0) { + world_pos += n * normalSize; + } + + gl_Position = point_world_to_ndc(world_pos); + + finalColor.a *= (test_occlusion()) ? alpha : 1.0; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl new file mode 100644 index 00000000000..944eb41058e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl @@ -0,0 +1,25 @@ + +/* ---- Instantiated Attrs ---- */ +in vec3 pos; + +/* ---- Per instance Attrs ---- */ +in float size; +in vec3 local_pos; + +flat out vec4 finalColor; + +void main() +{ + mat3 imat = mat3(ModelMatrixInverse); + vec3 right = normalize(imat * screenVecs[0].xyz); + vec3 up = normalize(imat * screenVecs[1].xyz); + vec3 screen_pos = (right * pos.x + up * pos.z) * size; + vec4 pos_4d = ModelMatrix * vec4(local_pos + screen_pos, 1.0); + gl_Position = ViewProjectionMatrix * pos_4d; + /* Manual stipple: one segment out of 2 is transparent. */ + finalColor = ((gl_VertexID & 1) == 0) ? colorSkinRoot : vec4(0.0); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(pos_4d.xyz); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl new file mode 100644 index 00000000000..8759ef80888 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl @@ -0,0 +1,97 @@ + +uniform sampler2D depthTex; +uniform float alpha = 1.0; +uniform ivec4 dataMask = ivec4(0xFF); + +in ivec4 data; +in vec3 pos; +#ifndef FACEDOT +in vec3 vnor; +#else +in vec4 norAndFlag; +# define vnor norAndFlag.xyz +#endif + +out vec4 finalColor; +#ifdef EDGE +out vec4 finalColorOuter; +#endif +#ifdef USE_GEOM_SHADER +out int selectOveride; +#endif + +bool test_occlusion() +{ + vec3 ndc = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5; + return ndc.z > texture(depthTex, ndc.xy).r; +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + ivec4 m_data = data & dataMask; + +#if defined(VERT) + finalColor = EDIT_MESH_vertex_color(m_data.y); + gl_PointSize = sizeVertex * 2.0; + /* Make selected and active vertex always on top. */ + if ((data.x & VERT_SELECTED) != 0) { + gl_Position.z -= 1e-7; + } + if ((data.x & VERT_ACTIVE) != 0) { + gl_Position.z -= 1e-7; + } + + bool occluded = test_occlusion(); + +#elif defined(EDGE) +# ifdef FLAT + finalColor = EDIT_MESH_edge_color_inner(m_data.y); + selectOveride = 1; +# else + finalColor = EDIT_MESH_edge_vertex_color(m_data.y); + selectOveride = (m_data.y & EDGE_SELECTED); +# endif + + float crease = float(m_data.z) / 255.0; + float bweight = float(m_data.w) / 255.0; + finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight); + + bool occluded = false; /* Done in fragment shader */ + +#elif defined(FACE) + finalColor = EDIT_MESH_face_color(m_data.x); + bool occluded = true; + +#elif defined(FACEDOT) + finalColor = EDIT_MESH_facedot_color(norAndFlag.w); + + /* Bias Facedot Z position in clipspace. */ + gl_Position.z -= 0.00035; + gl_PointSize = sizeFaceDot; + + bool occluded = test_occlusion(); + +#endif + + finalColor.a *= (occluded) ? alpha : 1.0; + +#if !defined(FACE) + /* Facing based color blend */ + vec3 vpos = point_world_to_view(world_pos); + vec3 view_normal = normalize(normal_object_to_view(vnor) + 1e-4); + vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) ? normalize(vpos) : vec3(0.0, 0.0, 1.0); + float facing = dot(view_vec, view_normal); + facing = 1.0 - abs(facing) * 0.2; + + finalColor.rgb = mix(colorEditMeshMiddle.rgb, finalColor.rgb, facing); +#endif + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl new file mode 100644 index 00000000000..86d5547225c --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl @@ -0,0 +1,19 @@ + +in vec3 pos; +in float color; + +out vec4 finalColor; + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + finalColor = mix(colorWire, colorEdgeSelect, color); + + gl_PointSize = sizeVertex * 2.0; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl new file mode 100644 index 00000000000..1dde94f751c --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl @@ -0,0 +1,42 @@ + +uniform sampler1D weightTex; +uniform bool useWeight; + +in vec3 pos; +in float color; + +out vec4 finalColor; + +#define no_active_weight 666.0 + +vec3 weight_to_rgb(float t) +{ + if (t == no_active_weight) { + /* No weight. */ + return colorWire.rgb; + } + if (t > 1.0 || t < 0.0) { + /* Error color */ + return vec3(1.0, 0.0, 1.0); + } + else { + return texture(weightTex, t).rgb; + } +} + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + if (useWeight) { + finalColor = vec4(weight_to_rgb(color), 1.0); + } + else { + finalColor = mix(colorWire, colorEdgeSelect, color); + } + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl new file mode 100644 index 00000000000..8a8ae8a9611 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl @@ -0,0 +1,13 @@ + +noperspective in vec2 edgePos; +flat in vec2 edgeStart; +flat in vec4 finalColor; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; + +void main() +{ + fragColor = finalColor; + lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl new file mode 100644 index 00000000000..4b08ea587d4 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl @@ -0,0 +1,30 @@ + +in vec3 pos; + +/* Instance */ +in vec3 inst_pos; + +flat out vec4 finalColor; +flat out vec2 edgeStart; +noperspective out vec2 edgePos; + +void main() +{ + finalColor = colorLight; + + /* Relative to DPI scalling. Have constant screen size. */ + vec3 screen_pos = screenVecs[0].xyz * pos.x + screenVecs[1].xyz * pos.y; + vec3 p = inst_pos; + p.z *= (pos.z == 0.0) ? 0.0 : 1.0; + float screen_size = mul_project_m4_v3_zfac(p) * sizePixel; + vec3 world_pos = p + screen_pos * screen_size; + + gl_Position = point_world_to_ndc(world_pos); + + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl new file mode 100644 index 00000000000..8784b6cd73a --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl @@ -0,0 +1,18 @@ + +in vec4 finalColor; + +out vec4 fragColor; + +void main() +{ + vec2 centered = abs(gl_PointCoord - vec2(0.5)); + float dist = max(centered.x, centered.y); + + float fac = dist * dist * 4.0; + fragColor = mix(colorEditMeshMiddle, finalColor, 0.45 + fac * 0.65); + + /* Make the effect more like a fresnel by offsetting + * the depth and creating mini-spheres. + * Disabled as it has performance impact. */ + // gl_FragDepth = gl_FragCoord.z + 1e-6 * fac; +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl new file mode 100644 index 00000000000..76a2678a50e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl @@ -0,0 +1,20 @@ + +in vec3 pos; + +out vec4 finalColor; + +void main() +{ + /* Extract data packed inside the unused mat4 members. */ + mat4 obmat = ModelMatrix; + finalColor = vec4(obmat[0][3], obmat[1][3], obmat[2][3], obmat[3][3]); + + vec3 world_pos = (ModelMatrix * vec4(pos, 1.0)).xyz; + gl_Position = point_world_to_ndc(world_pos); + + gl_PointSize = sizeVertex * 2.0; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl new file mode 100644 index 00000000000..14c03248981 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl @@ -0,0 +1,30 @@ + +uniform vec4 color; + +in vec3 pos; + +out vec4 radii; +out vec4 fillColor; +out vec4 outlineColor; + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + gl_PointSize = sizeObjectCenter; + float radius = 0.5 * sizeObjectCenter; + float outline_width = sizePixel; + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outline_width; + radii[3] = radius - outline_width - 1.0; + radii /= sizeObjectCenter; + + fillColor = color; + outlineColor = colorOutline; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl new file mode 100644 index 00000000000..a72c5adb691 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl @@ -0,0 +1,227 @@ + +in vec3 pos; +in int vclass; + +/* Instance */ +in mat4 inst_obmat; +in vec4 color; + +#define lamp_area_size inst_data.xy +#define lamp_clip_sta inst_data.z +#define lamp_clip_end inst_data.w + +#define lamp_spot_cosine inst_data.x +#define lamp_spot_blend inst_data.y + +#define camera_corner inst_data.xy +#define camera_center inst_data.zw +#define camera_dist inst_color_data +#define camera_dist_sta inst_data.z +#define camera_dist_end inst_data.w +#define camera_distance_color inst_data.x + +#define empty_size inst_data.xyz +#define empty_scale inst_data.w + +#define VCLASS_LIGHT_AREA_SHAPE (1 << 0) +#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1) +#define VCLASS_LIGHT_SPOT_BLEND (1 << 2) +#define VCLASS_LIGHT_SPOT_CONE (1 << 3) +#define VCLASS_LIGHT_DIST (1 << 4) + +#define VCLASS_CAMERA_FRAME (1 << 5) +#define VCLASS_CAMERA_DIST (1 << 6) +#define VCLASS_CAMERA_VOLUME (1 << 7) + +#define VCLASS_SCREENSPACE (1 << 8) +#define VCLASS_SCREENALIGNED (1 << 9) + +#define VCLASS_EMPTY_SCALED (1 << 10) +#define VCLASS_EMPTY_AXES (1 << 11) +#define VCLASS_EMPTY_AXES_NAME (1 << 12) +#define VCLASS_EMPTY_AXES_SHADOW (1 << 13) +#define VCLASS_EMPTY_SIZE (1 << 14) + +flat out vec4 finalColor; +flat out vec2 edgeStart; +noperspective out vec2 edgePos; + +void main() +{ + /* Extract data packed inside the unused mat4 members. */ + vec4 inst_data = vec4(inst_obmat[0][3], inst_obmat[1][3], inst_obmat[2][3], inst_obmat[3][3]); + float inst_color_data = color.a; + mat4 obmat = inst_obmat; + obmat[0][3] = obmat[1][3] = obmat[2][3] = 0.0; + obmat[3][3] = 1.0; + + finalColor = color; + if (color.a < 0.0) { + finalColor.a = 1.0; + } + + float lamp_spot_sine; + vec3 vpos = pos; + vec3 vofs = vec3(0.0); + /* Lights */ + if ((vclass & VCLASS_LIGHT_AREA_SHAPE) != 0) { + /* HACK: use alpha color for spots to pass the area_size. */ + if (inst_color_data < 0.0) { + lamp_area_size.xy = vec2(-inst_color_data); + } + vpos.xy *= lamp_area_size.xy; + } + else if ((vclass & VCLASS_LIGHT_SPOT_SHAPE) != 0) { + lamp_spot_sine = sqrt(1.0 - lamp_spot_cosine * lamp_spot_cosine); + lamp_spot_sine *= ((vclass & VCLASS_LIGHT_SPOT_BLEND) != 0) ? lamp_spot_blend : 1.0; + vpos = vec3(pos.xy * lamp_spot_sine, -lamp_spot_cosine); + } + else if ((vclass & VCLASS_LIGHT_DIST) != 0) { + /* Meh nasty mess. Select one of the 6 axes to display on. (see light_distance_z_get()) */ + int dist_axis = int(pos.z); + float dist = pos.z - floor(pos.z) - 0.5; + float inv = sign(dist); + dist = (abs(dist) > 0.15) ? lamp_clip_end : lamp_clip_sta; + vofs[dist_axis] = inv * dist / length(obmat[dist_axis].xyz); + vpos.z = 0.0; + if (lamp_clip_end < 0.0) { + vpos = vofs = vec3(0.0); + } + } + /* Camera */ + else if ((vclass & VCLASS_CAMERA_FRAME) != 0) { + if ((vclass & VCLASS_CAMERA_VOLUME) != 0) { + vpos.z = mix(color.b, color.a, pos.z); + } + else if (camera_dist > 0.0) { + vpos.z = -abs(camera_dist); + } + else { + vpos.z *= -abs(camera_dist); + } + vpos.xy = (camera_center + camera_corner * vpos.xy) * abs(vpos.z); + } + else if ((vclass & VCLASS_CAMERA_DIST) != 0) { + vofs.xy = vec2(0.0); + vofs.z = -mix(camera_dist_sta, camera_dist_end, pos.z); + vpos.z = 0.0; + /* Distance line endpoints color */ + if (any(notEqual(pos.xy, vec2(0.0)))) { + /* Override color. */ + switch (int(camera_distance_color)) { + case 0: /* Mist */ + finalColor = vec4(0.5, 0.5, 0.5, 1.0); + break; + case 1: /* Mist Active */ + finalColor = vec4(1.0, 1.0, 1.0, 1.0); + break; + case 2: /* Clip */ + finalColor = vec4(0.5, 0.5, 0.25, 1.0); + break; + case 3: /* Clip Active */ + finalColor = vec4(1.0, 1.0, 0.5, 1.0); + break; + } + } + /* Focus cross */ + if (pos.z == 2.0) { + vofs.z = 0.0; + if (camera_dist < 0.0) { + vpos.z = -abs(camera_dist); + } + else { + /* Disabled */ + vpos = vec3(0.0); + } + } + } + /* Empties */ + else if ((vclass & VCLASS_EMPTY_SCALED) != 0) { + /* This is a bit silly but we avoid scalling the object matrix on CPU (saving a mat4 mul) */ + vpos *= empty_scale; + } + else if ((vclass & VCLASS_EMPTY_SIZE) != 0) { + /* This is a bit silly but we avoid scalling the object matrix on CPU (saving a mat4 mul) */ + vpos *= empty_size; + } + else if ((vclass & VCLASS_EMPTY_AXES) != 0) { + float axis = vpos.z; + vofs[int(axis)] = (1.0 + fract(axis)) * empty_scale; + /* Scale uniformly by axis length */ + vpos *= length(obmat[int(axis)].xyz) * empty_scale; + + vec3 axis_color = vec3(0.0); + axis_color[int(axis)] = 1.0; + finalColor.rgb = mix(axis_color + fract(axis), color.rgb, color.a); + finalColor.a = 1.0; + } + + /* Not exclusive with previous flags. */ + if ((vclass & VCLASS_CAMERA_VOLUME) != 0) { + /* Unpack final color. */ + int color_class = int(floor(color.r)); + float color_intensity = fract(color.r); + switch (color_class) { + case 0: /* No eye (convergence plane) */ + finalColor = vec4(1.0, 1.0, 1.0, 1.0); + break; + case 1: /* Left eye */ + finalColor = vec4(0.0, 1.0, 1.0, 1.0); + break; + case 2: /* Right eye */ + finalColor = vec4(1.0, 0.0, 0.0, 1.0); + break; + } + finalColor *= vec4(vec3(color_intensity), color.g); + } + + vec3 world_pos; + if ((vclass & VCLASS_SCREENSPACE) != 0) { + /* Relative to DPI scalling. Have constant screen size. */ + vec3 screen_pos = screenVecs[0].xyz * vpos.x + screenVecs[1].xyz * vpos.y; + vec3 p = (obmat * vec4(vofs, 1.0)).xyz; + float screen_size = mul_project_m4_v3_zfac(p) * sizePixel; + world_pos = p + screen_pos * screen_size; + } + else if ((vclass & VCLASS_SCREENALIGNED) != 0) { + /* World sized, camera facing geometry. */ + vec3 screen_pos = screenVecs[0].xyz * vpos.x + screenVecs[1].xyz * vpos.y; + world_pos = (obmat * vec4(vofs, 1.0)).xyz + screen_pos; + } + else { + world_pos = (obmat * vec4(vofs + vpos, 1.0)).xyz; + } + + if ((vclass & VCLASS_LIGHT_SPOT_CONE) != 0) { + /* Compute point on the cone before and after this one. */ + vec2 perp = vec2(pos.y, -pos.x); + const float incr_angle = 2.0 * 3.1415 / 32.0; + const vec2 slope = vec2(cos(incr_angle), sin(incr_angle)); + vec3 p0 = vec3((pos.xy * slope.x + perp * slope.y) * lamp_spot_sine, -lamp_spot_cosine); + vec3 p1 = vec3((pos.xy * slope.x - perp * slope.y) * lamp_spot_sine, -lamp_spot_cosine); + p0 = (obmat * vec4(p0, 1.0)).xyz; + p1 = (obmat * vec4(p1, 1.0)).xyz; + /* Compute normals of each side. */ + vec3 edge = obmat[3].xyz - world_pos; + vec3 n0 = normalize(cross(edge, p0 - world_pos)); + vec3 n1 = normalize(cross(edge, world_pos - p1)); + bool persp = (ProjectionMatrix[3][3] == 0.0); + vec3 V = (persp) ? normalize(ViewMatrixInverse[3].xyz - world_pos) : ViewMatrixInverse[2].xyz; + /* Discard non-silhouete edges. */ + bool facing0 = dot(n0, V) > 0.0; + bool facing1 = dot(n1, V) > 0.0; + if (facing0 == facing1) { + /* Hide line by making it cover 0 pixels. */ + world_pos = obmat[3].xyz; + } + } + + gl_Position = point_world_to_ndc(world_pos); + + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl new file mode 100644 index 00000000000..7e469aee18d --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl @@ -0,0 +1,31 @@ + +noperspective in vec2 stipple_coord; +flat in vec2 stipple_start; +flat in vec4 finalColor; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; + +void main() +{ + fragColor = finalColor; + + /* Stipple */ + const float dash_width = 6.0; + const float dash_factor = 0.5; + + lineOutput = pack_line_data(gl_FragCoord.xy, stipple_start, stipple_coord); + + float dist = distance(stipple_start, stipple_coord); + + if (fragColor.a == 0.0) { + /* Disable stippling. */ + dist = 0.0; + } + + fragColor.a = 1.0; + + if (fract(dist / dash_width) > dash_factor) { + discard; + } +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl new file mode 100644 index 00000000000..933b9d65a5f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl @@ -0,0 +1,40 @@ + +in vec3 pos; +in vec4 color; +in int colorid; /* if equal 0 (i.e: Not specified) use color attrib and stippling. */ + +noperspective out vec2 stipple_coord; +flat out vec2 stipple_start; +flat out vec4 finalColor; + +vec2 screen_position(vec4 p) +{ + return ((p.xy / p.w) * 0.5 + 0.5) * sizeViewport.xy; +} + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + stipple_coord = stipple_start = screen_position(gl_Position); + +#ifdef OBJECT_WIRE + /* Extract data packed inside the unused mat4 members. */ + finalColor = vec4(ModelMatrix[0][3], ModelMatrix[1][3], ModelMatrix[2][3], ModelMatrix[3][3]); +#else + + if (colorid == TH_CAMERA_PATH) { + finalColor = colorCameraPath; + finalColor.a = 0.0; /* No Stipple */ + } + else { + finalColor = color; + finalColor.a = 1.0; /* Stipple */ + } +#endif + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/facing_frag.glsl new file mode 100644 index 00000000000..1ed35b4a421 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/facing_frag.glsl @@ -0,0 +1,9 @@ +uniform vec3 color_towards = vec3(0.0, 0.0, 1.0); +uniform vec3 color_outwards = vec3(1.0, 0.0, 0.0); + +out vec4 fragColor; + +void main() +{ + fragColor = vec4(gl_FrontFacing ? color_towards : color_outwards, 0.7); +} diff --git a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl b/source/blender/draw/engines/overlay/shaders/facing_vert.glsl new file mode 100644 index 00000000000..2dd84c0a060 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/facing_vert.glsl @@ -0,0 +1,12 @@ + +in vec3 pos; + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl new file mode 100644 index 00000000000..db845c7f1dd --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl @@ -0,0 +1,248 @@ + +/* Infinite grid + * Author: Clément Foucault */ + +/* We use the normalized local position to avoid precision + * loss during interpolation. */ +in vec3 local_pos; + +out vec4 FragColor; + +uniform vec3 planeAxes; +uniform float gridDistance; +uniform float meshSize; +uniform float lineKernel = 0.0; +uniform sampler2D depthBuffer; + +#define cameraPos (ViewMatrixInverse[3].xyz) + +uniform int gridFlag; + +#define STEPS_LEN 8 +uniform float gridSteps[STEPS_LEN] = float[](0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0, 10000.0); + +#define AXIS_X (1 << 0) +#define AXIS_Y (1 << 1) +#define AXIS_Z (1 << 2) +#define GRID (1 << 3) +#define PLANE_XY (1 << 4) +#define PLANE_XZ (1 << 5) +#define PLANE_YZ (1 << 6) +#define GRID_BACK (1 << 9) /* grid is behind objects */ + +#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ + +/** + * We want to know how much a pixel is covered by a line. + * We replace the square pixel with acircle of the same area and try to find the intersection area. + * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment + * The formula for the area uses inverse trig function and is quite complexe. Instead, + * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius. + */ +#define DISC_RADIUS (M_1_SQRTPI * 1.05) +#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS) +#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS) + +float get_grid(vec2 co, vec2 fwidthCos, float grid_size) +{ + float half_size = grid_size / 2.0; + /* triangular wave pattern, amplitude is [0, half_size] */ + vec2 grid_domain = abs(mod(co + half_size, grid_size) - half_size); + /* modulate by the absolute rate of change of the coordinates + * (make lines have the same width under perspective) */ + grid_domain /= fwidthCos; + + /* collapse waves */ + float line_dist = min(grid_domain.x, grid_domain.y); + + return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, line_dist - lineKernel); +} + +vec3 get_axes(vec3 co, vec3 fwidthCos, float line_size) +{ + vec3 axes_domain = abs(co); + /* modulate by the absolute rate of change of the coordinates + * (make line have the same width under perspective) */ + axes_domain /= fwidthCos; + + return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, + GRID_LINE_SMOOTH_END, + axes_domain - (line_size + lineKernel)); +} + +#define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0)) + +void main() +{ + vec3 wPos = local_pos * meshSize; + vec3 dFdxPos = dFdx(wPos); + vec3 dFdyPos = dFdy(wPos); + vec3 fwidthPos = abs(dFdxPos) + abs(dFdyPos); + wPos += cameraPos * planeAxes; + + float dist, fade; + /* if persp */ + if (ProjectionMatrix[3][3] == 0.0) { + vec3 viewvec = cameraPos - wPos; + dist = length(viewvec); + viewvec /= dist; + + float angle; + if ((gridFlag & PLANE_XZ) != 0) { + angle = viewvec.y; + } + else if ((gridFlag & PLANE_YZ) != 0) { + angle = viewvec.x; + } + else { + angle = viewvec.z; + } + + angle = 1.0 - abs(angle); + angle *= angle; + fade = 1.0 - angle * angle; + fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance); + } + else { + dist = abs(gl_FragCoord.z * 2.0 - 1.0); + fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5); + dist = 1.0; /* avoid branch after */ + + if ((gridFlag & PLANE_XY) != 0) { + float angle = 1.0 - abs(ViewMatrixInverse[2].z); + dist = 1.0 + angle * 2.0; + angle *= angle; + fade *= 1.0 - angle * angle; + } + } + + if ((gridFlag & GRID) != 0) { + /* Using `max(dot(dFdxPos, screenVecs[0]), dot(dFdyPos, screenVecs[1]))` + * would be more accurate, but not really necessary. */ + float grid_res = dot(dFdxPos, screenVecs[0].xyz); + + /* The gride begins to appear when it comprises 4 pixels */ + grid_res *= 4; + + /* from biggest to smallest */ + vec4 scale; +#if 0 + int step_id = 0; + scale[0] = 0.0; + scale[1] = gridSteps[0]; + while (scale[1] < grid_res && step_id != STEPS_LEN - 1) { + scale[0] = scale[1]; + scale[1] = gridSteps[++step_id]; + } + scale[2] = gridSteps[min(step_id + 1, STEPS_LEN - 1)]; + scale[3] = gridSteps[min(step_id + 2, STEPS_LEN - 1)]; +#else + /* For more efficiency, unroll the loop above. */ + if (gridSteps[0] > grid_res) { + scale = vec4(0.0, gridSteps[0], gridSteps[1], gridSteps[2]); + } + else if (gridSteps[1] > grid_res) { + scale = vec4(gridSteps[0], gridSteps[1], gridSteps[2], gridSteps[3]); + } + else if (gridSteps[2] > grid_res) { + scale = vec4(gridSteps[1], gridSteps[2], gridSteps[3], gridSteps[4]); + } + else if (gridSteps[3] > grid_res) { + scale = vec4(gridSteps[2], gridSteps[3], gridSteps[4], gridSteps[5]); + } + else if (gridSteps[4] > grid_res) { + scale = vec4(gridSteps[3], gridSteps[4], gridSteps[5], gridSteps[6]); + } + else if (gridSteps[5] > grid_res) { + scale = vec4(gridSteps[4], gridSteps[5], gridSteps[6], gridSteps[7]); + } + else if (gridSteps[6] > grid_res) { + scale = vec4(gridSteps[5], gridSteps[6], gridSteps[7], gridSteps[7]); + } + else { + scale = vec4(gridSteps[6], gridSteps[7], gridSteps[7], gridSteps[7]); + } +#endif + float blend = 1.0 - linearstep(scale[0], scale[1], grid_res); + blend = blend * blend * blend; + + vec2 grid_pos, grid_fwidth; + if ((gridFlag & PLANE_XZ) != 0) { + grid_pos = wPos.xz; + grid_fwidth = fwidthPos.xz; + } + else if ((gridFlag & PLANE_YZ) != 0) { + grid_pos = wPos.yz; + grid_fwidth = fwidthPos.yz; + } + else { + grid_pos = wPos.xy; + grid_fwidth = fwidthPos.xy; + } + + float gridA = get_grid(grid_pos, grid_fwidth, scale[1]); + float gridB = get_grid(grid_pos, grid_fwidth, scale[2]); + float gridC = get_grid(grid_pos, grid_fwidth, scale[3]); + + FragColor = colorGrid; + FragColor.a *= gridA * blend; + FragColor = mix(FragColor, mix(colorGrid, colorGridEmphasise, blend), gridB); + FragColor = mix(FragColor, colorGridEmphasise, gridC); + } + else { + FragColor = vec4(colorGrid.rgb, 0.0); + } + + if ((gridFlag & (AXIS_X | AXIS_Y | AXIS_Z)) != 0) { + /* Setup axes 'domains' */ + vec3 axes_dist, axes_fwidth; + + if ((gridFlag & AXIS_X) != 0) { + axes_dist.x = dot(wPos.yz, planeAxes.yz); + axes_fwidth.x = dot(fwidthPos.yz, planeAxes.yz); + } + if ((gridFlag & AXIS_Y) != 0) { + axes_dist.y = dot(wPos.xz, planeAxes.xz); + axes_fwidth.y = dot(fwidthPos.xz, planeAxes.xz); + } + if ((gridFlag & AXIS_Z) != 0) { + axes_dist.z = dot(wPos.xy, planeAxes.xy); + axes_fwidth.z = dot(fwidthPos.xy, planeAxes.xy); + } + + /* Computing all axes at once using vec3 */ + vec3 axes = get_axes(axes_dist, axes_fwidth, 0.1); + + if ((gridFlag & AXIS_X) != 0) { + FragColor.a = max(FragColor.a, axes.x); + FragColor.rgb = (axes.x < 1e-8) ? FragColor.rgb : colorGridAxisX.rgb; + } + if ((gridFlag & AXIS_Y) != 0) { + FragColor.a = max(FragColor.a, axes.y); + FragColor.rgb = (axes.y < 1e-8) ? FragColor.rgb : colorGridAxisY.rgb; + } + if ((gridFlag & AXIS_Z) != 0) { + FragColor.a = max(FragColor.a, axes.z); + FragColor.rgb = (axes.z < 1e-8) ? FragColor.rgb : colorGridAxisZ.rgb; + } + } + + /* Add a small bias so the grid will always + * be on top of a mesh with the same depth. */ + float grid_depth = gl_FragCoord.z - 6e-8 - fwidth(gl_FragCoord.z); + float scene_depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; + if ((gridFlag & GRID_BACK) != 0) { + fade *= (scene_depth == 1.0) ? 1.0 : 0.0; + } + else { + /* Manual, non hard, depth test: + * Progressively fade the grid below occluders + * (avoids popping visuals due to depth buffer precision) */ + /* Harder settings tend to flicker more, + * but have less "see through" appearance. */ + const float test_hardness = 1e7; + fade *= 1.0 - clamp((grid_depth - scene_depth) * test_hardness, 0.0, 1.0); + } + + FragColor.a *= fade; +} diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl new file mode 100644 index 00000000000..496bb011c74 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl @@ -0,0 +1,52 @@ + +/* Infinite grid + * Clément Foucault */ + +uniform vec3 planeAxes; +uniform float meshSize; + +uniform int gridFlag; + +#define cameraPos (ViewMatrixInverse[3].xyz) + +#define PLANE_XY (1 << 4) +#define PLANE_XZ (1 << 5) +#define PLANE_YZ (1 << 6) +#define CLIP_Z_POS (1 << 7) +#define CLIP_Z_NEG (1 << 8) + +in vec3 pos; + +out vec3 local_pos; + +void main() +{ + vec3 vert_pos; + + /* Project camera pos to the needed plane */ + if ((gridFlag & PLANE_XY) != 0) { + vert_pos = vec3(pos.x, pos.y, 0.0); + } + else if ((gridFlag & PLANE_XZ) != 0) { + vert_pos = vec3(pos.x, 0.0, pos.y); + } + else { + vert_pos = vec3(0.0, pos.x, pos.y); + } + + local_pos = vert_pos; + + vec3 real_pos = cameraPos * planeAxes + vert_pos * meshSize; + + /* Used for additional Z axis */ + if ((gridFlag & CLIP_Z_POS) != 0) { + real_pos.z = clamp(real_pos.z, 0.0, 1e30); + local_pos.z = clamp(local_pos.z, 0.0, 1.0); + } + if ((gridFlag & CLIP_Z_NEG) != 0) { + real_pos.z = clamp(real_pos.z, -1e30, 0.0); + local_pos.z = clamp(local_pos.z, -1.0, 0.0); + } + + gl_Position = ViewProjectionMatrix * vec4(real_pos, 1.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/image_frag.glsl new file mode 100644 index 00000000000..0da7067851d --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/image_frag.glsl @@ -0,0 +1,34 @@ + +uniform sampler2D imgTexture; +uniform bool imgPremultiplied; +uniform bool imgAlphaBlend; +uniform bool imgLinear; +uniform vec4 color; + +in vec2 uvs; + +out vec4 fragColor; + +void main() +{ + vec2 uvs_clamped = clamp(uvs, 0.0, 1.0); + vec4 tex_color; + if (imgLinear) { + tex_color = texture_read_as_linearrgb(imgTexture, imgPremultiplied, uvs_clamped); + } + else { + tex_color = texture_read_as_srgb(imgTexture, imgPremultiplied, uvs_clamped); + } + fragColor = tex_color * color; + + if (!imgAlphaBlend) { + /* Arbitrary discard anything below 5% opacity. + * Note that this could be exposed to the User. */ + if (tex_color.a < 0.05) { + discard; + } + else { + fragColor.a = 1.0; + } + } +} diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/image_vert.glsl new file mode 100644 index 00000000000..621e1d8068b --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/image_vert.glsl @@ -0,0 +1,21 @@ + +uniform bool depthSet; + +in vec3 pos; + +out vec2 uvs; + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + if (depthSet) { + /* Result in a position at 1.0 (far plane). Small epsilon to avoid precision issue. + * This mimics the effect of infinite projection matrix + * (see http://www.terathon.com/gdc07_lengyel.pdf). */ + gl_Position.z = gl_Position.w - 2.4e-7; + } + + uvs = pos.xy * 0.5 + 0.5; +} diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl new file mode 100644 index 00000000000..95e5b08049e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl @@ -0,0 +1,47 @@ + +layout(lines) in; +layout(triangle_strip, max_vertices = 4) out; + +uniform int lineThickness = 2; + +in vec4 finalColor_geom[]; +in vec2 ssPos[]; + +out vec4 finalColor; + +vec2 compute_dir(vec2 v0, vec2 v1) +{ + vec2 dir = normalize(v1 - v0 + 1e-8); + dir = vec2(-dir.y, dir.x); + return dir; +} + +void main(void) +{ + vec2 t; + vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) * sizeViewportInv.xy; + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float line_size = float(lineThickness) * sizePixel; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance); +#endif + finalColor = finalColor_geom[0]; + t = edge_dir * (line_size * (is_persp ? gl_in[0].gl_Position.w : 1.0)); + gl_Position = gl_in[0].gl_Position + vec4(t, 0.0, 0.0); + EmitVertex(); + gl_Position = gl_in[0].gl_Position - vec4(t, 0.0, 0.0); + EmitVertex(); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance); +#endif + finalColor = finalColor_geom[1]; + t = edge_dir * (line_size * (is_persp ? gl_in[1].gl_Position.w : 1.0)); + gl_Position = gl_in[1].gl_Position + vec4(t, 0.0, 0.0); + EmitVertex(); + gl_Position = gl_in[1].gl_Position - vec4(t, 0.0, 0.0); + EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl new file mode 100644 index 00000000000..6d7f673731e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl @@ -0,0 +1,96 @@ + +uniform ivec4 mpathLineSettings; +uniform bool selected; +uniform vec3 customColor; + +#define frameCurrent mpathLineSettings.x +#define frameStart mpathLineSettings.y +#define frameEnd mpathLineSettings.z +#define cacheStart mpathLineSettings.w + +in vec3 pos; + +out vec2 ssPos; +out vec4 finalColor_geom; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy; +} + +#define SET_INTENSITY(A, B, C, min, max) \ + (((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min) + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + + ssPos = proj(gl_Position); + + int frame = gl_VertexID + cacheStart; + + float intensity; /* how faint */ + + vec3 blend_base = (abs(frame - frameCurrent) == 1) ? + colorCurrentFrame.rgb : + colorBackground.rgb; /* "bleed" cframe color to ease color blending */ + bool use_custom_color = customColor.x >= 0.0; + /* TODO: We might want something more consistent with custom color and standard colors. */ + if (frame < frameCurrent) { + if (use_custom_color) { + /* Custom color: previous frames color is darker than current frame */ + finalColor_geom.rgb = customColor * 0.25; + } + else { + /* black - before frameCurrent */ + if (selected) { + intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75); + } + else { + intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92); + } + finalColor_geom.rgb = mix(colorWire.rgb, blend_base, intensity); + } + } + else if (frame > frameCurrent) { + if (use_custom_color) { + /* Custom color: next frames color is equal to user selected color */ + finalColor_geom.rgb = customColor; + } + else { + /* blue - after frameCurrent */ + if (selected) { + intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75); + } + else { + intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92); + } + + finalColor_geom.rgb = mix(colorBonePose.rgb, blend_base, intensity); + } + } + else { + if (use_custom_color) { + /* Custom color: current frame color is slightly darker than user selected color */ + finalColor_geom.rgb = customColor * 0.5; + } + else { + /* green - on frameCurrent */ + if (selected) { + intensity = 0.5f; + } + else { + intensity = 0.99f; + } + finalColor_geom.rgb = clamp( + mix(colorCurrentFrame.rgb, colorBackground.rgb, intensity) - 0.1, 0.0, 0.1); + } + } + + finalColor_geom.a = 1.0; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl new file mode 100644 index 00000000000..14335eb1b99 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl @@ -0,0 +1,58 @@ + +uniform ivec4 mpathPointSettings; +uniform bool showKeyFrames = true; +uniform vec3 customColor; + +#define pointSize mpathPointSettings.x +#define frameCurrent mpathPointSettings.y +#define cacheStart mpathPointSettings.z +#define stepSize mpathPointSettings.w + +in vec3 pos; +in int flag; + +#define MOTIONPATH_VERT_SEL (1 << 0) +#define MOTIONPATH_VERT_KEY (1 << 1) + +out vec4 finalColor; + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = float(pointSize + 2); + + int frame = gl_VertexID + cacheStart; + bool use_custom_color = customColor.x >= 0.0; + finalColor = (use_custom_color) ? vec4(customColor, 1.0) : vec4(1.0); + + /* Bias to reduce z fighting with the path */ + gl_Position.z -= 1e-4; + + if (gl_VertexID % stepSize == 0) { + gl_PointSize = float(pointSize) + 4; + } + + if (showKeyFrames) { + if ((flag & MOTIONPATH_VERT_KEY) != 0) { + gl_PointSize = float(pointSize + 5); + finalColor = colorVertexSelect; + /* Bias more to get these on top of regular points */ + gl_Position.z -= 1e-4; + } + /* Draw big green dot where the current frame is. + * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter + */ + if (frame == frameCurrent) { + gl_PointSize = float(pointSize + 8); + finalColor = colorCurrentFrame; + /* Bias more to get these on top of keyframes */ + gl_Position.z -= 1e-4; + } + } + + gl_PointSize *= sizePixel; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl new file mode 100644 index 00000000000..79c970adfe0 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl @@ -0,0 +1,86 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform usampler2D outlineId; +uniform sampler2D outlineDepth; +uniform sampler2D sceneDepth; + +uniform float alphaOcclu; + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + +#ifdef GPU_ARB_texture_gather + vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy); + vec2 uv = ceil(gl_FragCoord.xy) * texel_size; + + /* Samples order is CW starting from top left. */ + uvec4 tmp1 = textureGather(outlineId, uv - texel_size); + uvec4 tmp2 = textureGather(outlineId, uv); + + uint ref_id = tmp1.y; + uvec4 id = uvec4(tmp1.xz, tmp2.xz); +#else + uvec4 id; + uint ref_id = texelFetch(outlineId, texel, 0).r; + id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r; + id.y = texelFetchOffset(outlineId, texel, 0, ivec2(0, -1)).r; + id.z = texelFetchOffset(outlineId, texel, 0, ivec2(0, 1)).r; + id.w = texelFetchOffset(outlineId, texel, 0, ivec2(1, 0)).r; +#endif + +#ifdef WIRE + /* We want only 2px outlines. */ + /* TODO optimize, don't sample if we don't need to. */ + id.xy = uvec2(ref_id); +#endif + + bool outline = any(notEqual(id, uvec4(ref_id))); + + ivec2 depth_texel = texel; + /* If texel is an outline but has no valid id ... + * replace id and depth texel by a valid one. + * This keeps the outline thickness consistent everywhere. */ + if (ref_id == 0u && outline) { + depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel; + depth_texel = (id.y != 0u) ? texel + ivec2(0, -1) : depth_texel; + depth_texel = (id.z != 0u) ? texel + ivec2(0, 1) : depth_texel; + depth_texel = (id.w != 0u) ? texel + ivec2(1, 0) : depth_texel; + + ref_id = (id.x != 0u) ? id.x : ref_id; + ref_id = (id.y != 0u) ? id.y : ref_id; + ref_id = (id.z != 0u) ? id.z : ref_id; + ref_id = (id.w != 0u) ? id.w : ref_id; + } + + float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r; + float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r; + + /* Avoid bad cases of zfighting for occlusion only. */ + const float epsilon = 3.0 / 8388608.0; + bool occluded = (ref_depth > scene_depth + epsilon); + + /* WATCH: Keep in sync with outlineId of the prepass. */ + uint color_id = ref_id >> 14u; + if (ref_id == 0u) { + FragColor = vec4(0.0); + } + else if (color_id == 1u) { + FragColor = colorSelect; + } + else if (color_id == 2u) { + FragColor = colorDupliSelect; + } + else if (color_id == 3u) { + FragColor = colorActive; + } + else { + FragColor = colorTransform; + } + + FragColor.a *= (occluded) ? alphaOcclu : 1.0; + FragColor.a = (outline) ? FragColor.a : 0.0; +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl new file mode 100644 index 00000000000..cb9fe0e7c36 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl @@ -0,0 +1,51 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D outlineColor; + +uniform float alpha; +uniform bool doExpand; + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + FragColor = texelFetch(outlineColor, uv, 0).rgba; + + vec4 color[4]; + color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(1, 0)).rgba; + color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 1)).rgba; + color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba; + color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -1)).rgba; + + vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a); + + vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */ + bvec4 btests = equal(tests, vec4(1.0)); + + if (FragColor.a != 0.0) { + return; + } + +#ifdef LARGE_OUTLINE + if (!any(btests)) { + color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(2, 0)).rgba; + color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 2)).rgba; + color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-2, 0)).rgba; + color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -2)).rgba; + + values = vec4(color[0].a, color[1].a, color[2].a, color[3].a); + + tests = step(vec4(1e-6), values); /* (color.a != 0.0) */ + btests = equal(tests, vec4(1.0)); + } +#endif + + FragColor = (btests.x) ? color[0] : FragColor; + FragColor = (btests.y) ? color[1] : FragColor; + FragColor = (btests.z) ? color[2] : FragColor; + FragColor = (btests.w) ? color[3] : FragColor; + + FragColor.a *= (!doExpand) ? 0.0 : 1.0; +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl new file mode 100644 index 00000000000..144024a7d5d --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl @@ -0,0 +1,31 @@ + +uniform ivec3 grid_resolution; +uniform vec3 corner; +uniform vec3 increment_x; +uniform vec3 increment_y; +uniform vec3 increment_z; + +flat out int objectId; + +void main() +{ + vec3 ls_cell_location; + /* Keep in sync with update_irradiance_probe */ + ls_cell_location.z = float(gl_VertexID % grid_resolution.z); + ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y); + ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y)); + + vec3 ws_cell_location = corner + + (increment_x * ls_cell_location.x + increment_y * ls_cell_location.y + + increment_z * ls_cell_location.z); + + gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0); + gl_PointSize = 2.0f; + + /* ID 0 is nothing (background) */ + objectId = resource_handle + 1; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(ws_cell_location); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl new file mode 100644 index 00000000000..5d6c4881b5b --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl @@ -0,0 +1,18 @@ + +/* Should be 2 bits only [0..3]. */ +uniform int outlineId; + +flat in int objectId; + +/* using uint because 16bit uint can contain more ids than int. */ +out uint outId; + +/* Replace top 2 bits (of the 16bit output) by outlineId. + * This leaves 16K different IDs to create outlines between objects. + * SHIFT = (32 - (16 - 2)) */ +#define SHIFT 18u + +void main() +{ + outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT); +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl new file mode 100644 index 00000000000..b32913dcd60 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl @@ -0,0 +1,54 @@ + +layout(lines_adjacency) in; +layout(line_strip, max_vertices = 2) out; + +in vec3 vPos[]; +in int objectId_g[]; + +flat out int objectId; + +void vert_from_gl_in(int v) +{ + gl_Position = gl_in[v].gl_Position; + objectId = objectId_g[v]; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance); +#endif +} + +void main() +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + + vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0); + + vec3 v10 = vPos[0] - vPos[1]; + vec3 v12 = vPos[2] - vPos[1]; + vec3 v13 = vPos[3] - vPos[1]; + + vec3 n0 = cross(v12, v10); + vec3 n3 = cross(v13, v12); + + float fac0 = dot(view_vec, n0); + float fac3 = dot(view_vec, n3); + + /* If both adjacent verts are facing the camera the same way, + * then it isn't an outline edge. */ + if (sign(fac0) == sign(fac3)) { + return; + } + + /* Don't outline if concave edge. */ + /* That would hide a lot of non useful edge but it flickers badly. + * TODO revisit later... */ + // if (dot(n0, v13) > 0.01) + // return; + + vert_from_gl_in(1); + EmitVertex(); + + vert_from_gl_in(2); + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl new file mode 100644 index 00000000000..7740f9a4af2 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl @@ -0,0 +1,29 @@ + +in vec3 pos; + +#ifdef USE_GEOM +out vec3 vPos; +out int objectId_g; +# define objectId objectId_g +#else + +flat out int objectId; +#endif + +void main() +{ + vec3 world_pos = point_object_to_world(pos); +#ifdef USE_GEOM + vPos = point_world_to_view(world_pos); +#endif + gl_Position = point_world_to_ndc(world_pos); + /* Small bias to always be on top of the geom. */ + gl_Position.z -= 1e-3; + + /* ID 0 is nothing (background) */ + objectId = resource_handle + 1; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl new file mode 100644 index 00000000000..ba5d073a9c2 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl @@ -0,0 +1,21 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D outlineBluredColor; +uniform vec2 rcpDimensions; + +void main() +{ +#ifdef USE_FXAA + float aa_alpha = + FxaaPixelShader(uvcoordsvar.st, outlineBluredColor, rcpDimensions, 1.0, 0.166, 0.0833).r; +#endif + + FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba; + +#ifdef USE_FXAA + FragColor.a = aa_alpha; +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl new file mode 100644 index 00000000000..2b5d586bdd1 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl @@ -0,0 +1,24 @@ + +in vec3 pos; +in vec4 nor; /* select flag on the 4th component */ + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + bool is_select = (nor.w > 0.0); + bool is_hidden = (nor.w < 0.0); + + /* Don't draw faces that are selected. */ + if (is_hidden || is_select) { + gl_Position = vec4(-2.0, -2.0, -2.0, 1.0); + } + else { +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif + } +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl new file mode 100644 index 00000000000..9d102bd4295 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl @@ -0,0 +1,32 @@ + +in vec3 pos; +in vec4 nor; /* select flag on the 4th component */ + +out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + bool is_select = (nor.w > 0.0); + bool is_hidden = (nor.w < 0.0); + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + /* Add offset in Z to avoid zfighting and render selected wires on top. */ + /* TODO scale this bias using znear and zfar range. */ + gl_Position.z -= (is_select ? 2e-4 : 1e-4); + + if (is_hidden) { + gl_Position = vec4(-2.0, -2.0, -2.0, 1.0); + } + + finalColor = (is_select) ? vec4(1.0) : colorWire; + finalColor.a = nor.w; + + gl_PointSize = sizeVertex * 2.0; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl new file mode 100644 index 00000000000..4d0692039a4 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl @@ -0,0 +1,23 @@ +in vec2 uv_interp; + +out vec4 fragColor; + +uniform float opacity = 1.0; + +uniform sampler2D maskImage; +uniform bool maskImagePremultiplied; +uniform vec3 maskColor; +uniform bool maskInvertStencil; + +void main() +{ + vec4 mask = vec4(texture_read_as_srgb(maskImage, maskImagePremultiplied, uv_interp).rgb, 1.0); + if (maskInvertStencil) { + mask.rgb = 1.0 - mask.rgb; + } + float mask_step = smoothstep(0, 3.0, mask.r + mask.g + mask.b); + mask.rgb *= maskColor; + mask.a = mask_step * opacity; + + fragColor = mask; +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl new file mode 100644 index 00000000000..cb29fefb7ef --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl @@ -0,0 +1,19 @@ + +in vec3 pos; +in vec2 mu; /* masking uv map */ + +out vec2 uv_interp; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + uv_interp = mu; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl new file mode 100644 index 00000000000..2500ff83abe --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl @@ -0,0 +1,28 @@ + +in vec3 finalColor; + +out vec4 fragColor; + +uniform float opacity = 1.0; +uniform bool useAlphaBlend = false; + +vec3 linear_to_srgb_attr(vec3 c) +{ + c = max(c, vec3(0.0)); + vec3 c1 = c * 12.92; + vec3 c2 = 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055; + return mix(c1, c2, step(vec3(0.0031308), c)); +} + +void main() +{ + vec3 color = linear_to_srgb_attr(finalColor); + + if (useAlphaBlend) { + fragColor = vec4(color, opacity); + } + else { + /* mix with 1.0 -> is like opacity when using multiply blend mode */ + fragColor = vec4(mix(vec3(1.0), color, opacity), 1.0); + } +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl new file mode 100644 index 00000000000..e060e33deba --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl @@ -0,0 +1,27 @@ + +in vec3 pos; +in vec3 ac; /* active color */ + +out vec3 finalColor; + +vec3 srgb_to_linear_attr(vec3 c) +{ + c = max(c, vec3(0.0)); + vec3 c1 = c * (1.0 / 12.92); + vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4)); + return mix(c1, c2, step(vec3(0.04045), c)); +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + finalColor = srgb_to_linear_attr(ac); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl new file mode 100644 index 00000000000..0020d76ed6a --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl @@ -0,0 +1,106 @@ + +in vec2 weight_interp; /* (weight, alert) */ + +out vec4 fragColor; + +uniform float opacity = 1.0; +uniform sampler1D colorramp; + +uniform bool useAlphaBlend = false; +uniform bool drawContours = false; + +float contours(float value, float steps, float width_px, float max_rel_width, float gradient) +{ + /* Minimum visible and minimum full strength line width in screen space for fade out. */ + const float min_width_px = 1.3, fade_width_px = 2.3; + /* Line is thinner towards the increase in the weight gradient by this factor. */ + const float hi_bias = 2.0; + + /* Don't draw lines at 0 or 1. */ + float rel_value = value * steps; + + if (rel_value < 0.5 || rel_value > steps - 0.5) { + return 0.0; + } + + /* Check if completely invisible due to fade out. */ + float rel_gradient = gradient * steps; + float rel_min_width = min_width_px * rel_gradient; + + if (max_rel_width <= rel_min_width) { + return 0.0; + } + + /* Main shape of the line, accounting for width bias and maximum weight space width. */ + float rel_width = width_px * rel_gradient; + + float offset = fract(rel_value + 0.5) - 0.5; + + float base_alpha = 1.0 - max(offset * hi_bias, -offset) / min(max_rel_width, rel_width); + + /* Line fadeout when too thin in screen space. */ + float rel_fade_width = fade_width_px * rel_gradient; + + float fade_alpha = (max_rel_width - rel_min_width) / (rel_fade_width - rel_min_width); + + return clamp(base_alpha, 0.0, 1.0) * clamp(fade_alpha, 0.0, 1.0); +} + +vec4 contour_grid(float weight, float weight_gradient) +{ + /* Fade away when the gradient is too low to avoid big fills and noise. */ + float flt_eps = max(1e-8, 1e-6 * weight); + + if (weight_gradient <= flt_eps) { + return vec4(0.0); + } + + /* Three levels of grid lines */ + float grid10 = contours(weight, 10.0, 5.0, 0.3, weight_gradient); + float grid100 = contours(weight, 100.0, 3.5, 0.35, weight_gradient) * 0.6; + float grid1000 = contours(weight, 1000.0, 2.5, 0.4, weight_gradient) * 0.25; + + /* White lines for 0.1 and 0.01, and black for 0.001 */ + vec4 grid = vec4(1.0) * max(grid10, grid100); + + grid.a = max(grid.a, grid1000); + + return grid * clamp((weight_gradient - flt_eps) / flt_eps, 0.0, 1.0); +} + +void main() +{ + float alert = weight_interp.y; + vec4 color; + + /* Missing vertex group alert color. Uniform in practice. */ + if (alert > 1.1) { + color = colorVertexMissingData; + } + /* Weights are available */ + else { + float weight = weight_interp.x; + vec4 weight_color = texture(colorramp, weight, 0); + + /* Contour display */ + if (drawContours) { + /* This must be executed uniformly for all fragments */ + float weight_gradient = length(vec2(dFdx(weight), dFdy(weight))); + + vec4 grid = contour_grid(weight, weight_gradient); + + weight_color = grid + weight_color * (1 - grid.a); + } + + /* Zero weight alert color. Nonlinear blend to reduce impact. */ + color = mix(weight_color, colorVertexUnreferenced, alert * alert); + } + + if (useAlphaBlend) { + fragColor = vec4(color.rgb, opacity); + } + else { + /* mix with 1.0 -> is like opacity when using multiply blend mode */ + fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0); + } +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl new file mode 100644 index 00000000000..b3baa8c7b07 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl @@ -0,0 +1,20 @@ + +in float weight; +in vec3 pos; + +out vec2 weight_interp; /* (weight, alert) */ + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + /* Separate actual weight and alerts for independent interpolation */ + weight_interp = max(vec2(weight, -weight), 0.0); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl new file mode 100644 index 00000000000..d5a42d2d309 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl @@ -0,0 +1,38 @@ + +uniform bool useSelect; + +in vec3 pos; +in vec4 nor; /* flag stored in w */ + +flat out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + bool is_select = (nor.w > 0.0) && useSelect; + bool is_hidden = (nor.w < 0.0) && useSelect; + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + /* Add offset in Z to avoid zfighting and render selected wires on top. */ + /* TODO scale this bias using znear and zfar range. */ + gl_Position.z -= (is_select ? 2e-4 : 1e-4); + + if (is_hidden) { + gl_Position = vec4(-2.0, -2.0, -2.0, 1.0); + } + + const vec4 colSel = vec4(1.0); + + finalColor = (is_select) ? colSel : colorWire; + + /* Weight paint needs a light color to contrasts with dark weights. */ + if (!useSelect) { + finalColor = vec4(1.0, 1.0, 1.0, 0.3); + } + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/particle_frag.glsl new file mode 100644 index 00000000000..36928d0c776 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/particle_frag.glsl @@ -0,0 +1,16 @@ + +in vec4 finalColor; + +out vec4 fragColor; + +void main() +{ + float dist = length(gl_PointCoord - vec2(0.5)); + + if (dist > 0.5) { + discard; + } + /* Nice sphere falloff. */ + float intensity = sqrt(1.0 - dist * 2.0) * 0.5 + 0.5; + fragColor = finalColor * vec4(intensity, intensity, intensity, 1.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/particle_vert.glsl new file mode 100644 index 00000000000..9ff2c42921d --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/particle_vert.glsl @@ -0,0 +1,68 @@ + +uniform sampler1D weightTex; +uniform vec4 color; /* Drawsize packed in alpha */ + +/* ---- Instantiated Attrs ---- */ +in vec3 pos; +in int vclass; + +/* ---- Per instance Attrs ---- */ +in vec3 part_pos; +in vec4 part_rot; +in float part_val; + +#ifdef USE_DOTS +out vec4 finalColor; +#else +flat out vec4 finalColor; +#endif + +#define VCLASS_SCREENALIGNED (1 << 9) + +#define VCLASS_EMPTY_AXES (1 << 11) + +vec3 rotate(vec3 vec, vec4 quat) +{ + /* The quaternion representation here stores the w component in the first index */ + return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec); +} + +void main() +{ + float draw_size = color.a; + + vec3 world_pos = part_pos; + +#ifdef USE_DOTS + gl_Position = point_world_to_ndc(world_pos); + /* World sized points. */ + gl_PointSize = sizePixel * draw_size * ProjectionMatrix[1][1] * sizeViewport.y / gl_Position.w; +#else + + if ((vclass & VCLASS_SCREENALIGNED) != 0) { + /* World sized, camera facing geometry. */ + world_pos += (screenVecs[0].xyz * pos.x + screenVecs[1].xyz * pos.y) * draw_size; + } + else { + world_pos += rotate(pos, part_rot) * draw_size; + } + + gl_Position = point_world_to_ndc(world_pos); +#endif + + /* Coloring */ + if ((vclass & VCLASS_EMPTY_AXES) != 0) { + /* see VBO construction for explanation. */ + finalColor = vec4(clamp(pos * 10000.0, 0.0, 1.0), 1.0); + } + else if (part_val < 0.0) { + finalColor = vec4(color.rgb, 1.0); + } + else { + finalColor = vec4(texture(weightTex, part_val).rgb, 1.0); + } + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl new file mode 100644 index 00000000000..18a096da61b --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl @@ -0,0 +1,20 @@ + +uniform float maskOpacity; + +in vec3 pos; +in float msk; + +out vec4 finalColor; + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + float mask = 1.0 - (msk * maskOpacity); + finalColor = vec4(0.0, 0.0, 0.0, mask); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl new file mode 100644 index 00000000000..64f88bd74fa --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl @@ -0,0 +1,117 @@ + +uniform sampler3D velocityX; +uniform sampler3D velocityY; +uniform sampler3D velocityZ; +uniform float displaySize = 1.0; +uniform float slicePosition; +uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ + +/* SmokeDomainSettings.cell_size */ +uniform vec3 cellSize; +/* SmokeDomainSettings.p0 */ +uniform vec3 domainOriginOffset; +/* SmokeDomainSettings.res_min */ +uniform ivec3 adaptiveCellOffset; + +flat out vec4 finalColor; + +const vec3 corners[4] = vec3[4](vec3(0.0, 0.2, -0.5), + vec3(-0.2 * 0.866, -0.2 * 0.5, -0.5), + vec3(0.2 * 0.866, -0.2 * 0.5, -0.5), + vec3(0.0, 0.0, 0.5)); + +const int indices[12] = int[12](0, 1, 1, 2, 2, 0, 0, 3, 1, 3, 2, 3); + +/* Straight Port from BKE_defvert_weight_to_rgb() + * TODO port this to a color ramp. */ +vec3 weight_to_color(float weight) +{ + vec3 r_rgb = vec3(0.0); + float blend = ((weight / 2.0) + 0.5); + + if (weight <= 0.25) { /* blue->cyan */ + r_rgb.g = blend * weight * 4.0; + r_rgb.b = blend; + } + else if (weight <= 0.50) { /* cyan->green */ + r_rgb.g = blend; + r_rgb.b = blend * (1.0 - ((weight - 0.25) * 4.0)); + } + else if (weight <= 0.75) { /* green->yellow */ + r_rgb.r = blend * ((weight - 0.50) * 4.0); + r_rgb.g = blend; + } + else if (weight <= 1.0) { /* yellow->red */ + r_rgb.r = blend; + r_rgb.g = blend * (1.0 - ((weight - 0.75) * 4.0)); + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb = vec3(1.0, 0.0, 1.0); + } + + return r_rgb; +} + +mat3 rotation_from_vector(vec3 v) +{ + /* Add epsilon to avoid NaN. */ + vec3 N = normalize(v + 1e-8); + vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 T = normalize(cross(UpVector, N)); + vec3 B = cross(N, T); + return mat3(T, B, N); +} + +void main() +{ +#ifdef USE_NEEDLE + int cell = gl_VertexID / 12; +#else + int cell = gl_VertexID / 2; +#endif + + ivec3 volume_size = textureSize(velocityX, 0); + + ivec3 cell_ofs = ivec3(0); + ivec3 cell_div = volume_size; + if (sliceAxis == 0) { + cell_ofs.x = int(slicePosition * float(volume_size.x)); + cell_div.x = 1; + } + else if (sliceAxis == 1) { + cell_ofs.y = int(slicePosition * float(volume_size.y)); + cell_div.y = 1; + } + else if (sliceAxis == 2) { + cell_ofs.z = int(slicePosition * float(volume_size.z)); + cell_div.z = 1; + } + + ivec3 cell_co; + cell_co.x = cell % cell_div.x; + cell_co.y = (cell / cell_div.x) % cell_div.y; + cell_co.z = cell / (cell_div.x * cell_div.y); + cell_co += cell_ofs; + + vec3 pos = domainOriginOffset + cellSize * (vec3(cell_co + adaptiveCellOffset) + 0.5); + + vec3 velocity; + velocity.x = texelFetch(velocityX, cell_co, 0).r; + velocity.y = texelFetch(velocityY, cell_co, 0).r; + velocity.z = texelFetch(velocityZ, cell_co, 0).r; + + finalColor = vec4(weight_to_color(length(velocity)), 1.0); + +#ifdef USE_NEEDLE + mat3 rot_mat = rotation_from_vector(velocity); + vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]]; + pos += rotated_pos * length(velocity) * displaySize * cellSize; +#else + pos += ((gl_VertexID % 2) == 1) ? velocity * displaySize * cellSize : vec3(0.0); +#endif + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); +} diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl new file mode 100644 index 00000000000..39d0012574c --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl @@ -0,0 +1,20 @@ + +in vec3 finalColor; +flat in float edgeSharpness; + +flat in vec2 edgeStart; +noperspective in vec2 edgePos; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; + +void main() +{ + if (edgeSharpness < 0.0) { + discard; + } + + lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); + fragColor.rgb = finalColor; + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl new file mode 100644 index 00000000000..346c9d83a9e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl @@ -0,0 +1,61 @@ + +/* This shader is only used for edge selection and OSX workaround for large wires. */ + +layout(lines) in; +layout(triangle_strip, max_vertices = 4) out; + +in vec3 finalColor_g[]; +in float edgeSharpness_g[]; + +#ifndef SELECT_EDGES +out vec3 finalColor; +flat out float edgeSharpness; + +flat out vec2 edgeStart; +noperspective out vec2 edgePos; +#endif + +void do_vertex(const int i, float coord, vec2 offset) +{ +#ifndef SELECT_EDGES + /* TODO */ + edgePos = edgeStart = vec2(0); + edgeSharpness = edgeSharpness_g[i]; + finalColor = finalColor_g[i]; +#endif + gl_Position = gl_in[i].gl_Position; + /* Multiply offset by 2 because gl_Position range is [-1..1]. */ + gl_Position.xy += offset * 2.0 * gl_Position.w; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_set_clip_distance(gl_in[i].gl_ClipDistance); +#endif + EmitVertex(); +} + +void main() +{ + vec2 ss_pos[2]; + ss_pos[0] = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w; + ss_pos[1] = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w; + + vec2 line = ss_pos[0] - ss_pos[1]; + line = abs(line) * sizeViewport.xy; + + float half_size = sizePixel * 0.5; + + vec3 edge_ofs = vec3(half_size * sizeViewportInv.xy, 0.0); + + bool horizontal = line.x > line.y; + edge_ofs = (horizontal) ? edge_ofs.zyz : edge_ofs.xzz; + + if (edgeSharpness_g[0] < 0.0) { + return; + } + + do_vertex(0, half_size, edge_ofs.xy); + do_vertex(0, -half_size, -edge_ofs.xy); + do_vertex(1, half_size, edge_ofs.xy); + do_vertex(1, -half_size, -edge_ofs.xy); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl new file mode 100644 index 00000000000..78ce8fd8a8f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -0,0 +1,144 @@ + +uniform float wireStepParam; + +in vec3 pos; +in vec3 nor; +in float wd; /* wiredata */ + +float get_edge_sharpness(float wd) +{ + return ((wd == 0.0) ? -1.5 : wd) + wireStepParam; +} + +/* Geometry shader version */ +#if defined(SELECT_EDGES) || defined(USE_GEOM) +out vec3 finalColor_g; +out float edgeSharpness_g; + +#else /* USE_GEOM */ + +flat out vec2 edgeStart; +noperspective out vec2 edgePos; + +out vec3 finalColor; +flat out float edgeSharpness; +# define finalColor_g finalColor +# define edgeSharpness_g edgeSharpness + +#endif /* SELECT_EDGES */ + +uniform bool useColoring; +uniform bool isTransform; +uniform bool isObjectColor; +uniform bool isRandomColor; + +void wire_color_get(out vec3 rim_col, out vec3 wire_col) +{ + int flag = int(abs(ObjectInfo.w)); + bool is_selected = (flag & DRW_BASE_SELECTED) != 0; + bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0; + bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0; + bool is_active = (flag & DRW_BASE_ACTIVE) != 0; + + if (is_from_set) { + rim_col = colorDupli.rgb; + wire_col = colorDupli.rgb; + } + else if (is_from_dupli) { + if (is_selected) { + if (isTransform) { + rim_col = colorTransform.rgb; + } + else { + rim_col = colorDupliSelect.rgb; + } + } + else { + rim_col = colorDupli.rgb; + } + wire_col = colorDupli.rgb; + } + else if (is_selected && useColoring) { + if (isTransform) { + rim_col = colorTransform.rgb; + } + else if (is_active) { + rim_col = colorActive.rgb; + } + else { + rim_col = colorSelect.rgb; + } + wire_col = colorWire.rgb; + } + else { + rim_col = colorWire.rgb; + wire_col = colorBackground.rgb; + } +} + +vec3 hsv_to_rgb(vec3 hsv) +{ + vec3 nrgb = abs(hsv.x * 6.0 - vec3(3.0, 2.0, 4.0)) * vec3(1, -1, -1) + vec3(-1, 2, 2); + nrgb = clamp(nrgb, 0.0, 1.0); + return ((nrgb - 1.0) * hsv.y + 1.0) * hsv.z; +} + +void wire_object_color_get(out vec3 rim_col, out vec3 wire_col) +{ + int flag = int(abs(ObjectInfo.w)); + bool is_selected = (flag & DRW_BASE_SELECTED) != 0; + + if (isObjectColor) { + rim_col = wire_col = ObjectColor.rgb * 0.5; + } + else { + float hue = ObjectInfo.z; + vec3 hsv = vec3(hue, 0.75, 0.8); + rim_col = wire_col = hsv_to_rgb(hsv); + } + + if (is_selected && useColoring) { + /* "Normalize" color. */ + wire_col += 1e-4; /* Avoid division by 0. */ + float brightness = max(wire_col.x, max(wire_col.y, wire_col.z)); + wire_col *= 0.5 / brightness; + rim_col += 0.75; + } + else { + rim_col *= 0.5; + wire_col += 0.5; + } +} + +void main() +{ + vec3 wpos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(wpos); + +#if !(defined(SELECT_EDGES) || defined(USE_GEOM)) + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +#endif + + edgeSharpness_g = get_edge_sharpness(wd); + + vec3 rim_col, wire_col; + if (isObjectColor || isRandomColor) { + wire_object_color_get(rim_col, wire_col); + } + else { + wire_color_get(rim_col, wire_col); + } + + vec3 wnor = normalize(normal_object_to_world(nor)); + float facing = dot(wnor, ViewMatrixInverse[2].xyz); + facing = clamp(abs(facing), 0.0, 1.0); + + vec3 final_front_col = mix(rim_col, wire_col, 0.4); + vec3 final_rim_col = mix(rim_col, wire_col, 0.1); + finalColor_g = mix(final_rim_col, final_front_col, facing); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(wpos); +#endif +} -- cgit v1.2.3