Refactor/Rewrite overlay wire colors #110097

Closed
Gilberto Rodrigues wants to merge 19 commits from Gilberto.R/blender:temp-fresnelpref into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
14 changed files with 135 additions and 119 deletions

View File

@ -120,6 +120,7 @@ const UserDef U_default = {
.gizmo_flag = USER_GIZMO_DRAW,
.gizmo_size = 75,
.gizmo_size_navigate_v3d = 80,
.fresnel_intensity = 0.4,
.edit_studio_light = 0,
.lookdev_sphere_size = 150,
.vbotimeout = 120,

View File

@ -747,6 +747,11 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
if view.mini_axis_type == 'GIZMO':
col.prop(view, "gizmo_size_navigate_v3d", text="Size")
layout.separator()
col = layout.column(heading="Fresnel")
col.prop(view, "use_fresnel_edit")
col.prop(view, "use_fresnel")
col.prop(view, "fresnel_intensity_factor")
class USERPREF_PT_viewport_quality(ViewportPanel, CenterAlignMixIn, Panel):
bl_label = "Quality"

View File

@ -6235,13 +6235,13 @@ class VIEW3D_PT_shading_lighting(Panel):
class VIEW3D_PT_shading_color(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Color"
bl_label = "Wire Color"
bl_parent_id = 'VIEW3D_PT_shading'
@classmethod
def poll(cls, context):
shading = VIEW3D_PT_shading.get_shading(context)
return shading.type in {'WIREFRAME', 'SOLID'}
return shading.type in {'WIREFRAME', 'SOLID', 'MATERIAL', 'RENDERED'}
def _draw_color_type(self, context):
layout = self.layout
@ -6261,13 +6261,19 @@ class VIEW3D_PT_shading_color(Panel):
layout.row().prop(shading, "background_color", text="")
def draw(self, context):
layout = self.layout
shading = VIEW3D_PT_shading.get_shading(context)
if shading.type == 'WIREFRAME':
self.layout.row().prop(shading, "wireframe_color_type", expand=True)
else:
self.layout.row().prop(shading, "wireframe_color_type", expand=True)
self.layout.separator()
if shading.type == 'SOLID':
layout.row().label(text="Color")
self._draw_color_type(context)
self.layout.separator()
self._draw_background_color(context)
self._draw_background_color(context)
elif shading.type == 'WIREFRAME':
self._draw_background_color(context)
class VIEW3D_PT_shading_options(Panel):

View File

@ -60,10 +60,9 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
pd->shdata.wire_opacity = pd->overlay.wireframe_opacity;
bool is_wire_shmode = (shading->type == OB_WIRE);
bool is_material_shmode = (shading->type > OB_SOLID);
bool is_object_color = is_wire_shmode && (shading->wire_color_type == V3D_SHADING_OBJECT_COLOR);
bool is_random_color = is_wire_shmode && (shading->wire_color_type == V3D_SHADING_RANDOM_COLOR);
int color_type = shading->wire_color_type;
const bool use_select = (DRW_state_is_select() || DRW_state_is_depth());
GPUShader *wires_sh = use_select ? OVERLAY_shader_wireframe_select() :
@ -95,8 +94,7 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_float_copy(grp, "wireOpacity", pd->shdata.wire_opacity);
DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
DRW_shgroup_uniform_int_copy(grp, "colorType", color_type);
DRW_shgroup_uniform_bool_copy(grp, "isHair", false);
pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);

View File

@ -15,8 +15,7 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.push_constant(Type::FLOAT, "wireOpacity")
.push_constant(Type::BOOL, "useColoring")
.push_constant(Type::BOOL, "isTransform")
.push_constant(Type::BOOL, "isObjectColor")
.push_constant(Type::BOOL, "isRandomColor")
.push_constant(Type::INT, "colorType")
.push_constant(Type::BOOL, "isHair")
.push_constant(Type::MAT4, "hairDupliMatrix")
/* Scene Depth texture copy for manual depth test. */

View File

@ -97,10 +97,11 @@ void main()
vec3 view_normal = normalize(normal_object_to_view(vnor) + 1e-4);
vec3 view_vec = (drw_view.winmat[3][3] == 0.0) ? normalize(view_pos) : vec3(0.0, 0.0, 1.0);
float facing = dot(view_vec, view_normal);
facing = 1.0 - abs(facing) * 0.2;
facing = 1.0 - abs(facing)*0.6;
/* Do interpolation in a non-linear space to have a better visual result. */
finalColor.rgb = non_linear_blend_color(colorEditMeshMiddle.rgb, finalColor.rgb, facing);
finalColor.rgb = mix(finalColor.rgb, non_linear_blend_color(colorEditMeshMiddle.rgb,
finalColor.rgb, facing), fresnelMixEdit);
#endif
view_clipping_distances(world_pos);

View File

@ -142,10 +142,10 @@ void main()
facing1 = 1.0 - abs(facing1) * 0.2;
/* Do interpolation in a non-linear space to have a better visual result. */
out_finalColor[0].rgb = non_linear_blend_color(
colorEditMeshMiddle.rgb, out_finalColor[0].rgb, facing0);
out_finalColor[1].rgb = non_linear_blend_color(
colorEditMeshMiddle.rgb, out_finalColor[1].rgb, facing1);
out_finalColor[0].rgb = mix(out_finalColor[0].rgb, non_linear_blend_color(
colorEditMeshMiddle.rgb, out_finalColor[0].rgb, facing0), fresnelMixEdit);
out_finalColor[1].rgb = mix(out_finalColor[1].rgb, non_linear_blend_color(
colorEditMeshMiddle.rgb, out_finalColor[1].rgb, facing1), fresnelMixEdit);
#endif
// -------- GEOM SHADER ALTERNATIVE ----------- //

View File

@ -6,35 +6,6 @@ bool is_edge_sharpness_visible(float wd)
return wd <= wireStepParam;
}
void wire_color_get(out vec3 rim_col, out vec3 wire_col)
{
int flag = int(abs(ObjectInfo.w));
bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0;
bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
if (is_from_set) {
rim_col = colorWire.rgb;
wire_col = colorWire.rgb;
}
else if (is_selected && useColoring) {
if (isTransform) {
rim_col = colorTransform.rgb;
}
else if (is_active) {
rim_col = colorActive.rgb;
}
else {
rim_col = colorSelect.rgb;
}
wire_col = colorWire.rgb;
}
else {
rim_col = colorWire.rgb;
wire_col = colorBackground.rgb;
}
}
vec3 hsv_to_rgb(vec3 hsv)
{
vec3 nrgb = abs(hsv.x * 6.0 - vec3(3.0, 2.0, 4.0)) * vec3(1, -1, -1) + vec3(-1, 2, 2);
@ -42,31 +13,57 @@ vec3 hsv_to_rgb(vec3 hsv)
return ((nrgb - 1.0) * hsv.y + 1.0) * hsv.z;
}
void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
vec3 wire_selected_color_get(bool is_active)
{
int flag = int(abs(ObjectInfo.w));
bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
if (isObjectColor) {
rim_col = wire_col = ObjectColor.rgb * 0.5;
vec3 wire_col;
if (isTransform) {
wire_col = colorTransform.rgb;
}
else if (is_active) {
wire_col = colorActive.rgb;
}
else {
wire_col = colorSelect.rgb;
}
return wire_col;
}
vec3 base_wire_color_get()
{
vec3 wire_col;
if (colorType == V3D_SHADING_SINGLE_COLOR) {
wire_col = colorWire.rgb;
}
else if (colorType == V3D_SHADING_RANDOM_COLOR) {
/* Dim random color. */
float hue = ObjectInfo.z;
vec3 hsv = vec3(hue, 0.75, 0.8);
rim_col = wire_col = hsv_to_rgb(hsv);
wire_col = hsv_to_rgb(hsv);
}
else /* V3D_SHADING_OBJECT_COLOR */
wire_col = ObjectColor.rgb;
return wire_col;
}
if (is_selected && useColoring) {
/* "Normalize" color. */
wire_col += 1e-4; /* Avoid division by 0. */
float brightness = max(wire_col.x, max(wire_col.y, wire_col.z));
wire_col *= 0.5 / brightness;
rim_col += 0.75;
}
else {
rim_col *= 0.5;
wire_col += 0.5;
vec3 wire_color_get(bool is_active, bool is_selected)
{
vec3 wire_col;
if (useColoring && is_selected) {
wire_col = wire_selected_color_get(is_active);
}
else
wire_col = base_wire_color_get();
return wire_col;
}
vec4 wire_fresnel_get(vec4 wire_col, float facing, bool is_selected)
{
facing = clamp(abs(facing), 0.0, 1.0);
float fresnel_alpha = mix(0.0, fresnelMix, facing);
vec3 fresnel_color = wire_col.rgb * fresnel_alpha;
wire_col.rgb = mix(wire_col.rgb, fresnel_color, fresnelMix);
wire_col.a = wireOpacity * (1 - fresnel_alpha);
return wire_col;
Gilberto.R marked this conversation as resolved Outdated

We might want to split this into multiple functions for readability.
We currently store 3 uniform bools what can due to changes in this patch be reduced
to a single int (colorType). For reference on a GPU a bool is 32 bits same as an int. Although not important for OpenGL, but when all uniforms space together are smaller then 256 bytes it can be optimized by the backend as push constants so we try to keep them as small as possible.

We should always test uniform values before local variables as these are constant in all cores of the same compute unit (for GPU hardware this can matter)

vec3 wire_color_get() {
  if (useColoring && is_selected) {\
    return wire_selection_color_get();
  }
  else if (colorType == V3D_SHADING_SINGLE_COLOR)
    ..
  }
  else if (colorType == V3D_SHADING_RANDOM_COLOR)
    ..
  } else /* V3d_SHADING_OBJECT_COLOR */ {
    ..
  }
}

The defines can be added to overlay_shader_shared.h

This part would then be reduced to

finalColor.rgb = wire_color_get();

/* Fresnel */
...
We might want to split this into multiple functions for readability. We currently store 3 uniform bools what can due to changes in this patch be reduced to a single int (colorType). For reference on a GPU a bool is 32 bits same as an int. Although not important for OpenGL, but when all uniforms space together are smaller then 256 bytes it can be optimized by the backend as push constants so we try to keep them as small as possible. We should always test uniform values before local variables as these are constant in all cores of the same compute unit (for GPU hardware this can matter) ``` vec3 wire_color_get() { if (useColoring && is_selected) {\ return wire_selection_color_get(); } else if (colorType == V3D_SHADING_SINGLE_COLOR) .. } else if (colorType == V3D_SHADING_RANDOM_COLOR) .. } else /* V3d_SHADING_OBJECT_COLOR */ { .. } } ``` The defines can be added to `overlay_shader_shared.h` This part would then be reduced to ``` finalColor.rgb = wire_color_get(); /* Fresnel */ ... ```
}
void main()
@ -107,25 +104,10 @@ void main()
#ifndef SELECT_EDGES
edgePos = edgeStart;
vec3 rim_col, wire_col;
if (isObjectColor || isRandomColor) {
wire_object_color_get(rim_col, wire_col);
}
else {
wire_color_get(rim_col, wire_col);
}
facing = clamp(abs(facing), 0.0, 1.0);
/* Do interpolation in a non-linear space to have a better visual result. */
rim_col = pow(rim_col, vec3(1.0 / 2.2));
wire_col = pow(wire_col, vec3(1.0 / 2.2));
vec3 final_front_col = mix(rim_col, wire_col, 0.35);
finalColor.rgb = mix(rim_col, final_front_col, facing);
finalColor.rgb = pow(finalColor.rgb, vec3(2.2));
finalColor.a = wireOpacity;
finalColor.rgb *= wireOpacity;
#else
/* HACK: to avoid losing sub-pixel object in selections, we add a bit of randomness to the
* wire to at least create one fragment that will pass the occlusion query. */
gl_Position.xy += sizeViewportInv * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0);
#endif
/* Cull flat edges below threshold. */
@ -133,11 +115,17 @@ void main()
edgeStart = vec2(-1.0);
}
#ifdef SELECT_EDGES
/* HACK: to avoid losing sub-pixel object in selections, we add a bit of randomness to the
* wire to at least create one fragment that will pass the occlusion query. */
gl_Position.xy += sizeViewportInv * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0);
#endif
/* Wire Color */
int flag = int(abs(ObjectInfo.w));
bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
finalColor.rgb = wire_color_get(is_active, is_selected);
/* Fresnel */
finalColor = wire_fresnel_get(finalColor, facing, is_selected);
finalColor.rgb *= wireOpacity;
view_clipping_distances(wpos);
}

