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
This commit is contained in:
parent
6791d95b1d
commit
3da46a8d8d
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ layout(std140) uniform globalsBlock {
|
|||
vec4 colorEmpty;
|
||||
vec4 colorVertex;
|
||||
vec4 colorVertexSelect;
|
||||
vec4 colorVertexUnreferenced;
|
||||
vec4 colorVertexMissingData;
|
||||
vec4 colorEditMeshActive;
|
||||
vec4 colorEdgeSelect;
|
||||
vec4 colorEdgeSeam;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue