Viewport: draw light icons using the light colors #105236

Closed
Weizhen Huang wants to merge 5 commits from weizhen:colorful_light_icon into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
7 changed files with 122 additions and 46 deletions

View File

@ -6376,6 +6376,9 @@ class VIEW3D_PT_overlay_object(Panel):
sub = split.column(align=True)
sub.prop(overlay, "show_extras", text="Extras")
subsub = sub.column()
subsub.active = overlay.show_extras
subsub.prop(overlay, "show_light_colors")
sub.prop(overlay, "show_relationship_lines")
sub.prop(overlay, "show_outline_selected")

View File

@ -123,6 +123,9 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
cb->field_tube_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_tube_limit_get());
cb->field_vortex = BUF_INSTANCE(grp_sub, format, DRW_cache_field_vortex_get());
cb->field_wind = BUF_INSTANCE(grp_sub, format, DRW_cache_field_wind_get());
cb->light_icon_inner = BUF_INSTANCE(grp_sub, format, DRW_cache_light_icon_inner_lines_get());
cb->light_icon_outer = BUF_INSTANCE(grp_sub, format, DRW_cache_light_icon_outer_lines_get());
cb->light_icon_sun_rays = BUF_INSTANCE(grp_sub, format, DRW_cache_light_icon_sun_rays_get());
cb->light_area[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_disk_lines_get());
cb->light_area[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_square_lines_get());
cb->light_point = BUF_INSTANCE(grp_sub, format, DRW_cache_light_point_lines_get());
@ -605,8 +608,9 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
Light *la = static_cast<Light *>(ob->data);
float *color_p;
DRW_object_wire_theme_get(ob, view_layer, &color_p);
/* Remove the alpha. */
float color[4] = {UNPACK3(color_p), 1.0f};
float theme_color[4] = {UNPACK3(color_p), 1.0f};
/* Pack render data into object matrix. */
union {
float mat[4][4];
@ -636,12 +640,25 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
DRW_buffer_add_entry(cb->groundline, instdata.pos);
float light_color[4] = {1.0f};
const bool show_light_colors = vedata->stl->pd->overlay.flag & V3D_OVERLAY_SHOW_LIGHT_COLORS;
if (show_light_colors) {
copy_v3_v3(light_color, &la->r);

I am unsure about using the light color as is. I think it should be normalized.

For instance, a light with color (0.0, 0.01, 0.0) at really high power will still give a powerful green.

I am unsure about using the light color as is. I think it should be normalized. For instance, a light with color `(0.0, 0.01, 0.0)` at really high power will still give a powerful green.
Review

Not sure about getting into such details, because different light types with the same power could have quite different perceptual strength, it also depends on the size/radius and the spread of the light, a lot of things need to be considered.. we could do this in another commit if needed.

Not sure about getting into such details, because different light types with the same power could have quite different perceptual strength, it also depends on the size/radius and the spread of the light, a lot of things need to be considered.. we could do this in another commit if needed.

Maybe there is a misunderstanding: I'm not asking about taking light perceptual intensity into account, I'm saying that the color should be normalized as it is the "tint" we are interested in for display. Having a nearly black light overlay makes zero sense to me.

I'm just asking to replace copy_v3_v3(light_color, &la->r); by normalize_v3_v3(light_color, &la->r);.

Maybe there is a misunderstanding: I'm not asking about taking light perceptual intensity into account, I'm saying that the color should be normalized as it is the "tint" we are interested in for display. Having a nearly black light overlay makes zero sense to me. I'm just asking to replace `copy_v3_v3(light_color, &la->r);` by `normalize_v3_v3(light_color, &la->r);`.
Review

For the record: Today I discussed this with @weizhen and @fclem and we decided to go with the non-normalized display for the time being. If many users struggle to find their lights, we can still look into normalization (or other ways to make the overlay more visible).

For the record: Today I discussed this with @weizhen and @fclem and we decided to go with the non-normalized display for the time being. If many users struggle to find their lights, we can still look into normalization (or other ways to make the overlay more visible).
}
weizhen marked this conversation as resolved
Review

In drawing (where performance matters) we don't use RNA. You can just read the data directly from the la.

In drawing (where performance matters) we don't use RNA. You can just read the data directly from the `la`.
/* Draw the outer ring of the light icon and the sun rays in `light_color`, if required. */
DRW_buffer_add_entry(
cb->light_icon_outer, show_light_colors ? light_color : theme_color, &instdata);
DRW_buffer_add_entry(cb->light_icon_inner, theme_color, &instdata);
if (la->type == LA_LOCAL) {
instdata.area_size_x = instdata.area_size_y = la->radius;
DRW_buffer_add_entry(cb->light_point, color, &instdata);
DRW_buffer_add_entry(cb->light_point, theme_color, &instdata);
}
else if (la->type == LA_SUN) {
DRW_buffer_add_entry(cb->light_sun, color, &instdata);
DRW_buffer_add_entry(cb->light_sun, theme_color, &instdata);
DRW_buffer_add_entry(
cb->light_icon_sun_rays, show_light_colors ? light_color : theme_color, &instdata);
}
else if (la->type == LA_SPOT) {
/* Previous implementation was using the clip-end distance as cone size.
@ -664,8 +681,8 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
instdata.spot_blend = sqrtf((a2 - a2 * c2) / (c2 - a2 * c2));
instdata.spot_cosine = a;
/* HACK: We pack the area size in alpha color. This is decoded by the shader. */
color[3] = -max_ff(la->radius, FLT_MIN);
DRW_buffer_add_entry(cb->light_spot, color, &instdata);
theme_color[3] = -max_ff(la->radius, FLT_MIN);
DRW_buffer_add_entry(cb->light_spot, theme_color, &instdata);
if ((la->mode & LA_SHOW_CONE) && !DRW_state_is_select()) {
const float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f};
@ -679,7 +696,7 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
int sqr = ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_RECT);
instdata.area_size_x = la->area_size;
instdata.area_size_y = uniform_scale ? la->area_size : la->area_sizey;
DRW_buffer_add_entry(cb->light_area[sqr], color, &instdata);
DRW_buffer_add_entry(cb->light_area[sqr], theme_color, &instdata);
}
}