View File

@ -82,6 +82,8 @@ void DRW_globals_update(void)
UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, gb->color_checker_primary);
UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, gb->color_checker_secondary);
gb->size_checker = UI_GetThemeValuef(TH_TRANSPARENT_CHECKER_SIZE);
gb->fresnel_mix_edit = ((U.gpu_flag & USER_GPU_FLAG_FRESNEL_EDIT) == 0 ) ? 0.0 : U.fresnel_intensity;
gb->fresnel_mix = ((U.gpu_flag & USER_GPU_FLAG_FRESNEL) == 0 ) ? 0.0 : U.fresnel_intensity;
UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, gb->color_clipping_border);
/* Custom median color to slightly affect the edit mesh colors. */

View File

@ -134,6 +134,9 @@ struct GlobalsUboStorage {
float size_vertex, size_edge, size_edge_fix, size_face_dot;
float size_checker;
float size_vertex_gpencil;
float fresnel_mix_edit;
float fresnel_mix;
float _pad[2];
Gilberto.R marked this conversation as resolved Outdated

typo

typo
};
BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16)
@ -244,6 +247,8 @@ BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16)
# define sizeFaceDot globalsBlock.size_face_dot
# define sizeChecker globalsBlock.size_checker
# define sizeVertexGpencil globalsBlock.size_vertex_gpencil
# define fresnelMixEdit globalsBlock.fresnel_mix_edit
# define fresnelMix globalsBlock.fresnel_mix
#endif
/* See: 'draw_cache_impl.h' for matching includes. */

