Blender V4.5
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(GPUFrameBuffer *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 ResourceHandle handle = {0};
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.raw == 0u) {
154 handle = manager.resource_handle_for_psys(ob_ref,
156 }
157
158 select::ID select_id = use_material_slot_selection_ ?
159 res.select_id(ob_ref, part->omat << 16) :
160 res.select_id(ob_ref);
161
162 gpu::Batch *geom = DRW_cache_particles_get_hair(ob, psys, nullptr);
163 mesh_ps_->draw(geom, handle, select_id.get());
164 break;
165 }
166 break;
167 default:
168 /* Other draw modes should be handled by the particle overlay. */
169 break;
170 }
171 }
172 }
173
174 void sculpt_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
175 {
176 ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
177
179 select::ID select_id = use_material_slot_selection_ ?
180 res.select_id(ob_ref, (batch.material_slot + 1) << 16) :
181 res.select_id(ob_ref);
182
183 if (res.is_selection()) {
184 /* Conservative shader needs expanded draw-call. */
185 mesh_ps_->draw_expand(batch.batch, GPU_PRIM_TRIS, 1, 1, handle, select_id.get());
186 }
187 else {
188 mesh_ps_->draw(batch.batch, handle, select_id.get());
189 }
190 }
191 }
192
193 void object_sync(Manager &manager,
194 const ObjectRef &ob_ref,
195 Resources &res,
196 const State &state) final
197 {
198 bool is_solid = ob_ref.object->dt >= OB_SOLID ||
199 (state.v3d->shading.type == OB_RENDER &&
200 !(ob_ref.object->visibility_flag & OB_HIDE_CAMERA));
201
202 if (!enabled_ || !is_solid) {
203 return;
204 }
205
206 particle_sync(manager, ob_ref, res, state);
207
208 const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d) &&
209 !state.is_image_render;
210
211 if (use_sculpt_pbvh) {
212 sculpt_sync(manager, ob_ref, res);
213 return;
214 }
215
216 gpu::Batch *geom_single = nullptr;
217 Span<gpu::Batch *> geom_list(&geom_single, 1);
218
219 PassMain::Sub *pass = nullptr;
220 switch (ob_ref.object->type) {
221 case OB_MESH:
222 if (use_material_slot_selection_) {
223 /* TODO(fclem): Improve the API. */
224 const int materials_len = BKE_object_material_used_with_fallback_eval(*ob_ref.object);
225 Array<GPUMaterial *> materials(materials_len, nullptr);
226 geom_list = DRW_cache_mesh_surface_shaded_get(ob_ref.object, materials);
227 }
228 else {
229 geom_single = DRW_cache_mesh_surface_get(ob_ref.object);
230
231 if (res.is_selection() && !use_material_slot_selection_ &&
232 FlatObjectRef::flat_axis_index_get(ob_ref.object) != -1)
233 {
234 /* Avoid losing flat objects when in ortho views (see #56549) */
235 mesh_flat_ps_->draw(DRW_cache_mesh_all_edges_get(ob_ref.object),
236 manager.unique_handle(ob_ref),
237 res.select_id(ob_ref).get());
238 }
239 }
240 pass = mesh_ps_;
241 break;
242 case OB_VOLUME:
243 if (!res.is_selection()) {
244 /* Disable during display, only enable for selection. */
245 /* TODO(fclem): Would be nice to have even when not selecting to occlude overlays. */
246 return;
247 }
248 geom_single = DRW_cache_volume_selection_surface_get(ob_ref.object);
249 pass = mesh_ps_;
250 /* TODO(fclem): Get rid of these check and enforce correct API on the batch cache. */
251 if (geom_single == nullptr) {
252 return;
253 }
254 break;
255 case OB_POINTCLOUD:
256 geom_single = pointcloud_sub_pass_setup(*pointcloud_ps_, ob_ref.object);
257 pass = pointcloud_ps_;
258 break;
259 case OB_CURVES:
260 geom_single = curves_sub_pass_setup(*curves_ps_, state.scene, ob_ref.object);
261 pass = curves_ps_;
262 break;
263 case OB_GREASE_PENCIL:
264 if (!res.is_selection() && state.is_render_depth_available) {
265 /* Disable during display, only enable for selection.
266 * The grease pencil engine already renders it properly. */
267 return;
268 }
269 GreasePencil::draw_grease_pencil(res,
270 *grease_pencil_ps_,
271 state.scene,
272 ob_ref.object,
273 manager.unique_handle(ob_ref),
274 res.select_id(ob_ref));
275 return;
276 default:
277 break;
278 }
279
280 if (pass == nullptr) {
281 return;
282 }
283
284 ResourceHandle res_handle = manager.unique_handle(ob_ref);
285
286 for (int material_id : geom_list.index_range()) {
287 /* Meshes with more than 16 materials can have nullptr in the geometry list as materials are
288 * not filled for unused materials indices. We should actually use `material_indices_used`
289 * but these are only available for meshes. */
290 if (geom_list[material_id] == nullptr) {
291 continue;
292 }
293
294 select::ID select_id = use_material_slot_selection_ ?
295 res.select_id(ob_ref, (material_id + 1) << 16) :
296 res.select_id(ob_ref);
297 if (res.is_selection() && (pass == mesh_ps_)) {
298 /* Conservative shader needs expanded draw-call. */
299 pass->draw_expand(
300 geom_list[material_id], GPU_PRIM_TRIS, 1, 1, res_handle, select_id.get());
301 }
302 else {
303 pass->draw(geom_list[material_id], res_handle, select_id.get());
304 }
305 }
306 }
307
308 void pre_draw(Manager &manager, View &view) final
309 {
310 if (!enabled_) {
311 return;
312 }
313
314 manager.generate_commands(ps_, view);
315 }
316
317 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
318 {
319 if (!enabled_) {
320 return;
321 }
322 /* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
323 GPU_framebuffer_bind(framebuffer);
324 manager.submit_only(ps_, view);
325 }
326};
327
328} // 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:2928
#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(GPUFrameBuffer *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 resource_handle_for_sculpt(const ObjectRef &ref)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:884
void draw_expand(gpu::Batch *batch, GPUPrimType primitive_type, uint primitive_len, uint instance_len, uint vertex_len=-1, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:915
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:490
void begin_sync(Resources &res, const State &state) final
void draw_on_render(GPUFrameBuffer *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 @242053044010324116347033273112253060004051364061::@051143074301336237271216303350234260141112266062 batch
static ulong state[N]
detail::Pass< command::DrawCommandBuf > PassSimple
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, GPUMaterial *gpu_material=nullptr)
detail::Pass< command::DrawMultiBuf > PassMain
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)
float4x4 DRW_particles_dupli_matrix_get(const ObjectRef &ob_ref)
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)