DRW: New High Quality Normal & Tangent extract

This patch adds a dedicated path to extract 16bit normals instead of packing them into 10bits/comp.
The tangents are also packed to 10bits/comp if not using the new High Quality Normal option.

Fix T61024 Degraded texture shading on dense meshes

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6614
This commit is contained in:
Clément Foucault 2020-02-19 01:44:52 +01:00
parent 77619f5274
commit e82827bf6e
Notes: blender-bot 2023-02-14 03:53:58 +01:00
Referenced by commit 4fd005fefb, Fix T76131: Crash combing Hair using Python
Referenced by issue #76131, Reproducable Crash in Blender 2.83 Beta: Combing Hair using Python
Referenced by issue #61024, Degraded texture shading on dense meshes
6 changed files with 216 additions and 14 deletions

View File

@ -524,6 +524,25 @@ class RENDER_PT_eevee_hair(RenderButtonsPanel, Panel):
layout.prop(rd, "hair_subdiv")
class RENDER_PT_eevee_performance(RenderButtonsPanel, Panel):
bl_label = "Performance"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
return (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
layout.use_property_split = True
layout.prop(rd, "use_high_quality_normals")
class RENDER_PT_opengl_sampling(RenderButtonsPanel, Panel):
bl_label = "Sampling"
COMPAT_ENGINES = {'BLENDER_WORKBENCH'}
@ -674,6 +693,7 @@ classes = (
RENDER_PT_eevee_volumetric,
RENDER_PT_eevee_volumetric_lighting,
RENDER_PT_eevee_volumetric_shadows,
RENDER_PT_eevee_performance,
RENDER_PT_eevee_hair,
RENDER_PT_eevee_shadows,
RENDER_PT_eevee_indirect_lighting,

View File

@ -253,6 +253,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
const bool do_uvedit,
const bool use_subsurf_fdots,
const DRW_MeshCDMask *cd_layer_used,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide);

View File

@ -1579,6 +1579,81 @@ static const MeshExtract extract_pos_nor = {
};
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract HQ Loop Normal
* \{ */
typedef struct gpuHQNor {
short x, y, z, w;
} gpuHQNor;
static void *extract_lnor_hq_init(const MeshRenderData *mr, void *buf)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "lnor");
}
GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
return vbo->data;
}
static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data)
{
if (mr->loop_normals) {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]);
}
else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->v->no);
}
else {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->f->no);
}
}
static void extract_lnor_hq_loop_mesh(
const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data)
{
if (mr->loop_normals) {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]);
}
else if (mpoly->flag & ME_SMOOTH) {
copy_v3_v3_short(&((gpuHQNor *)data)[l].x, mr->mvert[mloop->v].no);
}
else {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->poly_normals[p]);
}
/* Flag for paint mode overlay. */
if (mpoly->flag & ME_HIDE) {
((gpuHQNor *)data)[l].w = -1;
}
else if (mpoly->flag & ME_FACE_SEL) {
((gpuHQNor *)data)[l].w = 1;
}
else {
((gpuHQNor *)data)[l].w = 0;
}
}
static const MeshExtract extract_lnor_hq = {
extract_lnor_hq_init,
NULL,
NULL,
extract_lnor_hq_loop_bmesh,
extract_lnor_hq_loop_mesh,
NULL,
NULL,
NULL,
NULL,
NULL,
MR_DATA_LOOP_NOR,
true,
};
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract Loop Normal
* \{ */
@ -1762,8 +1837,11 @@ static const MeshExtract extract_uv = {
/** \name Extract Tangent layers
* \{ */
static void *extract_tan_init(const MeshRenderData *mr, void *buf)
static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool do_hq)
{
GPUVertCompType comp_type = do_hq ? GPU_COMP_F32 : GPU_COMP_I10;
GPUVertFetchMode fetch_mode = do_hq ? GPU_FETCH_FLOAT : GPU_FETCH_INT_TO_FLOAT_UNIT;
GPUVertFormat format = {0};
GPU_vertformat_deinterleave(&format);
@ -1784,7 +1862,7 @@ static void *extract_tan_init(const MeshRenderData *mr, void *buf)
GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
/* Tangent layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
/* Active render layer name. */
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
GPU_vertformat_alias_add(&format, "t");
@ -1860,7 +1938,7 @@ static void *extract_tan_init(const MeshRenderData *mr, void *buf)
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_TANGENT, 0);
GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
GPU_vertformat_alias_add(&format, "t");
GPU_vertformat_alias_add(&format, "at");
}
@ -1876,23 +1954,56 @@ static void *extract_tan_init(const MeshRenderData *mr, void *buf)
v_len = 1;
}
GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, v_len);
float(*tan_data)[4] = (float(*)[4])vbo->data;
for (int i = 0; i < tan_len; i++) {
void *layer_data = CustomData_get_layer_named(cd_ldata, CD_TANGENT, tangent_names[i]);
memcpy(tan_data, layer_data, sizeof(*tan_data) * mr->loop_len);
tan_data += mr->loop_len;
if (do_hq) {
short(*tan_data)[4] = (short(*)[4])vbo->data;
for (int i = 0; i < tan_len; i++) {
const char *name = tangent_names[i];
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name);
for (int l = 0; l < mr->loop_len; l++) {
normal_float_to_short_v3(*tan_data, layer_data[l]);
(*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
tan_data++;
}
}
if (use_orco_tan) {
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0);
for (int l = 0; l < mr->loop_len; l++) {
normal_float_to_short_v3(*tan_data, layer_data[l]);
(*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
tan_data++;
}
}
}
if (use_orco_tan) {
void *layer_data = CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0);
memcpy(tan_data, layer_data, sizeof(*tan_data) * mr->loop_len);
else {
GPUPackedNormal *tan_data = (GPUPackedNormal *)vbo->data;
for (int i = 0; i < tan_len; i++) {
const char *name = tangent_names[i];
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name);
for (int l = 0; l < mr->loop_len; l++) {
*tan_data = GPU_normal_convert_i10_v3(layer_data[l]);
tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2;
tan_data++;
}
}
if (use_orco_tan) {
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0);
for (int l = 0; l < mr->loop_len; l++) {
*tan_data = GPU_normal_convert_i10_v3(layer_data[l]);
tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2;
tan_data++;
}
}
}
CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len);
}
static void *extract_tan_init(const MeshRenderData *mr, void *buf)
{
extract_tan_ex(mr, buf, false);
return NULL;
}
@ -1913,6 +2024,33 @@ static const MeshExtract extract_tan = {
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract HQ Tangent layers
* \{ */
static void *extract_tan_hq_init(const MeshRenderData *mr, void *buf)
{
extract_tan_ex(mr, buf, true);
return NULL;
}
static const MeshExtract extract_tan_hq = {
extract_tan_hq_init,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
false,
};
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract VCol
* \{ */
@ -4354,11 +4492,20 @@ static void extract_range_task_create(
}
static void extract_task_create(TaskPool *task_pool,
const Scene *scene,
const MeshRenderData *mr,
const MeshExtract *extract,
void *buf,
int32_t *task_counter)
{
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0;
if (do_hq_normals && (extract == &extract_lnor)) {
extract = &extract_lnor_hq;
}
if (do_hq_normals && (extract == &extract_tan)) {
extract = &extract_tan_hq;
}
/* Divide extraction of the VBO/IBO into sensible chunks of works. */
ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData");
taskdata->mr = mr;
@ -4419,6 +4566,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
const bool do_uvedit,
const bool use_subsurf_fdots,
const DRW_MeshCDMask *cd_layer_used,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide)
{
@ -4498,7 +4646,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
#define EXTRACT(buf, name) \
if (mbc.buf.name) { \
extract_task_create( \
task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
task_pool, scene, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
} \
((void)0)

View File

@ -1341,6 +1341,7 @@ void DRW_mesh_batch_cache_create_requested(
true,
false,
&cache->cd_used,
scene,
ts,
true);
}
@ -1355,6 +1356,7 @@ void DRW_mesh_batch_cache_create_requested(
false,
use_subsurf_fdots,
&cache->cd_used,
scene,
ts,
true);
}
@ -1368,6 +1370,7 @@ void DRW_mesh_batch_cache_create_requested(
false,
use_subsurf_fdots,
&cache->cd_used,
scene,
ts,
use_hide);

View File

@ -750,7 +750,10 @@ typedef struct RenderData {
/* render engine */
char engine[32];
char _pad2[4];
char _pad2[2];
/* Performance Options */
short perf_flag;
/* Cycles baking */
struct BakeData bake;
@ -776,6 +779,11 @@ typedef struct RenderData {
struct CurveMapping mblur_shutter_curve;
} RenderData;
/* RenderData.quality_flag */
typedef enum eQualityOption {
SCE_PERF_HQ_NORMALS = (1 << 0),
} eQualityOption;
/* RenderData.hair_type */
typedef enum eHairType {
SCE_HAIR_SHAPE_STRAND = 0,

View File

@ -1654,6 +1654,20 @@ static void rna_Scene_world_update(Main *bmain, Scene *scene, PointerRNA *ptr)
DEG_relations_tag_update(bmain);
}
static void rna_Scene_mesh_quality_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
if (ob->type == OB_MESH) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
}
FOREACH_SCENE_OBJECT_END;
rna_Scene_glsl_update(bmain, scene, ptr);
}
void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
@ -5762,6 +5776,14 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Additional Subdiv", "Additional subdivision along the hair");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
/* Performance */
prop = RNA_def_property(srna, "use_high_quality_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "perf_flag", SCE_PERF_HQ_NORMALS);
RNA_def_property_ui_text(prop,
"High Quality Normals",
"Use high quality tangent space at the cost of lower performance");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_mesh_quality_update");
/* border */
prop = RNA_def_property(srna, "use_border", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_BORDER);