Blender V4.3
overlay_next_light.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#pragma once
10
12
13namespace blender::draw::overlay {
14
15class Lights {
18
19 private:
20 const SelectionType selection_type_;
21
22 PassSimple ps_ = {"Lights"};
23
24 struct CallBuffers {
25 const SelectionType selection_type_;
26 GroundLineInstanceBuf ground_line_buf = {selection_type_, "ground_line_buf"};
27 LightInstanceBuf icon_inner_buf = {selection_type_, "icon_inner_buf"};
28 LightInstanceBuf icon_outer_buf = {selection_type_, "icon_outer_buf"};
29 LightInstanceBuf icon_sun_rays_buf = {selection_type_, "icon_sun_rays_buf"};
30 LightInstanceBuf point_buf = {selection_type_, "point_buf"};
31 LightInstanceBuf sun_buf = {selection_type_, "sun_buf"};
32 LightInstanceBuf spot_buf = {selection_type_, "spot_buf"};
33 LightInstanceBuf spot_cone_back_buf = {selection_type_, "spot_cone_back_buf"};
34 LightInstanceBuf spot_cone_front_buf = {selection_type_, "spot_cone_front_buf"};
35 LightInstanceBuf area_disk_buf = {selection_type_, "area_disk_buf"};
36 LightInstanceBuf area_square_buf = {selection_type_, "area_square_buf"};
37 } call_buffers_{selection_type_};
38
39 public:
40 Lights(const SelectionType selection_type) : selection_type_(selection_type){};
41
43 {
44 call_buffers_.ground_line_buf.clear();
45 call_buffers_.icon_inner_buf.clear();
46 call_buffers_.icon_outer_buf.clear();
47 call_buffers_.icon_sun_rays_buf.clear();
48 call_buffers_.point_buf.clear();
49 call_buffers_.sun_buf.clear();
50 call_buffers_.spot_buf.clear();
51 call_buffers_.spot_cone_back_buf.clear();
52 call_buffers_.spot_cone_front_buf.clear();
53 call_buffers_.area_disk_buf.clear();
54 call_buffers_.area_square_buf.clear();
55 }
56
57 void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
58 {
59 ExtraInstanceData data(ob_ref.object->object_to_world(),
60 float4(res.object_wire_color(ob_ref, state).xyz(), 1.0f),
61 1.0f);
62 float4 &theme_color = data.color_;
63
64 /* Pack render data into object matrix. */
65 float4x4 &matrix = data.object_to_world_;
66 float &area_size_x = matrix[0].w;
67 float &area_size_y = matrix[1].w;
68 float &spot_cosine = matrix[0].w;
69 float &spot_blend = matrix[1].w;
70 float &clip_start = matrix[2].w;
71 float &clip_end = matrix[3].w;
72
73 const Light &la = *static_cast<Light *>(ob_ref.object->data);
74 const select::ID select_id = res.select_id(ob_ref);
75
76 /* FIXME / TODO: clip_end has no meaning nowadays.
77 * In EEVEE, Only clip_start is used shadow-mapping.
78 * Clip end is computed automatically based on light power.
79 * For now, always use the custom distance as clip_end. */
80 clip_end = la.att_dist;
81 clip_start = la.clipsta;
82
83 call_buffers_.ground_line_buf.append(float4(matrix.location()), select_id);
84
85 const float4 light_color = {la.r, la.g, la.b, 1.0f};
86 const bool show_light_colors = state.overlay.flag & V3D_OVERLAY_SHOW_LIGHT_COLORS;
87
88 /* Draw the outer ring of the light icon and the sun rays in `light_color`, if required. */
89 call_buffers_.icon_outer_buf.append(data, select_id);
90 call_buffers_.icon_inner_buf.append(show_light_colors ? data.with_color(light_color) : data,
91 select_id);
92
93 switch (la.type) {
94 case LA_LOCAL:
95 area_size_x = area_size_y = la.radius;
96 call_buffers_.point_buf.append(data, select_id);
97 break;
98 case LA_SUN:
99 call_buffers_.sun_buf.append(data, select_id);
100 call_buffers_.icon_sun_rays_buf.append(
101 show_light_colors ? data.with_color(light_color) : data, select_id);
102 break;
103 case LA_SPOT: {
104 /* Previous implementation was using the clip-end distance as cone size.
105 * We cannot do this anymore so we use a fixed size of 10. (see #72871) */
106 rescale_m4(matrix.ptr(), float3(10.0f, 10.0f, 10.0f));
107 /* For cycles and EEVEE the spot attenuation is:
108 * `y = (1/sqrt(1 + x^2) - a)/((1 - a) b)`
109 * x being the tangent of the angle between the light direction and the generatrix of the
110 * cone. We solve the case where spot attenuation y = 1 and y = 0 root for y = 1 is
111 * `sqrt(1/c^2 - 1)`. root for y = 0 is `sqrt(1/a^2 - 1)` and use that to position the
112 * blend circle. */
113 const float a = cosf(la.spotsize * 0.5f);
114 const float b = la.spotblend;
115 const float c = a * b - a - b;
116 const float a2 = a * a;
117 const float c2 = c * c;
118 /* Optimized version or root1 / root0 */
119 spot_blend = sqrtf((a2 - a2 * c2) / (c2 - a2 * c2));
120 spot_cosine = a;
121 /* HACK: We pack the area size in alpha color. This is decoded by the shader. */
122 theme_color[3] = -max_ff(la.radius, FLT_MIN);
123 call_buffers_.spot_buf.append(data, select_id);
124 if ((la.mode & LA_SHOW_CONE) && selection_type_ == SelectionType::DISABLED) {
125 const float4 color_inside{0.0f, 0.0f, 0.0f, 0.5f};
126 const float4 color_outside{1.0f, 1.0f, 1.0f, 0.3f};
127 call_buffers_.spot_cone_front_buf.append(data.with_color(color_inside), select_id);
128 call_buffers_.spot_cone_back_buf.append(data.with_color(color_outside), select_id);
129 }
130 break;
131 }
132 case LA_AREA:
133 const bool uniform_scale = !ELEM(la.area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE);
134 LightInstanceBuf &area_buf = ELEM(la.area_shape, LA_AREA_SQUARE, LA_AREA_RECT) ?
135 call_buffers_.area_square_buf :
136 call_buffers_.area_disk_buf;
137 area_size_x = la.area_size;
138 area_size_y = uniform_scale ? la.area_size : la.area_sizey;
139 area_buf.append(data, select_id);
140 break;
141 }
142 }
143
144 void end_sync(Resources &res, ShapeCache &shapes, const State &state)
145 {
148 ps_.init();
149 res.select_bind(ps_);
150
151 {
152 PassSimple::Sub &sub_pass = ps_.sub("spot_cone_front");
154 state.clipping_plane_count);
155 sub_pass.shader_set(res.shaders.extra_shape.get());
156 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
157 call_buffers_.spot_cone_front_buf.end_sync(sub_pass, shapes.light_spot_volume.get());
158 }
159 {
160 PassSimple::Sub &sub_pass = ps_.sub("spot_cone_back");
163 state.clipping_plane_count);
164 sub_pass.shader_set(res.shaders.extra_shape.get());
165 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
166 call_buffers_.spot_cone_back_buf.end_sync(sub_pass, shapes.light_spot_volume.get());
167 }
168 {
169 PassSimple::Sub &sub_pass = ps_.sub("light_shapes");
170 sub_pass.state_set(pass_state, state.clipping_plane_count);
171 sub_pass.shader_set(res.shaders.extra_shape.get());
172 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
173 call_buffers_.icon_inner_buf.end_sync(sub_pass, shapes.light_icon_outer_lines.get());
174 call_buffers_.icon_outer_buf.end_sync(sub_pass, shapes.light_icon_inner_lines.get());
175 call_buffers_.icon_sun_rays_buf.end_sync(sub_pass, shapes.light_icon_sun_rays.get());
176 call_buffers_.point_buf.end_sync(sub_pass, shapes.light_point_lines.get());
177 call_buffers_.sun_buf.end_sync(sub_pass, shapes.light_sun_lines.get());
178 call_buffers_.spot_buf.end_sync(sub_pass, shapes.light_spot_lines.get());
179 call_buffers_.area_disk_buf.end_sync(sub_pass, shapes.light_area_disk_lines.get());
180 call_buffers_.area_square_buf.end_sync(sub_pass, shapes.light_area_square_lines.get());
181 }
182 {
183 PassSimple::Sub &sub_pass = ps_.sub("ground_line");
184 sub_pass.state_set(pass_state | DRW_STATE_BLEND_ALPHA, state.clipping_plane_count);
185 sub_pass.shader_set(res.shaders.extra_ground_line.get());
186 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
187 call_buffers_.ground_line_buf.end_sync(sub_pass, shapes.ground_line.get());
188 }
189 }
190
191 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
192 {
193 GPU_framebuffer_bind(framebuffer);
194 manager.submit(ps_, view);
195 }
196};
197
198} // namespace blender::draw::overlay
MINLINE float max_ff(float a, float b)
void rescale_m4(float mat[4][4], const float scale[3])
#define ELEM(...)
@ LA_SHOW_CONE
@ LA_AREA
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ LA_AREA_ELLIPSE
@ LA_AREA_SQUARE
@ LA_AREA_RECT
@ V3D_OVERLAY_SHOW_LIGHT_COLORS
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void submit(PassSimple &pass, View &view)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
Lights(const SelectionType selection_type)
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
local_group_size(16, 16) .push_constant(Type b
#define cosf(x)
#define sqrtf(x)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_CULL_FRONT
Definition draw_state.hh:44
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_CULL_BACK
Definition draw_state.hh:43
static ulong state[N]
VecBase< float, 4 > float4
VecBase< T, 3 > xyz() const
const float4 & object_wire_color(const ObjectRef &ob_ref, ThemeColorID theme_id) const
void append(const InstanceDataT &data, select::ID select_id)
void select_bind(PassSimple &pass)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)