Blender V5.0
overlay_prepass.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
8
9#pragma once
10
11#include "BKE_paint.hh"
12
13#include "DNA_particle_types.h"
14
15#include "draw_sculpt.hh"
16
17#include "overlay_base.hh"
19#include "overlay_particle.hh"
20
21namespace blender::draw::overlay {
22
23/* Add prepass which will write to the depth buffer so that the
24 * alpha-under overlays (alpha checker) will draw correctly for external engines.
25 * NOTE: Use the same Z-depth value as in the regular image drawing engine. */
27 private:
28 PassSimple ps_ = {"ImagePrepass"};
29
30 public:
31 void begin_sync(Resources &res, const State &state) final
32 {
33 enabled_ = state.is_space_image() && state.is_image_valid && !res.is_selection();
34
35 if (!enabled_) {
36 return;
37 }
38
39 ps_.init();
41 ps_.shader_set(res.shaders->mesh_edit_depth.get());
42 ps_.push_constant("retopology_offset", 0.0f);
43 ps_.draw(res.shapes.image_quad.get());
44 }
45
46 void draw_on_render(gpu::FrameBuffer *framebuffer, Manager &manager, View &view) final
47 {
48 if (!enabled_) {
49 return;
50 }
51
52 GPU_framebuffer_bind(framebuffer);
53 manager.submit(ps_, view);
54 }
55};
56
62 private:
63 PassMain ps_ = {"prepass"};
64 PassMain::Sub *mesh_ps_ = nullptr;
65 PassMain::Sub *mesh_flat_ps_ = nullptr;
66 PassMain::Sub *hair_ps_ = nullptr;
67 PassMain::Sub *curves_ps_ = nullptr;
68 PassMain::Sub *pointcloud_ps_ = nullptr;
69 PassMain::Sub *grease_pencil_ps_ = nullptr;
70
71 bool use_material_slot_selection_ = false;
72
73 public:
74 void begin_sync(Resources &res, const State &state) final
75 {
76 enabled_ = state.is_space_v3d() && (!state.xray_enabled || res.is_selection());
77
78 if (!enabled_) {
79 /* Not used. But release the data. */
80 ps_.init();
81 mesh_ps_ = nullptr;
82 curves_ps_ = nullptr;
83 pointcloud_ps_ = nullptr;
84 return;
85 }
86
87 use_material_slot_selection_ = state.is_material_select;
88
89 bool use_cull = res.globals_buf.backface_culling;
90 DRWState backface_cull_state = use_cull ? DRW_STATE_CULL_BACK : DRWState(0);
91
92 ps_.init();
93 ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
94 ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
95 ps_.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | backface_cull_state,
96 state.clipping_plane_count);
97 res.select_bind(ps_);
98 {
99 auto &sub = ps_.sub("Mesh");
100 sub.shader_set(res.is_selection() ? res.shaders->depth_mesh_conservative.get() :
101 res.shaders->depth_mesh.get());
102 mesh_ps_ = ⊂
103 }
104 {
105 auto &sub = ps_.sub("MeshFlat");
106 sub.shader_set(res.shaders->depth_mesh.get());
107 mesh_flat_ps_ = ⊂
108 }
109 {
110 auto &sub = ps_.sub("Hair");
111 sub.shader_set(res.shaders->depth_mesh.get());
112 hair_ps_ = ⊂
113 }
114 {
115 auto &sub = ps_.sub("Curves");
116 sub.shader_set(res.shaders->depth_curves.get());
117 curves_ps_ = ⊂
118 }
119 {
120 auto &sub = ps_.sub("PointCloud");
121 sub.shader_set(res.shaders->depth_pointcloud.get());
122 pointcloud_ps_ = ⊂
123 }
124 {
125 auto &sub = ps_.sub("GreasePencil");
126 sub.shader_set(res.shaders->depth_grease_pencil.get());
127 grease_pencil_ps_ = ⊂
128 }
129 }
130
131 void particle_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
132 {
133 if (state.skip_particles) {
134 return;
135 }
136
137 Object *ob = ob_ref.object;
138
139 ResourceHandleRange handle = {};
140
143 continue;
144 }
145
146 const ParticleSettings *part = psys->part;
147 const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
148 switch (draw_as) {
149 case PART_DRAW_PATH:
150 if ((state.is_wireframe_mode == false) && (part->draw_as == PART_DRAW_REND)) {
151 /* Case where the render engine should have rendered it, but we need to draw it for
152 * selection purpose. */
153 if (!handle.is_valid()) {
154 handle = manager.resource_handle_for_psys(ob_ref, ob_ref.particles_matrix());
155 }
156
157 select::ID select_id = use_material_slot_selection_ ?
158 res.select_id(ob_ref, part->omat << 16) :
159 res.select_id(ob_ref);
160
161 gpu::Batch *geom = DRW_cache_particles_get_hair(ob, psys, nullptr);
162 mesh_ps_->draw(geom, handle, select_id.get());
163 break;
164 }
165 break;
166 default:
167 /* Other draw modes should be handled by the particle overlay. */
168 break;
169 }
170 }
171 }
172
173 void sculpt_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
174 {
175 ResourceHandleRange handle = manager.unique_handle_for_sculpt(ob_ref);
176
178 select::ID select_id = use_material_slot_selection_ ?
179 res.select_id(ob_ref, (batch.material_slot + 1) << 16) :
180 res.select_id(ob_ref);
181
182 if (res.is_selection()) {
183 /* Conservative shader needs expanded draw-call. */
184 mesh_ps_->draw_expand(batch.batch, GPU_PRIM_TRIS, 1, 1, handle, select_id.get());
185 }
186 else {
187 mesh_ps_->draw(batch.batch, handle, select_id.get());
188 }
189 }
190 }
191
192 void object_sync(Manager &manager,
193 const ObjectRef &ob_ref,
194 Resources &res,
195 const State &state) final
196 {
197 bool is_solid = ob_ref.object->dt >= OB_SOLID ||
198 (state.v3d->shading.type == OB_RENDER &&
199 !(ob_ref.object->visibility_flag & OB_HIDE_CAMERA));
200
201 if (!enabled_ || !is_solid) {
202 return;
203 }
204
205 particle_sync(manager, ob_ref, res, state);
206
207 const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d) &&
208 !state.is_image_render;
209
210 if (use_sculpt_pbvh) {
211 sculpt_sync(manager, ob_ref, res);
212 return;
213 }
214
215 gpu::Batch *geom_single = nullptr;
216 Span<gpu::Batch *> geom_list(&geom_single, 1);
217
218 PassMain::Sub *pass = nullptr;
219 switch (ob_ref.object->type) {
220 case OB_MESH:
221 if (use_material_slot_selection_) {
222 /* TODO(fclem): Improve the API. */
223 const int materials_len = BKE_object_material_used_with_fallback_eval(*ob_ref.object);
224 Array<GPUMaterial *> materials(materials_len, nullptr);
225 geom_list = DRW_cache_mesh_surface_shaded_get(ob_ref.object, materials);
226 }
227 else {
228 geom_single = DRW_cache_mesh_surface_get(ob_ref.object);
229
230 if (res.is_selection() && !use_material_slot_selection_ &&
231 FlatObjectRef::flat_axis_index_get(ob_ref.object) != -1)
232 {
233 /* Avoid losing flat objects when in ortho views (see #56549) */
234 mesh_flat_ps_->draw(DRW_cache_mesh_all_edges_get(ob_ref.object),
235 manager.unique_handle(ob_ref),
236 res.select_id(ob_ref).get());
237 }
238 }
239 pass = mesh_ps_;
240 break;
241 case OB_VOLUME:
242 if (!res.is_selection()) {
243 /* Disable during display, only enable for selection. */
244 /* TODO(fclem): Would be nice to have even when not selecting to occlude overlays. */
245 return;
246 }
247 geom_single = DRW_cache_volume_selection_surface_get(ob_ref.object);
248 pass = mesh_ps_;
249 /* TODO(fclem): Get rid of these check and enforce correct API on the batch cache. */
250 if (geom_single == nullptr) {
251 return;
252 }
253 break;
254 case OB_POINTCLOUD:
255 geom_single = pointcloud_sub_pass_setup(*pointcloud_ps_, ob_ref.object);
256 pass = pointcloud_ps_;
257 break;
258 case OB_CURVES: {
259 const char *error = nullptr;
260 /* The error string will always have been printed by the engine already.
261 * No need to display it twice. */
262 geom_single = curves_sub_pass_setup(*curves_ps_, state.scene, ob_ref.object, error);
263 pass = curves_ps_;
264 break;
265 }
266 case OB_GREASE_PENCIL:
267 if (!res.is_selection() && state.is_render_depth_available) {
268 /* Disable during display, only enable for selection.
269 * The grease pencil engine already renders it properly. */
270 return;
271 }
272 GreasePencil::draw_grease_pencil(res,
273 *grease_pencil_ps_,
274 state.scene,
275 ob_ref.object,
276 manager.unique_handle(ob_ref),
277 res.select_id(ob_ref));
278 return;
279 default:
280 break;
281 }
282
283 if (pass == nullptr) {
284 return;
285 }
286
287 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
288
289 for (int material_id : geom_list.index_range()) {
290 /* Meshes with more than 16 materials can have nullptr in the geometry list as materials are
291 * not filled for unused materials indices. We should actually use `material_indices_used`
292 * but these are only available for meshes. */
293 if (geom_list[material_id] == nullptr) {
294 continue;
295 }
296
297 select::ID select_id = use_material_slot_selection_ ?
298 res.select_id(ob_ref, (material_id + 1) << 16) :
299 res.select_id(ob_ref);
300 if (res.is_selection() && (pass == mesh_ps_)) {
301 /* Conservative shader needs expanded draw-call. */
302 pass->draw_expand(
303 geom_list[material_id], GPU_PRIM_TRIS, 1, 1, res_handle, select_id.get());
304 }
305 else {
306 pass->draw(geom_list[material_id], res_handle, select_id.get());
307 }
308 }
309 }
310
311 void pre_draw(Manager &manager, View &view) final
312 {
313 if (!enabled_) {
314 return;
315 }
316
317 manager.generate_commands(ps_, view);
318 }
319
320 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
321 {
322 if (!enabled_) {
323 return;
324 }
325 /* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
326 GPU_framebuffer_bind(framebuffer);
327 manager.submit_only(ps_, view);
328 }
329};
330
331} // namespace blender::draw::overlay
int BKE_object_material_used_with_fallback_eval(const Object &ob)
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:3068
#define LISTBASE_FOREACH(type, var, list)
@ OB_SOLID
@ OB_RENDER
@ OB_HIDE_CAMERA
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES
@ PART_DRAW_PATH
@ PART_DRAW_REND
static AppView * view
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
@ GPU_PRIM_TRIS
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix)
ResourceHandleRange unique_handle_for_sculpt(const ObjectRef &ref)
float4x4 particles_matrix() const
void draw_expand(gpu::Batch *batch, GPUPrimType primitive_type, uint primitive_len, uint instance_len, uint vertex_len, uint vertex_first, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:925
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:893
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
void begin_sync(Resources &res, const State &state) final
void draw_on_render(gpu::FrameBuffer *framebuffer, Manager &manager, View &view) final
void sculpt_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state) final
void begin_sync(Resources &res, const State &state) final
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
void pre_draw(Manager &manager, View &view) final
void particle_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys)
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
DRWState
Definition draw_state.hh:25
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_CULL_BACK
Definition draw_state.hh:43
@ DRW_STATE_DEPTH_ALWAYS
Definition draw_state.hh:36
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
static ulong state[N]
static void error(const char *str)
detail::Pass< command::DrawCommandBuf > PassSimple
detail::Pass< command::DrawMultiBuf > PassMain
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, const char *&r_error, GPUMaterial *gpu_material=nullptr)
gpu::Batch * pointcloud_sub_pass_setup(PassMain::Sub &sub_ps, Object *object, GPUMaterial *gpu_material=nullptr)
Vector< SculptBatch > sculpt_batches_get(const Object *ob, SculptBatchFeature features)
Span< gpu::Batch * > DRW_cache_mesh_surface_shaded_get(Object *ob, const Span< const GPUMaterial * > materials)
gpu::Batch * DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
gpu::Batch * DRW_cache_volume_selection_surface_get(Object *ob)
gpu::Batch * DRW_cache_mesh_surface_get(Object *ob)
gpu::Batch * DRW_cache_mesh_all_edges_get(Object *ob)
ListBase particlesystem
static int flat_axis_index_get(const Object *ob)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)