diff options
author | Jeroen Bakker <j.bakker@atmind.nl> | 2018-09-25 19:19:59 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2018-09-27 17:33:33 +0300 |
commit | 3da46a8d8df26d6fe5b9289ae7ebfe01f1deeda8 (patch) | |
tree | e752806eb0db2c61f4592435a1173439ef534cbb /source/blender | |
parent | 6791d95b1db8a2419b9534e95ea7c73c1cb4ff62 (diff) |
Implement a new dedicated weight painting shader.
Move the weight paint drawing to the fragment shader. The shader
uses a texture that uses the U.coba_weight custom color band, or
an internal color band.
In addition to actual weights, the shader has to display two
alert colors: missing vertex group, and zero weight. The zero
weight alert has to be blended with regular weight colors,
so that a single alert vertex surrounded by weighted ones is
still visible.
Reviewers: campbellbarton, fclem
Differential Revision: https://developer.blender.org/D3675
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_mesh.c | 109 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.c | 56 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/paint_weight_mode.c | 12 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/common_globals_lib.glsl | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/paint_weight_frag.glsl | 29 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/paint_weight_vert.glsl | 15 |
9 files changed, 147 insertions, 82 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index f2a8256489d..06752e41092 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -307,6 +307,8 @@ data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_texture_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_vertex_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_vertex_vert.glsl SRC) +data_to_c_simple(modes/shaders/paint_weight_frag.glsl SRC) +data_to_c_simple(modes/shaders/paint_weight_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_wire_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_wire_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_vert_frag.glsl SRC) diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 0e451fe12a6..6a324aa078f 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -201,7 +201,7 @@ typedef struct MeshRenderData { int *loose_verts; float (*poly_normals)[3]; - float (*vert_weight_color)[3]; + float (*vert_weight); char (*vert_color)[3]; GPUPackedNormal *poly_normals_pack; GPUPackedNormal *vert_normals_pack; @@ -845,7 +845,7 @@ static void mesh_render_data_free(MeshRenderData *rdata) MEM_SAFE_FREE(rdata->poly_normals); MEM_SAFE_FREE(rdata->poly_normals_pack); MEM_SAFE_FREE(rdata->vert_normals_pack); - MEM_SAFE_FREE(rdata->vert_weight_color); + MEM_SAFE_FREE(rdata->vert_weight); MEM_SAFE_FREE(rdata->edge_select_bool); MEM_SAFE_FREE(rdata->vert_color); @@ -1068,58 +1068,7 @@ fallback: } } -/* TODO, move into shader? */ -static void rgb_from_weight(float r_rgb[3], const float weight) -{ - const float blend = ((weight / 2.0f) + 0.5f); - - if (weight <= 0.25f) { /* blue->cyan */ - r_rgb[0] = 0.0f; - r_rgb[1] = blend * weight * 4.0f; - r_rgb[2] = blend; - } - else if (weight <= 0.50f) { /* cyan->green */ - r_rgb[0] = 0.0f; - r_rgb[1] = blend; - r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f)); - } - else if (weight <= 0.75f) { /* green->yellow */ - r_rgb[0] = blend * ((weight - 0.50f) * 4.0f); - r_rgb[1] = blend; - r_rgb[2] = 0.0f; - } - else if (weight <= 1.0f) { /* yellow->red */ - r_rgb[0] = blend; - r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f)); - r_rgb[2] = 0.0f; - } - else { - /* exceptional value, unclamped or nan, - * avoid uninitialized memory use */ - r_rgb[0] = 1.0f; - r_rgb[1] = 0.0f; - r_rgb[2] = 1.0f; - } -} - -static void vertex_weight_color(float vweight[3], float weight, bool show_alert_color) -{ - CLAMP(weight, 0.0f, 1.0f); - - if (show_alert_color) { - bTheme *theme = U.themes.first; - - rgb_uchar_to_float(vweight, (uchar *)theme->tv3d.vertex_unreferenced); - } - else if (U.flag & USER_CUSTOM_RANGE) { - BKE_colorband_evaluate(&U.coba_weight, weight, vweight); - } - else { - rgb_from_weight(vweight, weight); - } -} - -static void evaluate_vertex_weight(float vweight[3], const MDeformVert *dvert, const struct DRW_MeshWeightState *wstate) +static float evaluate_vertex_weight(const MDeformVert *dvert, const struct DRW_MeshWeightState *wstate) { float input = 0.0f; bool show_alert_color = false; @@ -1152,16 +1101,19 @@ static void evaluate_vertex_weight(float vweight[3], const MDeformVert *dvert, c } } - vertex_weight_color(vweight, input, show_alert_color); + if (show_alert_color) { + return -1.0f; + } + else { + CLAMP(input, 0.0f, 1.0f); + return input; + } } -/* color-code for missing data (full brightness isn't easy on the eye). */ -static const unsigned char missing_weight_color[3] = { 0xa0, 0x00, 0xa0 }; - -/** Ensure #MeshRenderData.vert_weight_color */ -static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, const struct DRW_MeshWeightState *wstate) +/** Ensure #MeshRenderData.vert_weight */ +static void mesh_render_data_ensure_vert_weight(MeshRenderData *rdata, const struct DRW_MeshWeightState *wstate) { - float (*vweight)[3] = rdata->vert_weight_color; + float (*vweight) = rdata->vert_weight; if (vweight == NULL) { if (wstate->defgroup_active == -1) { goto fallback; @@ -1178,10 +1130,10 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con BMVert *eve; int i; - vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); + vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) { const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - evaluate_vertex_weight(vweight[i], dvert, wstate); + vweight[i] = evaluate_vertex_weight(dvert, wstate); } } else { @@ -1189,31 +1141,26 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con goto fallback; } - vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); + vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); for (int i = 0; i < rdata->vert_len; i++) { - evaluate_vertex_weight(vweight[i], &rdata->dvert[i], wstate); + vweight[i] = evaluate_vertex_weight(&rdata->dvert[i], wstate); } } } return; fallback: - vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); - - float error_color[3]; + vweight = rdata->vert_weight = MEM_callocN(sizeof(*vweight) * rdata->vert_len, __func__); if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) { - rgb_uchar_to_float(error_color, missing_weight_color); + copy_vn_fl(vweight, rdata->vert_len, -2.0f); } - else { - vertex_weight_color(error_color, 0.0f, wstate->alert_mode != OB_DRAW_GROUPUSER_NONE); - } - - for (int i = 0; i < rdata->vert_len; i++) { - copy_v3_v3(vweight[i], error_color); + else if (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) { + copy_vn_fl(vweight, rdata->vert_len, -1.0f); } } + /** Ensure #MeshRenderData.edge_select_bool */ static void mesh_render_data_ensure_edge_select_bool(MeshRenderData *rdata, bool use_wire) { @@ -2782,9 +2729,9 @@ static GPUVertBuf *mesh_create_tri_weights( uint cidx = 0; static GPUVertFormat format = { 0 }; - static struct { uint col; } attr_id; + static struct { uint weight; } attr_id; if (format.attr_len == 0) { - attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.weight = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } vbo = GPU_vertbuf_create_with_format(&format); @@ -2794,8 +2741,8 @@ static GPUVertBuf *mesh_create_tri_weights( int vbo_len_used = 0; GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - mesh_render_data_ensure_vert_weight_color(rdata, wstate); - const float (*vert_weight_color)[3] = rdata->vert_weight_color; + mesh_render_data_ensure_vert_weight(rdata, wstate); + const float (*vert_weight) = rdata->vert_weight; if (rdata->edit_bmesh) { for (int i = 0; i < tri_len; i++) { @@ -2804,7 +2751,7 @@ static GPUVertBuf *mesh_create_tri_weights( if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) { for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { const int v_index = BM_elem_index_get(ltri[tri_corner]->v); - GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_weight_color[v_index]); + GPU_vertbuf_attr_set(vbo, attr_id.weight, cidx++, &vert_weight[v_index]); } } } @@ -2815,7 +2762,7 @@ static GPUVertBuf *mesh_create_tri_weights( if (!(use_hide && (rdata->mpoly[mlt->poly].flag & ME_HIDE))) { for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { const uint v_index = rdata->mloop[mlt->tri[tri_corner]].v; - GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_weight_color[v_index]); + GPU_vertbuf_attr_set(vbo, attr_id.weight, cidx++, &vert_weight[v_index]); } } } diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index eeaa204a252..faa4d980cd1 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -47,6 +47,12 @@ GlobalsUboStorage ts; struct GPUUniformBuffer *globals_ubo = NULL; struct GPUTexture *globals_ramp = NULL; +struct GPUTexture *globals_weight_ramp = NULL; + +static bool weight_ramp_custom = false; +static ColorBand weight_ramp_copy; + +static struct GPUTexture* DRW_create_weight_colorramp_texture(void); void DRW_globals_update(void) { @@ -63,6 +69,8 @@ void DRW_globals_update(void) UI_GetThemeColor4fv(TH_EMPTY, ts.colorEmpty); UI_GetThemeColor4fv(TH_VERTEX, ts.colorVertex); UI_GetThemeColor4fv(TH_VERTEX_SELECT, ts.colorVertexSelect); + UI_GetThemeColor4fv(TH_VERTEX_UNREFERENCED, ts.colorVertexUnreferenced); + UI_COLOR_RGBA_FROM_U8(0xB0, 0x00, 0xB0, 0xFF, ts.colorVertexMissingData); UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, ts.colorEditMeshActive); UI_GetThemeColor4fv(TH_EDGE_SELECT, ts.colorEdgeSelect); @@ -174,6 +182,21 @@ void DRW_globals_update(void) globals_ramp = GPU_texture_create_1D(col_size, GPU_RGBA8, colors, NULL); MEM_freeN(colors); + + /* Weight Painting color ramp texture */ + bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0; + + if (weight_ramp_custom != user_weight_ramp || + (user_weight_ramp && memcmp(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)) != 0)) { + DRW_TEXTURE_FREE_SAFE(globals_weight_ramp); + } + + if (globals_weight_ramp == NULL) { + weight_ramp_custom = user_weight_ramp; + memcpy(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)); + + globals_weight_ramp = DRW_create_weight_colorramp_texture(); + } } /* ********************************* SHGROUP ************************************* */ @@ -924,3 +947,36 @@ bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis) return false; } + +static void DRW_evaluate_weight_to_color(float *result, float weight) +{ + if (U.flag & USER_CUSTOM_RANGE) + { + BKE_colorband_evaluate(&U.coba_weight, weight, result); + } + else { + /* Use gamma correction to even out the color bands: + * increasing widens yellow/cyan vs red/green/blue. + * Gamma 1.0 produces the original 2.79 color ramp. */ + const float gamma = 1.5f; + float hsv[3] = { (2.0f / 3.0f) * (1.0f - weight), 1.0f, pow(0.5f + 0.5f * weight, gamma) }; + + hsv_to_rgb_v(hsv, result); + + for (int i = 0; i < 3; i++) { + result[i] = pow(result[i], 1.0f/gamma); + } + } +} + +static GPUTexture* DRW_create_weight_colorramp_texture(void) +{ + char error[256]; + float pixels[256 * 4]; + for (int i = 0 ; i < 256 ; i ++) { + DRW_evaluate_weight_to_color(&pixels[i*4], i / 255.0f); + pixels[i*4 + 3] = 1.0f; + } + + return GPU_texture_create_1D(256, GPU_RGBA8, pixels, error); +} diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 2640451a889..a7de7fdeafa 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -57,6 +57,8 @@ typedef struct GlobalsUboStorage { float colorEmpty[4]; float colorVertex[4]; float colorVertexSelect[4]; + float colorVertexUnreferenced[4]; + float colorVertexMissingData[4]; float colorEditMeshActive[4]; float colorEdgeSelect[4]; float colorEdgeSeam[4]; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 41c905337ac..487e1d7a3ac 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2528,6 +2528,7 @@ void DRW_engines_register(void) extern struct GPUVertFormat *g_pos_format; /* draw_shgroup.c */ extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ extern struct GPUTexture *globals_ramp; /* draw_common.c */ +extern struct GPUTexture *globals_weight_ramp; /* draw_common.c */ void DRW_engines_free(void) { DRW_opengl_context_enable(); @@ -2553,6 +2554,7 @@ void DRW_engines_free(void) DRW_UBO_FREE_SAFE(globals_ubo); DRW_UBO_FREE_SAFE(view_ubo); DRW_TEXTURE_FREE_SAFE(globals_ramp); + DRW_TEXTURE_FREE_SAFE(globals_weight_ramp); MEM_SAFE_FREE(g_pos_format); MEM_SAFE_FREE(DST.RST.bound_texs); diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c index 68d1ffab2e6..f5394e4e925 100644 --- a/source/blender/draw/modes/paint_weight_mode.c +++ b/source/blender/draw/modes/paint_weight_mode.c @@ -43,6 +43,10 @@ extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ extern struct GlobalsUboStorage ts; /* draw_common.c */ +extern struct GPUTexture *globals_weight_ramp; /* draw_common.c */ + +extern char datatoc_paint_weight_vert_glsl[]; +extern char datatoc_paint_weight_frag_glsl[]; extern char datatoc_paint_wire_vert_glsl[]; extern char datatoc_paint_wire_frag_glsl[]; extern char datatoc_paint_vert_frag_glsl[]; @@ -91,7 +95,10 @@ typedef struct PAINT_WEIGHT_PrivateData { static void PAINT_WEIGHT_engine_init(void *UNUSED(vedata)) { if (!e_data.weight_face_shader) { - e_data.weight_face_shader = GPU_shader_get_builtin_shader(GPU_SHADER_MULTIPLY_AND_BLEND_PREPROCESSING); + e_data.weight_face_shader = DRW_shader_create_with_lib( + datatoc_paint_weight_vert_glsl, NULL, + datatoc_paint_weight_frag_glsl, + datatoc_common_globals_lib_glsl, NULL); } if (!e_data.wire_overlay_shader) { @@ -134,6 +141,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_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); } { @@ -214,6 +223,7 @@ static void PAINT_WEIGHT_draw_scene(void *vedata) static void PAINT_WEIGHT_engine_free(void) { + DRW_SHADER_FREE_SAFE(e_data.weight_face_shader); DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader); DRW_SHADER_FREE_SAFE(e_data.vert_overlay_shader); } diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl index bf761cd7c79..f1d118e572a 100644 --- a/source/blender/draw/modes/shaders/common_globals_lib.glsl +++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl @@ -14,6 +14,8 @@ layout(std140) uniform globalsBlock { vec4 colorEmpty; vec4 colorVertex; vec4 colorVertexSelect; + vec4 colorVertexUnreferenced; + vec4 colorVertexMissingData; vec4 colorEditMeshActive; vec4 colorEdgeSelect; vec4 colorEdgeSeam; diff --git a/source/blender/draw/modes/shaders/paint_weight_frag.glsl b/source/blender/draw/modes/shaders/paint_weight_frag.glsl new file mode 100644 index 00000000000..668ca9e3c07 --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_weight_frag.glsl @@ -0,0 +1,29 @@ + +in vec2 weight_interp; /* (weight, alert) */ + +out vec4 fragColor; + +uniform float opacity = 1.0; +uniform sampler1D colorramp; + +void main() +{ + float alert = weight_interp.y; + vec4 color; + + /* Missing vertex group alert color */ + if (alert > 1.0) { + color = colorVertexMissingData; + } + /* Weights are available */ + else { + float weight = weight_interp.x; + vec4 weight_color = texture(colorramp, weight, 0); + + /* Zero weight alert color. Nonlinear blend to reduce impact. */ + color = mix(weight_color, colorVertexUnreferenced, alert * alert); + } + + /* See gpu_shader_multiply_and_blend_preprocessing.glsl */ + fragColor = vec4(color.rgb * opacity + (1 - opacity), 1.0); +} diff --git a/source/blender/draw/modes/shaders/paint_weight_vert.glsl b/source/blender/draw/modes/shaders/paint_weight_vert.glsl new file mode 100644 index 00000000000..78a3695c82c --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_weight_vert.glsl @@ -0,0 +1,15 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in float weight; +in vec3 pos; + +out vec2 weight_interp; /* (weight, alert) */ + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + /* Separate actual weight and alerts for independent interpolation */ + weight_interp = max(vec2(weight, -weight), 0.0); +} |