Implement display of weight isoline contours in the fragment shader.

Add an option to display contour lines tracing through points with the
same interpolated weight value in weight paint mode. This can be useful
for working on gentle gradients over a relatively high resolution mesh,
where the difference in color between adjacent vertices is very small.

The contour grid has 3 levels of detail going down to step 0.001,
which automatically fade in or out based on the weight gradient.

Fade out works by capping both screen space and weight space line
width, and reducing alpha when the screen space width becomes too
small for moire and noise-less rendering.

Reviewers: fclem

Differential Revision: https://developer.blender.org/D3749
This commit is contained in:
Alexander Gavrilov 2018-09-27 18:38:07 +03:00
parent d12e781810
commit ba3ef44a6b
6 changed files with 97 additions and 8 deletions

View File

@ -4501,9 +4501,10 @@ class VIEW3D_PT_overlay_edit_mesh_shading(Panel):
col.prop(overlay, "show_weight", text="Vertex Group Weights")
if overlay.show_weight:
row = col.split()
row = col.split(factor=0.33)
row.label(text="Zero Weights")
row.prop(tool_settings, "vertex_group_user", text="")
sub = row.row()
sub.prop(tool_settings, "vertex_group_user", expand=True)
col.prop(overlay, "show_statvis", text="Mesh Analysis")
if overlay.show_statvis:
@ -4774,6 +4775,14 @@ class VIEW3D_PT_overlay_paint(Panel):
'PAINT_WEIGHT': "weight_paint_mode_opacity",
}[context.mode], text="Opacity")
if context.mode == 'PAINT_WEIGHT':
row = col.split(factor=0.33)
row.label(text="Zero Weights")
sub = row.row()
sub.prop(context.tool_settings, "vertex_group_user", expand=True)
col.prop(overlay, "show_wpaint_contours")
if context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
col.prop(overlay, "show_paint_wire")

View File

@ -1091,10 +1091,6 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
row.active = mesh.use_mirror_x
row.prop(mesh, "use_mirror_topology")
col.label(text="Show Zero Weights:")
sub = col.row()
sub.prop(tool_settings, "vertex_group_user", expand=True)
self.unified_paint_settings(col, context)
# ********** default tools for vertex-paint ****************

View File

@ -140,6 +140,8 @@ static void PAINT_WEIGHT_cache_init(void *vedata)
stl->g_data->fweights_shgrp = DRW_shgroup_create(e_data.weight_face_shader, psl->weight_faces);
DRW_shgroup_uniform_bool_copy(stl->g_data->fweights_shgrp, "drawContours", (v3d->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0);
DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "opacity", &v3d->overlay.weight_paint_mode_opacity, 1);
DRW_shgroup_uniform_texture(stl->g_data->fweights_shgrp, "colorramp", globals_weight_ramp);
DRW_shgroup_uniform_block(stl->g_data->fweights_shgrp, "globalsBlock", globals_ubo);

View File

@ -6,13 +6,71 @@ out vec4 fragColor;
uniform float opacity = 1.0;
uniform sampler1D colorramp;
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 */
if (alert > 1.0) {
/* Missing vertex group alert color. Uniform in practice. */
if (alert > 1.1) {
color = colorVertexMissingData;
}
/* Weights are available */
@ -20,6 +78,16 @@ void main()
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);
}

View File

@ -177,6 +177,10 @@ typedef struct View3DOverlay {
/* Paint mode settings */
int paint_flag;
/* Weight paint mode settings */
int wpaint_flag;
char _pad2[4];
/* Alpha for texture, weight, vertex paint overlay */
float texture_paint_mode_opacity;
float vertex_paint_mode_opacity;
@ -460,6 +464,11 @@ enum {
V3D_OVERLAY_PAINT_WIRE = (1 << 0),
};
/* View3DOverlay->wpaint_flag */
enum {
V3D_OVERLAY_WPAINT_CONTOURS = (1 << 0),
};
/* View3D->around */
enum {
/* center of the bounding box */

View File

@ -2783,6 +2783,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_wpaint_contours", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.wpaint_flag", V3D_OVERLAY_WPAINT_CONTOURS);
RNA_def_property_ui_text(prop, "Show Weight Contours", "Show contour lines formed by points with the same interpolated weight");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_WEIGHT);
RNA_def_property_ui_text(prop, "Show Weights", "Display weights in editmode");