Blender V4.3
overlay_next_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
12#pragma once
13
14#include "draw_sculpt.hh"
15
18
19namespace blender::draw::overlay {
20
21class Prepass {
22 private:
23 const SelectionType selection_type_;
24
25 PassMain ps_ = {"prepass"};
26 PassMain::Sub *mesh_ps_ = nullptr;
27 PassMain::Sub *hair_ps_ = nullptr;
28 PassMain::Sub *curves_ps_ = nullptr;
29 PassMain::Sub *point_cloud_ps_ = nullptr;
30 PassMain::Sub *grease_pencil_ps_ = nullptr;
31
32 bool enabled_ = false;
33 bool use_selection_ = false;
34 bool use_material_slot_selection_ = false;
35
36 overlay::GreasePencil::ViewParameters grease_pencil_view;
37
38 public:
39 Prepass(const SelectionType selection_type) : selection_type_(selection_type){};
40
41 void begin_sync(Resources &res, const State &state)
42 {
43 use_selection_ = (selection_type_ != SelectionType::DISABLED);
44 enabled_ = (state.space_type == SPACE_VIEW3D);
45
46 if (!enabled_) {
47 /* Not used. But release the data. */
48 ps_.init();
49 mesh_ps_ = nullptr;
50 curves_ps_ = nullptr;
51 point_cloud_ps_ = nullptr;
52 return;
53 }
54
55 {
56 /* TODO(fclem): This is against design. We should not sync depending on view position.
57 * Eventually, we should do this in a compute shader prepass. */
58 float4x4 viewinv;
59 DRW_view_viewmat_get(nullptr, viewinv.ptr(), true);
60 grease_pencil_view = {DRW_view_is_persp_get(nullptr), viewinv};
61 }
62
63 use_material_slot_selection_ = DRW_state_is_material_select();
64
65 const View3DShading &shading = state.v3d->shading;
66 bool use_cull = ((shading.type == OB_SOLID) && (shading.flag & V3D_SHADING_BACKFACE_CULLING));
67 DRWState backface_cull_state = use_cull ? DRW_STATE_CULL_BACK : DRWState(0);
68
69 ps_.init();
71 state.clipping_plane_count);
72 res.select_bind(ps_);
73 {
74 auto &sub = ps_.sub("Mesh");
75 sub.shader_set(use_selection_ ? res.shaders.depth_mesh_conservative.get() :
76 res.shaders.depth_mesh.get());
77 sub.bind_ubo("globalsBlock", &res.globals_buf);
78 mesh_ps_ = ⊂
79 }
80 {
81 auto &sub = ps_.sub("Hair");
82 sub.shader_set(res.shaders.depth_mesh.get());
83 sub.bind_ubo("globalsBlock", &res.globals_buf);
84 hair_ps_ = ⊂
85 }
86 {
87 auto &sub = ps_.sub("Curves");
88 sub.shader_set(res.shaders.depth_curves.get());
89 sub.bind_ubo("globalsBlock", &res.globals_buf);
90 curves_ps_ = ⊂
91 }
92 {
93 auto &sub = ps_.sub("PointCloud");
95 sub.bind_ubo("globalsBlock", &res.globals_buf);
96 point_cloud_ps_ = ⊂
97 }
98 {
99 auto &sub = ps_.sub("GreasePencil");
101 sub.bind_ubo("globalsBlock", &res.globals_buf);
102 grease_pencil_ps_ = ⊂
103 }
104 }
105
106 void particle_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
107 {
108 Object *ob = ob_ref.object;
109
110 ResourceHandle handle = {0};
111
114 continue;
115 }
116
117 const ParticleSettings *part = psys->part;
118 const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
119 switch (draw_as) {
120 case PART_DRAW_PATH:
121 if ((state.is_wireframe_mode == false) && (part->draw_as == PART_DRAW_REND)) {
122 /* Case where the render engine should have rendered it, but we need to draw it for
123 * selection purpose. */
124 if (handle.raw == 0u) {
125 handle = manager.resource_handle_for_psys(ob_ref,
127 }
128
129 select::ID select_id = use_material_slot_selection_ ?
130 res.select_id(ob_ref, part->omat << 16) :
131 res.select_id(ob_ref);
132
133 gpu::Batch *geom = DRW_cache_particles_get_hair(ob, psys, nullptr);
134 mesh_ps_->draw(geom, handle, select_id.get());
135 break;
136 }
137 break;
138 default:
139 /* Other draw modes should be handled by the particle overlay. */
140 break;
141 }
142 }
143 }
144
145 void sculpt_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
146 {
147 ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
148 select::ID select_id = res.select_id(ob_ref);
149
151 mesh_ps_->draw(batch.batch, handle, select_id.get());
152 }
153 }
154
155 void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
156 {
157 if (!enabled_) {
158 return;
159 }
160
161 particle_sync(manager, ob_ref, res, state);
162
163 const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d) &&
165
166 if (use_sculpt_pbvh) {
167 sculpt_sync(manager, ob_ref, res);
168 return;
169 }
170
171 gpu::Batch *geom_single = nullptr;
172 Span<gpu::Batch *> geom_list(&geom_single, 1);
173
174 PassMain::Sub *pass = nullptr;
175 switch (ob_ref.object->type) {
176 case OB_MESH:
177 if (use_material_slot_selection_) {
178 /* TODO(fclem): Improve the API. */
179 const int materials_len = DRW_cache_object_material_count_get(ob_ref.object);
180 Array<GPUMaterial *> materials(materials_len);
181 materials.fill(nullptr);
182
183 gpu::Batch **geom_per_mat = DRW_cache_mesh_surface_shaded_get(
184 ob_ref.object, materials.data(), materials_len);
185
186 geom_list = {geom_per_mat, materials_len};
187 }
188 else {
189 geom_single = DRW_cache_mesh_surface_get(ob_ref.object);
190 }
191 pass = mesh_ps_;
192 break;
193 case OB_VOLUME:
194 if (selection_type_ == SelectionType::DISABLED) {
195 /* Disable during display, only enable for selection. */
196 /* TODO(fclem): Would be nice to have even when not selecting to occlude overlays. */
197 return;
198 }
200 pass = mesh_ps_;
201 break;
202 case OB_POINTCLOUD:
203 geom_single = point_cloud_sub_pass_setup(*point_cloud_ps_, ob_ref.object);
204 pass = point_cloud_ps_;
205 break;
206 case OB_CURVES:
207 geom_single = curves_sub_pass_setup(*curves_ps_, state.scene, ob_ref.object);
208 pass = curves_ps_;
209 break;
210 case OB_GREASE_PENCIL:
211 if (selection_type_ == SelectionType::DISABLED) {
212 /* Disable during display, only enable for selection.
213 * The grease pencil engine already renders it properly. */
214 return;
215 }
216 GreasePencil::draw_grease_pencil(*grease_pencil_ps_,
217 grease_pencil_view,
218 state.scene,
219 ob_ref.object,
220 manager.unique_handle(ob_ref),
221 res.select_id(ob_ref));
222 return;
223 default:
224 break;
225 }
226
227 if (pass == nullptr) {
228 return;
229 }
230
231 ResourceHandle res_handle = manager.unique_handle(ob_ref);
232
233 for (int material_id : geom_list.index_range()) {
234 select::ID select_id = use_material_slot_selection_ ?
235 res.select_id(ob_ref, (material_id + 1) << 16) :
236 res.select_id(ob_ref);
237
238 if (use_selection_ && (pass == mesh_ps_)) {
239 /* Conservative shader needs expanded draw-call. */
240 pass->draw_expand(
241 geom_list[material_id], GPU_PRIM_TRIS, 1, 1, res_handle, select_id.get());
242 }
243 else {
244 pass->draw(geom_list[material_id], res_handle, select_id.get());
245 }
246 }
247 }
248
249 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
250 {
251 if (!enabled_) {
252 return;
253 }
254 /* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
255 GPU_framebuffer_bind(framebuffer);
256 manager.submit(ps_, view);
257 }
258};
259
260} // namespace blender::draw::overlay
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2862
#define LISTBASE_FOREACH(type, var, list)
@ OB_SOLID
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES
@ PART_DRAW_PATH
@ PART_DRAW_REND
@ SPACE_VIEW3D
@ V3D_SHADING_BACKFACE_CULLING
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
@ GPU_PRIM_TRIS
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
ResourceHandle unique_handle(const ObjectRef &ref)
ResourceHandle resource_handle_for_sculpt(const ObjectRef &ref)
ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix)
void submit(PassSimple &pass, View &view)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:760
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 shader_set(GPUShader *shader)
Definition draw_pass.hh:971
static float4x4 dupli_matrix_get(const ObjectRef &ob_ref)
void begin_sync(Resources &res, const State &state)
void sculpt_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
Prepass(const SelectionType selection_type)
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
void particle_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
blender::gpu::Batch * DRW_cache_mesh_surface_get(Object *ob)
blender::gpu::Batch * DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
blender::gpu::Batch ** DRW_cache_mesh_surface_shaded_get(Object *ob, GPUMaterial **gpumat_array, uint gpumat_array_len)
int DRW_cache_object_material_count_get(const Object *ob)
bool DRW_state_is_material_select()
bool DRW_state_is_image_render()
bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys)
bool DRW_view_is_persp_get(const DRWView *view)
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
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
struct @620::@622 batch
static ulong state[N]
gpu::Batch * point_cloud_sub_pass_setup(PassMain::Sub &sub_ps, Object *object, GPUMaterial *gpu_material=nullptr)
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, GPUMaterial *gpu_material=nullptr)
Vector< SculptBatch > sculpt_batches_get(const Object *ob, SculptBatchFeature features)
blender::gpu::Batch * DRW_cache_volume_selection_surface_get(Object *ob)
ListBase particlesystem
const c_style_mat & ptr() const
void select_bind(PassSimple &pass)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)