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
10
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/* -------------------------------------------------------------------- */
36
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
60
61/* -------------------------------------------------------------------- */
64
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
86
87/* -------------------------------------------------------------------- */
90
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
262
263/* -------------------------------------------------------------------- */
266
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,
328 material.has_transparent_shadows);
329}
330
332
333/* -------------------------------------------------------------------- */
336
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
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). */
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
395
396/* -------------------------------------------------------------------- */
399
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,
475 material.has_transparent_shadows);
476}
477
479
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)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between world
int64_t size() const
IndexRange index_range() const
T * data()
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
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:462
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)
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 @157336070235062372277311340362362342103123126032::@262166344314164341202215145112231240022370055142 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)
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 * 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
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
FunctionRef< void(ObjectHandle, ModifierData &, ParticleSystem &)> HairHandleCallback
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)
VecBase< float, 3 > float3
ListBase modifiers
ParticleSettings * part
Vector< GPUMaterial * > gpu_materials
MaterialPass lightprobe_sphere_shading
MaterialPass lightprobe_sphere_prepass