View File

@ -178,6 +178,9 @@ typedef struct OVERLAY_ExtraCallBuffers {
DRWCallBuffer *groundline;
DRWCallBuffer *light_icon_inner;
Review

I know this is just a WIP ticket and you can apply these changes whenever it's appropriate.

perhaps light_center should be a better description. (also for the other related methods).

I know this is just a WIP ticket and you can apply these changes whenever it's appropriate. perhaps `light_center` should be a better description. (also for the other related methods).
Review

I am following the comment I deleted for drawing the part, it was /* Light Icon */. Now we draw the inner circles and the outer circle separately, it's weird to call all of them "center". If "icon" is not a good name, I could probably change them to DRW_cache_light_inner_circles_get(), DRW_cache_light_outer_circle_get()? Then I will also adjust it in the commit message.

I am following the comment I deleted for drawing the part, it was `/* Light Icon */`. Now we draw the inner circles and the outer circle separately, it's weird to call all of them "center". If "icon" is not a good name, I could probably change them to `DRW_cache_light_inner_circles_get()`, `DRW_cache_light_outer_circle_get()`? Then I will also adjust it in the commit message.
DRWCallBuffer *light_icon_outer;
DRWCallBuffer *light_icon_sun_rays;
DRWCallBuffer *light_point;
DRWCallBuffer *light_sun;
DRWCallBuffer *light_spot;

View File

@ -116,6 +116,9 @@ static struct DRWShapeCache {
GPUBatch *drw_field_cone_limit;
GPUBatch *drw_field_sphere_limit;
GPUBatch *drw_ground_line;
GPUBatch *drw_light_icon_inner_lines;
GPUBatch *drw_light_icon_outer_lines;
GPUBatch *drw_light_icon_sun_rays;
GPUBatch *drw_light_point_lines;
GPUBatch *drw_light_sun_lines;
GPUBatch *drw_light_spot_lines;
@ -1461,21 +1464,90 @@ GPUBatch *DRW_cache_groundline_get(void)
return SHC.drw_ground_line;
}
GPUBatch *DRW_cache_light_point_lines_get(void)
GPUBatch *DRW_cache_light_icon_inner_lines_get(void)
{
if (!SHC.drw_light_point_lines) {
if (!SHC.drw_light_icon_inner_lines) {
GPUVertFormat format = extra_vert_format();
int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS + OUTER_NSEGMENTS + CIRCLE_NSEGMENTS);
int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
/* Light Icon */
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
SHC.drw_light_icon_inner_lines = GPU_batch_create_ex(
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_light_icon_inner_lines;
}
GPUBatch *DRW_cache_light_icon_outer_lines_get(void)
{
if (!SHC.drw_light_icon_outer_lines) {
GPUVertFormat format = extra_vert_format();
int v_len = 2 * OUTER_NSEGMENTS;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
SHC.drw_light_icon_outer_lines = GPU_batch_create_ex(
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_light_icon_outer_lines;
}
GPUBatch *DRW_cache_light_icon_sun_rays_get(void)
{
if (!SHC.drw_light_icon_sun_rays) {
GPUVertFormat format = extra_vert_format();
const int num_rays = 8;
int v_len = 4 * num_rays;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
/* Sun Rays */
for (int a = 0; a < num_rays; a++) {
float angle = (2.0f * M_PI * a) / (float)num_rays;
float s = sinf(angle) * r;
float c = cosf(angle) * r;
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.6f, c * 1.6f, 0.0f}, VCLASS_SCREENSPACE});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.9f, c * 1.9f, 0.0f}, VCLASS_SCREENSPACE});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.2f, c * 2.2f, 0.0f}, VCLASS_SCREENSPACE});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.5f, c * 2.5f, 0.0f}, VCLASS_SCREENSPACE});
}
SHC.drw_light_icon_sun_rays = GPU_batch_create_ex(
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_light_icon_sun_rays;
}
GPUBatch *DRW_cache_light_point_lines_get(void)
{
if (!SHC.drw_light_point_lines) {
GPUVertFormat format = extra_vert_format();
int v_len = 2 * CIRCLE_NSEGMENTS;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
int v = 0;
/* Light area */
int flag = VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE;
circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
@ -1490,26 +1562,12 @@ GPUBatch *DRW_cache_light_sun_lines_get(void)
if (!SHC.drw_light_sun_lines) {
GPUVertFormat format = extra_vert_format();
int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS + OUTER_NSEGMENTS + 8 * 2 + 1);
int v_len = 2;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
/* Light Icon */
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
/* Sun Rays */
for (int a = 0; a < 8; a++) {
float angle = (2.0f * M_PI * a) / 8.0f;
float s = sinf(angle) * r;
float c = cosf(angle) * r;
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.6f, c * 1.6f, 0.0f}, VCLASS_SCREENSPACE});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.9f, c * 1.9f, 0.0f}, VCLASS_SCREENSPACE});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.2f, c * 2.2f, 0.0f}, VCLASS_SCREENSPACE});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.5f, c * 2.5f, 0.0f}, VCLASS_SCREENSPACE});
}
/* Direction Line */
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 0.0}, 0});
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, -20.0}, 0}); /* Good default. */
@ -1524,17 +1582,12 @@ GPUBatch *DRW_cache_light_spot_lines_get(void)
if (!SHC.drw_light_spot_lines) {
GPUVertFormat format = extra_vert_format();
int v_len = 2 * (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS +
CIRCLE_NSEGMENTS * 4 + 1);
int v_len = 2 * (DIAMOND_NSEGMENTS * 2 + CIRCLE_NSEGMENTS * 4 + 1);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
/* Light Icon */
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
/* Light area */
int flag = VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE;
circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
@ -1597,17 +1650,12 @@ GPUBatch *DRW_cache_light_area_disk_lines_get(void)
if (!SHC.drw_light_area_disk_lines) {
GPUVertFormat format = extra_vert_format();
int v_len = 2 *
(DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS + CIRCLE_NSEGMENTS + 1);
int v_len = 2 * (DIAMOND_NSEGMENTS * 2 + CIRCLE_NSEGMENTS + 1);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
/* Light Icon */
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
/* Light area */
circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 0.5f, 0.0f, VCLASS_LIGHT_AREA_SHAPE);
/* Direction Line */
@ -1630,15 +1678,11 @@ GPUBatch *DRW_cache_light_area_square_lines_get(void)
GPUVertFormat format = extra_vert_format();
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
int v_len = 2 * (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS + 4 + 1);
int v_len = 2 * (DIAMOND_NSEGMENTS * 2 + 4 + 1);
GPU_vertbuf_data_alloc(vbo, v_len);
const float r = 9.0f;
int v = 0;
/* Light Icon */
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
/* Light area */
int flag = VCLASS_LIGHT_AREA_SHAPE;
for (int a = 0; a < 4; a++) {

View File

@ -106,6 +106,9 @@ struct GPUBatch *DRW_cache_field_sphere_limit_get(void);
/* Lights */
struct GPUBatch *DRW_cache_light_icon_inner_lines_get(void);
struct GPUBatch *DRW_cache_light_icon_outer_lines_get(void);
struct GPUBatch *DRW_cache_light_icon_sun_rays_get(void);
struct GPUBatch *DRW_cache_light_point_lines_get(void);
struct GPUBatch *DRW_cache_light_sun_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_lines_get(void);

View File

@ -552,6 +552,7 @@ enum {
V3D_OVERLAY_SCULPT_SHOW_MASK = (1 << 14),
V3D_OVERLAY_SCULPT_SHOW_FACE_SETS = (1 << 15),
V3D_OVERLAY_SCULPT_CURVES_CAGE = (1 << 16),
V3D_OVERLAY_SHOW_LIGHT_COLORS = (1 << 17),
};
/** #View3DOverlay.edit_flag */

View File

@ -4407,6 +4407,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Extras", "Object details, including empty wire, cameras and other visual guides");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_light_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_SHOW_LIGHT_COLORS);
RNA_def_property_ui_text(prop, "Light Colors", "Show light colors");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_bones", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_BONES);
RNA_def_property_ui_text(