Blender V4.3
eevee_sync.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "eevee_engine.h"
12
13#include "BKE_gpencil_legacy.h"
14#include "BKE_object.hh"
15#include "BKE_paint.hh"
16#include "BKE_pbvh_api.hh"
18#include "DNA_curves_types.h"
20#include "DNA_modifier_types.h"
21#include "DNA_particle_types.h"
23#include "DNA_volume_types.h"
24
25#include "draw_common.hh"
26#include "draw_sculpt.hh"
27
28#include "eevee_instance.hh"
29
30namespace blender::eevee {
31
32/* -------------------------------------------------------------------- */
38{
39 ObjectKey key(ob_ref.object);
40
41 ObjectHandle &handle = ob_handles.lookup_or_add_cb(key, [&]() {
42 ObjectHandle new_handle;
43 new_handle.object_key = key;
44 return new_handle;
45 });
46
47 handle.recalc = inst_.get_recalc_flags(ob_ref);
48
49 return handle;
50}
51
53{
54 WorldHandle handle;
55 handle.recalc = inst_.get_recalc_flags(world);
56 return handle;
57}
58
61/* -------------------------------------------------------------------- */
65static inline void geometry_call(PassMain::Sub *sub_pass,
66 gpu::Batch *geom,
67 ResourceHandle resource_handle)
68{
69 if (sub_pass != nullptr) {
70 sub_pass->draw(geom, resource_handle);
71 }
72}
73
74static inline void volume_call(
75 MaterialPass &matpass, Scene *scene, Object *ob, gpu::Batch *geom, ResourceHandle res_handle)
76{
77 if (matpass.sub_pass != nullptr) {
78 PassMain::Sub *object_pass = volume_sub_pass(*matpass.sub_pass, scene, ob, matpass.gpumat);
79 if (object_pass != nullptr) {
80 object_pass->draw(geom, res_handle);
81 }
82 }
83}
84
87/* -------------------------------------------------------------------- */
92 ObjectHandle &ob_handle,
93 ResourceHandle res_handle,
94 const ObjectRef &ob_ref)
95{
96 if (!inst_.use_surfaces) {
97 return;
98 }
99
100 bool has_motion = inst_.velocity.step_object_sync(
101 ob, ob_handle.object_key, res_handle, ob_handle.recalc);
102
103 MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
104
105 gpu::Batch **mat_geom = DRW_cache_object_surface_material_get(
106 ob, material_array.gpu_materials.data(), material_array.gpu_materials.size());
107
108 if (mat_geom == nullptr) {
109 return;
110 }
111
112 if ((ob->dt < OB_SOLID) && (inst_.is_viewport() && inst_.v3d->shading.type != OB_RENDER)) {
114 return;
115 }
116
117 bool is_alpha_blend = false;
118 bool has_transparent_shadows = false;
119 bool has_volume = false;
120 float inflate_bounds = 0.0f;
121 for (auto i : material_array.gpu_materials.index_range()) {
122 gpu::Batch *geom = mat_geom[i];
123 if (geom == nullptr) {
124 continue;
125 }
126
127 Material &material = material_array.materials[i];
128 GPUMaterial *gpu_material = material_array.gpu_materials[i];
129
130 if (material.has_volume) {
131 volume_call(material.volume_occupancy, inst_.scene, ob, geom, res_handle);
132 volume_call(material.volume_material, inst_.scene, ob, geom, res_handle);
133 has_volume = true;
134 /* Do not render surface if we are rendering a volume object
135 * and do not have a surface closure. */
136 if (!material.has_surface) {
137 continue;
138 }
139 }
140
141 geometry_call(material.capture.sub_pass, geom, res_handle);
142 geometry_call(material.overlap_masking.sub_pass, geom, res_handle);
143 geometry_call(material.prepass.sub_pass, geom, res_handle);
144 geometry_call(material.shading.sub_pass, geom, res_handle);
145 geometry_call(material.shadow.sub_pass, geom, res_handle);
146
147 geometry_call(material.planar_probe_prepass.sub_pass, geom, res_handle);
148 geometry_call(material.planar_probe_shading.sub_pass, geom, res_handle);
149 geometry_call(material.lightprobe_sphere_prepass.sub_pass, geom, res_handle);
150 geometry_call(material.lightprobe_sphere_shading.sub_pass, geom, res_handle);
151
152 is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
153 has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
154
155 ::Material *mat = GPU_material_get_material(gpu_material);
156 inst_.cryptomatte.sync_material(mat);
157
158 if (GPU_material_has_displacement_output(gpu_material)) {
159 inflate_bounds = math::max(inflate_bounds, mat->inflate_bounds);
160 }
161 }
162
163 if (has_volume) {
164 inst_.volume.object_sync(ob_handle);
165 }
166
167 if (inflate_bounds != 0.0f) {
168 inst_.manager->update_handle_bounds(res_handle, ob_ref, inflate_bounds);
169 }
170
171 inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
172
173 inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
174 inst_.cryptomatte.sync_object(ob, res_handle);
175}
176
178 ObjectHandle &ob_handle,
179 ResourceHandle res_handle,
180 const ObjectRef &ob_ref)
181{
182 if (!inst_.use_surfaces) {
183 return false;
184 }
185
186 bool pbvh_draw = BKE_sculptsession_use_pbvh_draw(ob, inst_.rv3d) && !DRW_state_is_image_render();
187 if (!pbvh_draw) {
188 return false;
189 }
190
191 bool has_motion = false;
192 MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
193
194 bool is_alpha_blend = false;
195 bool has_transparent_shadows = false;
196 bool has_volume = false;
197 float inflate_bounds = 0.0f;
198 for (SculptBatch &batch :
200 {
201 gpu::Batch *geom = batch.batch;
202 if (geom == nullptr) {
203 continue;
204 }
205
206 Material &material = material_array.materials[batch.material_slot];
207
208 if (material.has_volume) {
209 volume_call(material.volume_occupancy, inst_.scene, ob, geom, res_handle);
210 volume_call(material.volume_material, inst_.scene, ob, geom, res_handle);
211 has_volume = true;
212 /* Do not render surface if we are rendering a volume object
213 * and do not have a surface closure. */
214 if (material.has_surface == false) {
215 continue;
216 }
217 }
218
219 geometry_call(material.capture.sub_pass, geom, res_handle);
220 geometry_call(material.overlap_masking.sub_pass, geom, res_handle);
221 geometry_call(material.prepass.sub_pass, geom, res_handle);
222 geometry_call(material.shading.sub_pass, geom, res_handle);
223 geometry_call(material.shadow.sub_pass, geom, res_handle);
224
225 geometry_call(material.planar_probe_prepass.sub_pass, geom, res_handle);
226 geometry_call(material.planar_probe_shading.sub_pass, geom, res_handle);
227 geometry_call(material.lightprobe_sphere_prepass.sub_pass, geom, res_handle);
228 geometry_call(material.lightprobe_sphere_shading.sub_pass, geom, res_handle);
229
230 is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
231 has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
232
233 GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot];
234 ::Material *mat = GPU_material_get_material(gpu_material);
235 inst_.cryptomatte.sync_material(mat);
236
237 if (GPU_material_has_displacement_output(gpu_material)) {
238 inflate_bounds = math::max(inflate_bounds, mat->inflate_bounds);
239 }
240 }
241
242 if (has_volume) {
243 inst_.volume.object_sync(ob_handle);
244 }
245
246 /* Use a valid bounding box. The pbvh::Tree module already does its own culling, but a valid */
247 /* bounding box is still needed for directional shadow tile-map bounds computation. */
249 const float3 center = math::midpoint(bounds.min, bounds.max);
250 const float3 half_extent = bounds.max - center + inflate_bounds;
251 inst_.manager->update_handle_bounds(res_handle, center, half_extent);
252
253 inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
254
255 inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
256 inst_.cryptomatte.sync_object(ob, res_handle);
257
258 return true;
259}
260
263/* -------------------------------------------------------------------- */
268 ObjectHandle &ob_handle,
269 ResourceHandle res_handle,
270 const ObjectRef &ob_ref)
271{
272 const int material_slot = POINTCLOUD_MATERIAL_NR;
273
274 bool has_motion = inst_.velocity.step_object_sync(
275 ob, ob_handle.object_key, res_handle, ob_handle.recalc);
276
277 Material &material = inst_.materials.material_get(
278 ob, has_motion, material_slot - 1, MAT_GEOM_POINT_CLOUD);
279
280 auto drawcall_add = [&](MaterialPass &matpass) {
281 if (matpass.sub_pass == nullptr) {
282 return;
283 }
284 PassMain::Sub &object_pass = matpass.sub_pass->sub("Point Cloud Sub Pass");
285 gpu::Batch *geometry = point_cloud_sub_pass_setup(object_pass, ob, matpass.gpumat);
286 object_pass.draw(geometry, res_handle);
287 };
288
289 if (material.has_volume) {
290 /* Only support single volume material for now. */
291 drawcall_add(material.volume_occupancy);
292 drawcall_add(material.volume_material);
293 inst_.volume.object_sync(ob_handle);
294
295 /* Do not render surface if we are rendering a volume object
296 * and do not have a surface closure. */
297 if (material.has_surface == false) {
298 return;
299 }
300 }
301
302 drawcall_add(material.capture);
303 drawcall_add(material.overlap_masking);
304 drawcall_add(material.prepass);
305 drawcall_add(material.shading);
306 drawcall_add(material.shadow);
307
308 drawcall_add(material.planar_probe_prepass);
309 drawcall_add(material.planar_probe_shading);
310 drawcall_add(material.lightprobe_sphere_prepass);
311 drawcall_add(material.lightprobe_sphere_shading);
312
313 inst_.cryptomatte.sync_object(ob, res_handle);
314 GPUMaterial *gpu_material = material.shading.gpumat;
315 ::Material *mat = GPU_material_get_material(gpu_material);
316 inst_.cryptomatte.sync_material(mat);
317
318 if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
319 inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
320 }
321
322 inst_.manager->extract_object_attributes(res_handle, ob_ref, material.shading.gpumat);
323
324 inst_.shadows.sync_object(ob,
325 ob_handle,
326 res_handle,
327 material.is_alpha_blend_transparent,
328 material.has_transparent_shadows);
329}
330
333/* -------------------------------------------------------------------- */
338 ObjectHandle &ob_handle,
339 ResourceHandle res_handle,
340 const ObjectRef &ob_ref)
341{
342 if (!inst_.use_volumes) {
343 return;
344 }
345
346 const int material_slot = VOLUME_MATERIAL_NR;
347
348 /* Motion is not supported on volumes yet. */
349 const bool has_motion = false;
350
351 Material &material = inst_.materials.material_get(
352 ob, has_motion, material_slot - 1, MAT_GEOM_VOLUME);
353
354 if (!GPU_material_has_volume_output(material.volume_material.gpumat)) {
355 return;
356 }
357
358 /* Do not render the object if there is no attribute used in the volume.
359 * This mimic Cycles behavior (see #124061). */
360 ListBase attr_list = GPU_material_attributes(material.volume_material.gpumat);
361 if (BLI_listbase_is_empty(&attr_list)) {
362 return;
363 }
364
365 auto drawcall_add = [&](MaterialPass &matpass, gpu::Batch *geom, ResourceHandle res_handle) {
366 if (matpass.sub_pass == nullptr) {
367 return false;
368 }
369 PassMain::Sub *object_pass = volume_sub_pass(
370 *matpass.sub_pass, inst_.scene, ob, matpass.gpumat);
371 if (object_pass != nullptr) {
372 object_pass->draw(geom, res_handle);
373 return true;
374 }
375 return false;
376 };
377
378 /* Use bounding box tag empty spaces. */
379 gpu::Batch *geom = DRW_cache_cube_get();
380
381 bool is_rendered = false;
382 is_rendered |= drawcall_add(material.volume_occupancy, geom, res_handle);
383 is_rendered |= drawcall_add(material.volume_material, geom, res_handle);
384
385 if (!is_rendered) {
386 return;
387 }
388
389 inst_.manager->extract_object_attributes(res_handle, ob_ref, material.volume_material.gpumat);
390
391 inst_.volume.object_sync(ob_handle);
392}
393
396/* -------------------------------------------------------------------- */
401 ObjectHandle &ob_handle,
402 ResourceHandle res_handle,
403 const ObjectRef &ob_ref,
404 ModifierData *modifier_data,
405 ParticleSystem *particle_sys)
406{
407 if (!inst_.use_curves) {
408 return;
409 }
410
411 int mat_nr = CURVES_MATERIAL_NR;
412 if (particle_sys != nullptr) {
413 mat_nr = particle_sys->part->omat;
414 }
415
416 bool has_motion = inst_.velocity.step_object_sync(
417 ob, ob_handle.object_key, res_handle, ob_handle.recalc, modifier_data, particle_sys);
418 Material &material = inst_.materials.material_get(ob, has_motion, mat_nr - 1, MAT_GEOM_CURVES);
419
420 auto drawcall_add = [&](MaterialPass &matpass) {
421 if (matpass.sub_pass == nullptr) {
422 return;
423 }
424 if (particle_sys != nullptr) {
425 PassMain::Sub &sub_pass = matpass.sub_pass->sub("Hair SubPass");
426 gpu::Batch *geometry = hair_sub_pass_setup(
427 sub_pass, inst_.scene, ob, particle_sys, modifier_data, matpass.gpumat);
428 sub_pass.draw(geometry, res_handle);
429 }
430 else {
431 PassMain::Sub &sub_pass = matpass.sub_pass->sub("Curves SubPass");
432 gpu::Batch *geometry = curves_sub_pass_setup(sub_pass, inst_.scene, ob, matpass.gpumat);
433 sub_pass.draw(geometry, res_handle);
434 }
435 };
436
437 if (material.has_volume) {
438 /* Only support single volume material for now. */
439 drawcall_add(material.volume_occupancy);
440 drawcall_add(material.volume_material);
441 inst_.volume.object_sync(ob_handle);
442 /* Do not render surface if we are rendering a volume object
443 * and do not have a surface closure. */
444 if (material.has_surface == false) {
445 return;
446 }
447 }
448
449 drawcall_add(material.capture);
450 drawcall_add(material.overlap_masking);
451 drawcall_add(material.prepass);
452 drawcall_add(material.shading);
453 drawcall_add(material.shadow);
454
455 drawcall_add(material.planar_probe_prepass);
456 drawcall_add(material.planar_probe_shading);
457 drawcall_add(material.lightprobe_sphere_prepass);
458 drawcall_add(material.lightprobe_sphere_shading);
459
460 inst_.cryptomatte.sync_object(ob, res_handle);
461 GPUMaterial *gpu_material = material.shading.gpumat;
462 ::Material *mat = GPU_material_get_material(gpu_material);
463 inst_.cryptomatte.sync_material(mat);
464
465 if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
466 inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
467 }
468
469 inst_.manager->extract_object_attributes(res_handle, ob_ref, material.shading.gpumat);
470
471 inst_.shadows.sync_object(ob,
472 ob_handle,
473 res_handle,
474 material.is_alpha_blend_transparent,
475 material.has_transparent_shadows);
476}
477
481{
482 int sub_key = 1;
483
485 if (md->type == eModifierType_ParticleSystem) {
486 ParticleSystem *particle_sys = reinterpret_cast<ParticleSystemModifierData *>(md)->psys;
487 ParticleSettings *part_settings = particle_sys->part;
488 const int draw_as = (part_settings->draw_as == PART_DRAW_REND) ? part_settings->ren_as :
489 part_settings->draw_as;
490 if (draw_as != PART_DRAW_PATH ||
492 {
493 continue;
494 }
495
496 ObjectHandle particle_sys_handle = ob_handle;
497 particle_sys_handle.object_key = ObjectKey(ob, sub_key++);
498 particle_sys_handle.recalc = particle_sys->recalc;
499
500 callback(particle_sys_handle, *md, *particle_sys);
501 }
502 }
503}
504
505} // namespace blender::eevee
General operations, lookup, etc. for blender objects.
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2862
A BVH for high poly meshes.
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define CURVES_MATERIAL_NR
@ eModifierType_ParticleSystem
@ OB_SOLID
@ OB_RENDER
@ PART_DRAW_PATH
@ PART_DRAW_REND
#define POINTCLOUD_MATERIAL_NR
#define VOLUME_MATERIAL_NR
ListBase GPU_material_attributes(const GPUMaterial *material)
Material * GPU_material_get_material(GPUMaterial *material)
bool GPU_material_has_displacement_output(GPUMaterial *mat)
bool GPU_material_has_volume_output(GPUMaterial *mat)
int64_t size() const
IndexRange index_range() const
void extract_object_attributes(ResourceHandle handle, const ObjectRef &ref, const GPUMaterial *material)
void update_handle_bounds(ResourceHandle handle, const ObjectRef &ref, float inflate_bounds=0.0f)
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 sync_object(Object *ob, ResourceHandle res_handle)
void sync_material(const ::Material *material)
int get_recalc_flags(const ObjectRef &ob_ref)
const RegionView3D * rv3d
Material & material_get(Object *ob, bool has_motion, int mat_nr, eMaterialGeometry geometry_type)
MaterialArray & material_array_get(Object *ob, bool has_motion)
void sync_object(const Object *ob, const ObjectHandle &handle, const ResourceHandle &resource_handle, bool is_alpha_blend, bool has_transparent_shadows)
void sync_point_cloud(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle, const ObjectRef &ob_ref)
ObjectHandle & sync_object(const ObjectRef &ob_ref)
Definition eevee_sync.cc:37
void sync_mesh(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle, const ObjectRef &ob_ref)
Definition eevee_sync.cc:91
void sync_volume(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle, const ObjectRef &ob_ref)
void sync_curves(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle, const ObjectRef &ob_ref, ModifierData *modifier_data=nullptr, ParticleSystem *particle_sys=nullptr)
WorldHandle sync_world(const ::World &world)
Definition eevee_sync.cc:52
bool sync_sculpt(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle, const ObjectRef &ob_ref)
bool step_object_sync(Object *ob, ObjectKey &object_key, ResourceHandle resource_handle, int recalc=0, ModifierData *modifier_data=nullptr, ParticleSystem *particle_sys=nullptr)
void object_sync(const ObjectHandle &ob_handle)
DEGForeachIDComponentCallback callback
blender::gpu::Batch ** DRW_cache_object_surface_material_get(Object *ob, GPUMaterial **gpumat_array, uint gpumat_array_len)
blender::gpu::Batch * DRW_cache_cube_get()
bool DRW_state_is_image_render()
bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys)
struct @620::@622 batch
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
Bounds< float3 > bounds_get(const Tree &pbvh)
Definition pbvh.cc:1480
gpu::Batch * point_cloud_sub_pass_setup(PassMain::Sub &sub_ps, Object *object, GPUMaterial *gpu_material=nullptr)
gpu::Batch * hair_sub_pass_setup(PassMain::Sub &sub_ps, const Scene *scene, Object *object, ParticleSystem *psys, ModifierData *md, GPUMaterial *gpu_material=nullptr)
Definition draw_hair.cc:416
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, GPUMaterial *gpu_material=nullptr)
PassMain::Sub * volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, GPUMaterial *gpu_material)
Vector< SculptBatch > sculpt_batches_per_material_get(const Object *ob, Span< const GPUMaterial * > materials)
static void geometry_call(PassMain::Sub *sub_pass, gpu::Batch *geom, ResourceHandle resource_handle)
Definition eevee_sync.cc:65
void foreach_hair_particle_handle(Object *ob, ObjectHandle ob_handle, HairHandleCallback callback)
static void volume_call(MaterialPass &matpass, Scene *scene, Object *ob, gpu::Batch *geom, ResourceHandle res_handle)
Definition eevee_sync.cc:74
T midpoint(const T &a, const T &b)
T max(const T &a, const T &b)
ListBase modifiers
ParticleSettings * part
View3DShading shading
Vector< GPUMaterial * > gpu_materials