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