Workbench: Sculpt fixes

* Fix #112284 and other non-reported sculpt-related regressions in the
   new Workbench.
* Cleanup ObjectState setup.
* Update `sculpt_batches_get` to support getting per material batches
   while passing SculptBatchFeatures.
* Make material indices 0 based in Workbench.

Pull Request: https://projects.blender.org/blender/blender/pulls/112344
This commit is contained in:
Miguel Pozo
2023-09-13 22:36:37 +02:00
parent 27c8dd89e3
commit f42b02cccc
6 changed files with 66 additions and 94 deletions
@@ -107,7 +107,7 @@ class Instance {
case V3D_SHADING_TEXTURE_COLOR:
ATTR_FALLTHROUGH;
case V3D_SHADING_MATERIAL_COLOR:
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot)) {
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot + 1)) {
return Material(*_mat);
}
ATTR_FALLTHROUGH;
@@ -271,8 +271,7 @@ class Instance {
continue;
}
/* Material slots start from 1. */
int material_slot = i + 1;
int material_slot = i;
Material mat = get_material(ob_ref, object_state.color_type, material_slot);
has_transparent_material = has_transparent_material || mat.is_transparent();
@@ -324,11 +323,16 @@ class Instance {
void sculpt_sync(ObjectRef &ob_ref, ResourceHandle handle, const ObjectState &object_state)
{
SculptBatchFeature features = SCULPT_BATCH_DEFAULT;
if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) {
features = SCULPT_BATCH_VERTEX_COLOR;
}
else if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
features = SCULPT_BATCH_UV;
}
if (object_state.use_per_material_batches) {
const int material_count = DRW_cache_object_material_count_get(ob_ref.object);
for (SculptBatch &batch : sculpt_batches_per_material_get(
ob_ref.object, {get_dummy_gpu_materials(material_count), material_count}))
{
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, true, features)) {
Material mat = get_material(ob_ref, object_state.color_type, batch.material_slot);
if (SCULPT_DEBUG_DRAW) {
mat.base_color = batch.debug_color();
@@ -346,15 +350,7 @@ class Instance {
}
else {
Material mat = get_material(ob_ref, object_state.color_type);
SculptBatchFeature features = SCULPT_BATCH_DEFAULT;
if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) {
features = SCULPT_BATCH_VERTEX_COLOR;
}
else if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
features = SCULPT_BATCH_UV;
}
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, features)) {
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, false, features)) {
if (SCULPT_DEBUG_DRAW) {
mat.base_color = batch.debug_color();
}
@@ -395,12 +391,12 @@ class Instance {
/* Skip frustum culling. */
ResourceHandle handle = manager.resource_handle(float4x4(ob_ref.object->object_to_world));
Material mat = get_material(ob_ref, object_state.color_type, psys->part->omat);
Material mat = get_material(ob_ref, object_state.color_type, psys->part->omat - 1);
::Image *image = nullptr;
ImageUser *iuser = nullptr;
GPUSamplerState sampler_state = GPUSamplerState::default_sampler();
if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
get_material_image(ob_ref.object, psys->part->omat, image, iuser, sampler_state);
get_material_image(ob_ref.object, psys->part->omat - 1, image, iuser, sampler_state);
}
resources.material_buf.append(mat);
int material_index = resources.material_buf.size() - 1;
@@ -68,7 +68,7 @@ void get_material_image(Object *ob,
{
const ::bNode *node = nullptr;
ED_object_get_active_image(ob, material_slot, &image, &iuser, &node, nullptr);
ED_object_get_active_image(ob, material_slot + 1, &image, &iuser, &node, nullptr);
if (node && image) {
switch (node->type) {
case SH_NODE_TEX_IMAGE: {
@@ -107,7 +107,6 @@ struct SceneState {
struct ObjectState {
eV3DShadingColorType color_type = V3D_SHADING_SINGLE_COLOR;
bool sculpt_pbvh = false;
bool texture_paint_mode = false;
::Image *image_paint_override = nullptr;
GPUSamplerState override_sampler_state = GPUSamplerState::default_sampler();
bool draw_shadow = false;
@@ -197,32 +197,42 @@ static const CustomData *get_vert_custom_data(const Mesh *mesh)
ObjectState::ObjectState(const SceneState &scene_state, Object *ob)
{
sculpt_pbvh = false;
texture_paint_mode = false;
image_paint_override = nullptr;
override_sampler_state = GPUSamplerState::default_sampler();
draw_shadow = false;
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool is_active = (ob == draw_ctx->obact);
/* TODO(@pragma37): Is the double check needed?
* If it is, wouldn't be needed for sculpt_pbvh too? */
const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == nullptr);
color_type = (eV3DShadingColorType)scene_state.shading.color_type;
if (!(is_active && DRW_object_use_hide_faces(ob))) {
draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && scene_state.draw_shadows;
}
image_paint_override = nullptr;
override_sampler_state = GPUSamplerState::default_sampler();
sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) &&
!DRW_state_is_image_render();
draw_shadow = scene_state.draw_shadows && (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 &&
!is_active && !sculpt_pbvh && !DRW_object_use_hide_faces(ob);
color_type = (eV3DShadingColorType)scene_state.shading.color_type;
bool has_color = false;
bool has_uv = false;
if (ob->type == OB_MESH) {
const Mesh *me = static_cast<Mesh *>(ob->data);
const CustomData *cd_vdata = get_vert_custom_data(me);
const CustomData *cd_ldata = get_loop_custom_data(me);
has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
has_uv = CustomData_has_layer(cd_ldata, CD_PROP_FLOAT2);
}
if (color_type == V3D_SHADING_TEXTURE_COLOR && (!has_uv || ob->dt < OB_TEXTURE)) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
else if (color_type == V3D_SHADING_VERTEX_COLOR && !has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
if (sculpt_pbvh) {
/* Shadows are unsupported in sculpt mode. We could revert to the slow
* method in this case but I'm not sure if it's a good idea given that
* sculpted meshes are heavy to begin with. */
draw_shadow = false;
if (color_type == V3D_SHADING_TEXTURE_COLOR && BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
/* Force use of material color for sculpt. */
color_type = V3D_SHADING_MATERIAL_COLOR;
@@ -236,59 +246,25 @@ ObjectState::ObjectState(const SceneState &scene_state, Object *ob)
C, &scene_state.scene->toolsettings->paint_mode, ob, color_type);
}
}
else if (ob->type == OB_MESH) {
const Mesh *me = static_cast<Mesh *>(ob->data);
const CustomData *cd_vdata = get_vert_custom_data(me);
const CustomData *cd_ldata = get_loop_custom_data(me);
bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
bool has_uv = CustomData_has_layer(cd_ldata, CD_PROP_FLOAT2);
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
if (ob->dt < OB_TEXTURE || !has_uv) {
color_type = V3D_SHADING_MATERIAL_COLOR;
else if (ob->type == OB_MESH && !DRW_state_is_scene_render()) {
/* Force texture or vertex mode if object is in paint mode. */
const bool is_vertpaint_mode = is_active && (scene_state.object_mode == CTX_MODE_PAINT_VERTEX);
const bool is_texpaint_mode = is_active && (scene_state.object_mode == CTX_MODE_PAINT_TEXTURE);
if (is_vertpaint_mode && has_color) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
else if (is_texpaint_mode && has_uv) {
color_type = V3D_SHADING_TEXTURE_COLOR;
const ImagePaintSettings *imapaint = &scene_state.scene->toolsettings->imapaint;
if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
image_paint_override = imapaint->canvas;
override_sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
override_sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
const bool use_linear_filter = imapaint->interp == IMAGEPAINT_INTERP_LINEAR;
override_sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR,
use_linear_filter);
}
}
else if (color_type == V3D_SHADING_VERTEX_COLOR && !has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
if (!is_render) {
/* Force texture or vertex mode if object is in paint mode. */
const bool is_vertpaint_mode = is_active &&
(scene_state.object_mode == CTX_MODE_PAINT_VERTEX);
const bool is_texpaint_mode = is_active &&
(scene_state.object_mode == CTX_MODE_PAINT_TEXTURE);
if (is_vertpaint_mode && has_color) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
else if (is_texpaint_mode && has_uv) {
color_type = V3D_SHADING_TEXTURE_COLOR;
texture_paint_mode = true;
const ImagePaintSettings *imapaint = &scene_state.scene->toolsettings->imapaint;
if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
image_paint_override = imapaint->canvas;
override_sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
override_sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
const bool use_linear_filter = imapaint->interp == IMAGEPAINT_INTERP_LINEAR;
override_sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR,
use_linear_filter);
}
}
}
}
else {
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
else if (color_type == V3D_SHADING_VERTEX_COLOR) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
}
use_per_material_batches = image_paint_override == nullptr && ELEM(color_type,
+3 -2
View File
@@ -152,7 +152,7 @@ static Vector<SculptBatch> sculpt_batches_get_ex(
return data.batches;
}
Vector<SculptBatch> sculpt_batches_get(Object *ob, SculptBatchFeature features)
Vector<SculptBatch> sculpt_batches_get(Object *ob, bool per_material, SculptBatchFeature features)
{
PBVHAttrReq attrs[16] = {};
int attrs_len = 0;
@@ -193,7 +193,8 @@ Vector<SculptBatch> sculpt_batches_get(Object *ob, SculptBatchFeature features)
}
}
return sculpt_batches_get_ex(ob, features & SCULPT_BATCH_WIREFRAME, false, attrs, attrs_len);
return sculpt_batches_get_ex(
ob, features & SCULPT_BATCH_WIREFRAME, per_material, attrs, attrs_len);
}
Vector<SculptBatch> sculpt_batches_per_material_get(Object *ob,
+2 -2
View File
@@ -32,9 +32,9 @@ enum SculptBatchFeature {
ENUM_OPERATORS(SculptBatchFeature, SCULPT_BATCH_UV);
/** Used by engines that don't use GPUMaterials, like the Workbench and Overlay engines. */
Vector<SculptBatch> sculpt_batches_get(Object *ob, SculptBatchFeature features);
Vector<SculptBatch> sculpt_batches_get(Object *ob, bool per_material, SculptBatchFeature features);
/** Used by EEVEE and Workbench Material/Texture modes. */
/** Used by EEVEE. */
Vector<SculptBatch> sculpt_batches_per_material_get(Object *ob,
MutableSpan<GPUMaterial *> materials);