Implement Stencil Mask Drawing for Texture Painting
authorJeroen Bakker <j.bakker@atmind.nl>
Thu, 21 Mar 2019 15:44:01 +0000 (16:44 +0100)
committerJeroen Bakker <j.bakker@atmind.nl>
Fri, 22 Mar 2019 07:21:12 +0000 (08:21 +0100)
Stencil mask drawing was not implemented yet. This commit will implement this for texture painting.
It brings the state back to how it was for B279.

Reviewed By: fclem

Maniphest Tasks: T58727

Differential Revision: https://developer.blender.org/D4570

source/blender/draw/intern/draw_cache_impl_mesh.c
source/blender/draw/modes/paint_texture_mode.c
source/blender/draw/modes/shaders/paint_texture_frag.glsl
source/blender/draw/modes/shaders/paint_texture_vert.glsl
source/blender/gpu/GPU_vertex_format.h
source/blender/makesrna/intern/rna_mesh.c

index 89972d0..c00a639 100644 (file)
@@ -237,6 +237,7 @@ typedef struct MeshRenderData {
                        MLoopUV **uv;
                        int       uv_len;
                        int       uv_active;
+                       int       uv_mask_active;
 
                        MLoopCol **vcol;
                        int        vcol_len;
@@ -389,6 +390,17 @@ static void mesh_cd_calc_active_uv_layer(
        }
 }
 
+static void mesh_cd_calc_active_mask_uv_layer(
+        const Mesh *me, ushort cd_lused[CD_NUMTYPES])
+{
+       const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
+
+       int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
+       if (layer != -1) {
+               cd_lused[CD_MLOOPUV] |= (1 << layer);
+       }
+}
+
 static void mesh_cd_calc_active_vcol_layer(
         const Mesh *me, ushort cd_lused[CD_NUMTYPES])
 {
@@ -839,6 +851,7 @@ static MeshRenderData *mesh_render_data_create_ex(
                }
 
                rdata->cd.layers.uv_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+               rdata->cd.layers.uv_mask_active = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
                rdata->cd.layers.vcol_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
                rdata->cd.layers.tangent_active = rdata->cd.layers.uv_active;
 
@@ -848,6 +861,7 @@ static MeshRenderData *mesh_render_data_create_ex(
                } ((void)0)
 
                CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_active, cd_lused[CD_MLOOPUV]);
+               CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_mask_active, cd_lused[CD_MLOOPUV]);
                CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_active, cd_lused[CD_TANGENT]);
                CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_active, cd_lused[CD_MLOOPCOL]);
 
@@ -2987,6 +3001,9 @@ static void mesh_create_loop_uv_and_tan(MeshRenderData *rdata, GPUVertBuf *vbo)
                if (i == rdata->cd.layers.uv_active) {
                        GPU_vertformat_alias_add(&format, "u");
                }
+               if (i == rdata->cd.layers.uv_mask_active) {
+                       GPU_vertformat_alias_add(&format, "mu");
+               }
        }
 
        for (uint i = 0; i < tangent_len; i++) {
@@ -3959,6 +3976,7 @@ static void texpaint_request_active_uv(MeshBatchCache *cache, Mesh *me)
                /* This should not happen. */
                BLI_assert(!"No uv layer available in texpaint, but batches requested anyway!");
        }
+       mesh_cd_calc_active_mask_uv_layer(me, cd_lneeded);
        bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_vused, cache->cd_lused,
                                                      cd_vneeded, cd_lneeded);
        if (cd_overlap == false) {
index 0a9746b..7696ce4 100644 (file)
@@ -106,6 +106,7 @@ static struct {
         * free in PAINT_TEXTURE_engine_free(); */
        struct GPUShader *fallback_sh;
        struct GPUShader *image_sh;
+       struct GPUShader *image_masking_sh;
 
        struct GPUShader *wire_overlay_shader;
        struct GPUShader *face_overlay_shader;
@@ -136,6 +137,12 @@ static void PAINT_TEXTURE_engine_init(void *UNUSED(vedata))
                        datatoc_paint_texture_frag_glsl,
                        datatoc_common_globals_lib_glsl, NULL);
 
+               e_data.image_masking_sh = DRW_shader_create_with_lib(
+                       datatoc_paint_texture_vert_glsl, NULL,
+                       datatoc_paint_texture_frag_glsl,
+                       datatoc_common_globals_lib_glsl,
+                       "#define TEXTURE_PAINT_MASK\n");
+
                e_data.wire_overlay_shader = DRW_shader_create_with_lib(
                        datatoc_paint_wire_vert_glsl, NULL,
                        datatoc_paint_wire_frag_glsl,
@@ -148,6 +155,28 @@ static void PAINT_TEXTURE_engine_init(void *UNUSED(vedata))
        }
 }
 
+static DRWShadingGroup* create_texture_paint_shading_group(PAINT_TEXTURE_PassList *psl, const struct GPUTexture *texture, const DRWContextState *draw_ctx, const bool nearest_interp)
+{
+       Scene *scene = draw_ctx->scene;
+       const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+       const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && imapaint->stencil != NULL;
+
+       DRWShadingGroup *grp = DRW_shgroup_create(masking_enabled?e_data.image_masking_sh:e_data.image_sh, psl->image_faces);
+       DRW_shgroup_uniform_texture(grp, "image", texture);
+       DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
+       DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+       DRW_shgroup_uniform_bool_copy(grp, "nearestInterp", nearest_interp);
+
+       if (masking_enabled) {
+               const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0;
+               GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D, false);
+               DRW_shgroup_uniform_texture(grp, "maskingImage", stencil);
+               DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1);
+               DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted);
+       }
+       return grp;
+}
+
 /* Here init all passes and shading groups
  * Assume that all Passes are NULL */
 static void PAINT_TEXTURE_cache_init(void *vedata)