View File

@ -291,6 +291,9 @@ float get_homogenous_z_offset(float vs_z, float hs_w, float vs_offset)
#define DRW_BASE_FROM_SET (1 << 3)
#define DRW_BASE_ACTIVE (1 << 4)
#define V3D_SHADING_RANDOM_COLOR 1
#define V3D_SHADING_SINGLE_COLOR 2
/* ---- Opengl Depth conversion ---- */
float linear_depth(bool is_persp, float z, float zf, float zn)

View File

@ -993,6 +993,10 @@ typedef struct UserDef {
struct WalkNavigation walk_navigation;
/** Fresnel */
float fresnel_intensity;
char _pad[4];
/** The UI for the user preferences. */
UserDef_SpaceData space_data;
UserDef_FileSpaceData file_space_data;
@ -1187,6 +1191,8 @@ typedef enum eUserpref_GPU_Flag {
USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE = (1 << 1),
USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE = (1 << 2),
USER_GPU_FLAG_SUBDIVISION_EVALUATION = (1 << 3),
USER_GPU_FLAG_FRESNEL_EDIT = (1 << 4),
USER_GPU_FLAG_FRESNEL = (1 << 5),
} eUserpref_GPU_Flag;
/** #UserDef.tablet_api */

View File

@ -438,6 +438,13 @@ static const EnumPropertyItem rna_enum_shading_color_type_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem rna_enum_shading_wire_color_type_items[] = {
{V3D_SHADING_SINGLE_COLOR, "THEME", 0, "Theme", "Show scene wireframes with the theme's wire color"},
{V3D_SHADING_OBJECT_COLOR, "OBJECT", 0, "Object", "Show object color on wireframe"},
{V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color on wireframe"},
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem rna_enum_studio_light_items[] = {
{0, "DEFAULT", 0, "Default", ""},
{0, nullptr, 0, nullptr, nullptr},
@ -1304,33 +1311,7 @@ static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr)
}
/* shading.light */
static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext * /*C*/,
PointerRNA *ptr,
PropertyRNA * /*prop*/,
bool *r_free)
{
View3DShading *shading = (View3DShading *)ptr->data;
int totitem = 0;
if (shading->type == OB_WIRE) {
EnumPropertyItem *item = nullptr;
RNA_enum_items_add_value(
&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_SINGLE_COLOR);
RNA_enum_items_add_value(
&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_OBJECT_COLOR);
RNA_enum_items_add_value(
&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_RANDOM_COLOR);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
else {
/* Solid mode, or lookdev mode for workbench engine. */
*r_free = false;
return rna_enum_shading_color_type_items;
}
}
static void rna_View3DShading_studio_light_get_storage(View3DShading *shading,
char **dna_storage,
@ -4168,7 +4149,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "color_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "color_type");
RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "rna_View3DShading_color_type_itemf");
RNA_def_property_ui_text(prop, "Color", "Color Type");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(
@ -4176,9 +4156,8 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "wireframe_color_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "wire_color_type");
RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "rna_View3DShading_color_type_itemf");
RNA_def_property_ui_text(prop, "Color", "Color Type");
RNA_def_property_enum_items(prop, rna_enum_shading_wire_color_type_items);
RNA_def_property_ui_text(prop, "Wire Color", "Wire Color Type");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, nullptr);
prop = RNA_def_property(srna, "single_color", PROP_FLOAT, PROP_COLOR);

View File

@ -4694,6 +4694,29 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"overlay while animation is played back");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "use_fresnel_edit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "gpu_flag", USER_GPU_FLAG_FRESNEL_EDIT);
RNA_def_property_ui_text(prop,
"Edit Mode",
"Enable a fresnel effect on edit mesh overlays.\n"
"It improves a bit the shape readability of very dense meshes, "
"but increases eye fatigue when modeling lower poly");
RNA_def_property_update(prop, 0, "rna_userdef_gpu_update");
prop = RNA_def_property(srna, "use_fresnel", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "gpu_flag", USER_GPU_FLAG_FRESNEL);
RNA_def_property_ui_text(prop,
"Other Modes",
"Enable a fresnel effect on wireframes.\n"
"It improves the shape readability of very dense meshes");
RNA_def_property_update(prop, 0, "rna_userdef_gpu_update");
prop = RNA_def_property(srna, "fresnel_intensity_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, nullptr, "fresnel_intensity");
RNA_def_property_ui_text(prop, "Fresnel Intensity", "Intensity of wireframe fresnel");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_update(prop, 0, "rna_userdef_gpu_update");
USERDEF_TAG_DIRTY_PROPERTY_UPDATE_DISABLE;
prop = RNA_def_property(srna, "show_addons_enabled_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(