@@ -192,15 +221,10 @@ static void PAINT_TEXTURE_cache_init(void *vedata)
                                        Material *ma = give_current_material(ob, i + 1);
                                        Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
                                        int interp = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].interp : 0;
-                                       GPUTexture *tex = ima ?
-                                               GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false) : NULL;
+                                       GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false);
 
                                        if (tex) {
-                                               DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
-                                               DRW_shgroup_uniform_texture(grp, "image", tex);
-                                               DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
-                                               DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
-                                               DRW_shgroup_uniform_bool_copy(grp, "nearestInterp", interp == SHD_INTERP_CLOSEST);
+                                               DRWShadingGroup *grp = create_texture_paint_shading_group(psl, tex, draw_ctx, interp == SHD_INTERP_CLOSEST);
                                                stl->g_data->shgroup_image_array[i] = grp;
                                        }
                                        else {
@@ -210,15 +234,10 @@ static void PAINT_TEXTURE_cache_init(void *vedata)
                        }
                        else {
                                Image *ima = imapaint->canvas;
-                               GPUTexture *tex = ima ?
-                                       GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false) : NULL;
+                               GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false);
 
                                if (tex) {
-                                       DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
-                                       DRW_shgroup_uniform_texture(grp, "image", tex);
-                                       DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
-                                       DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
-                                       DRW_shgroup_uniform_bool_copy(grp, "nearestInterp", imapaint->interp == IMAGEPAINT_INTERP_CLOSEST);
+                                       DRWShadingGroup *grp = create_texture_paint_shading_group(psl, tex, draw_ctx, imapaint->interp == IMAGEPAINT_INTERP_CLOSEST);
                                        stl->g_data->shgroup_image_array[0] = grp;
                                }
                                else {
@@ -345,6 +364,7 @@ static void PAINT_TEXTURE_draw_scene(void *vedata)
 static void PAINT_TEXTURE_engine_free(void)
 {
        DRW_SHADER_FREE_SAFE(e_data.image_sh);
+       DRW_SHADER_FREE_SAFE(e_data.image_masking_sh);
        DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
        DRW_SHADER_FREE_SAFE(e_data.face_overlay_shader);
 }
index 68fd1be..aadbf8c 100644 (file)
@@ -1,11 +1,21 @@
 
 in vec2 uv_interp;
+#ifdef TEXTURE_PAINT_MASK
+in vec2 masking_uv_interp;
+#endif
+
 out vec4 fragColor;
 
 uniform sampler2D image;
 uniform float alpha = 1.0;
 uniform bool nearestInterp;
 
+#ifdef TEXTURE_PAINT_MASK
+uniform sampler2D maskingImage;
+uniform vec3 maskingColor;
+uniform bool maskingInvertStencil;
+#endif
+
 void main()
 {
        vec2 uv = uv_interp;
@@ -13,5 +23,19 @@ void main()
                vec2 tex_size = vec2(textureSize(image, 0).xy);
                uv = (floor(uv_interp * tex_size) + 0.5) / tex_size;
        }
-       fragColor = vec4(texture(image, uv).rgb, alpha);
+
+       vec4 color = texture(image, uv);
+       color.a *= alpha;
+
+#ifdef TEXTURE_PAINT_MASK
+       vec4 mask = vec4(texture(maskingImage, masking_uv_interp).rgb, 1.0);
+       if (maskingInvertStencil) {
+               mask.rgb = 1.0 - mask.rgb;
+       }
+       float mask_step = smoothstep(0, 3.0, mask.r+mask.g+mask.b);
+       mask.rgb *= maskingColor;
+       color = mix(color, mask, mask_step);
+#endif
+
+       fragColor = color;
 }
index c53439f..43a353f 100644 (file)
@@ -5,15 +5,27 @@ uniform mat4 ModelMatrix;
 in vec2 u; /* active uv map */
 in vec3 pos;
 
+#ifdef TEXTURE_PAINT_MASK
+in vec2 mu; /* masking uv map */
+#endif
+
 out vec2 uv_interp;
 
+#ifdef TEXTURE_PAINT_MASK
+out vec2 masking_uv_interp;
+#endif
+
 void main()
 {
        gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
 
        uv_interp = u;
 
+#ifdef TEXTURE_PAINT_MASK
+       masking_uv_interp = mu;
+#endif
+
 #ifdef USE_WORLD_CLIP_PLANES
-               world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz);
+       world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz);
 #endif
 }
index 515fa54..63ff430 100644 (file)
@@ -29,7 +29,7 @@
 #include "GPU_common.h"
 
 #define GPU_VERT_ATTR_MAX_LEN 16
-#define GPU_VERT_ATTR_MAX_NAMES 3
+#define GPU_VERT_ATTR_MAX_NAMES 4
 #define GPU_VERT_ATTR_NAME_AVERAGE_LEN 11
 #define GPU_VERT_ATTR_NAMES_BUF_LEN ((GPU_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GPU_VERT_ATTR_MAX_LEN)
 
index c9a8da5..158f453 100644 (file)
@@ -2642,6 +2642,7 @@ static void rna_def_mesh(BlenderRNA *brna)
        RNA_def_property_int_funcs(prop, "rna_Mesh_uv_layer_stencil_index_get",
                                   "rna_Mesh_uv_layer_stencil_index_set", "rna_Mesh_uv_layer_index_range");
        RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index");
+       RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
 
        /* Vertex colors */