Blender V5.0
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 ResourceHandleRange resource_handle)
63{
64 if (sub_pass != nullptr) {
65 sub_pass->draw(geom, resource_handle);
66 }
67}
68
69static inline void volume_call(MaterialPass &matpass,
70 Scene *scene,
71 Object *ob,
72 gpu::Batch *geom,
73 ResourceHandleRange res_handle)
74{
75 if (matpass.sub_pass != nullptr) {
76 PassMain::Sub *object_pass = volume_sub_pass(*matpass.sub_pass, scene, ob, matpass.gpumat);
77 if (object_pass != nullptr) {
78 object_pass->draw(geom, res_handle);
79 }
80 }
81}
82
84
85/* -------------------------------------------------------------------- */
88
89void SyncModule::sync_mesh(Object *ob, ObjectHandle &ob_handle, const ObjectRef &ob_ref)
90{
91 if (!inst_.use_surfaces) {
92 return;
93 }
94
95 if ((ob->dt < OB_SOLID) && (inst_.is_viewport() && inst_.v3d->shading.type != OB_RENDER)) {
97 return;
98 }
99
100 ResourceHandleRange res_handle = inst_.manager->unique_handle(ob_ref);
101
102 bool has_motion = inst_.velocity.step_object_sync(
103 ob_handle.object_key, ob_ref, ob_handle.recalc, res_handle);
104
105 MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
106
108 ob, material_array.gpu_materials);
109 if (mat_geom.is_empty()) {
110 return;
111 }
112
113 bool is_alpha_blend = false;
114 bool has_transparent_shadows = false;
115 bool has_volume = false;
116 float inflate_bounds = 0.0f;
117 for (auto i : material_array.gpu_materials.index_range()) {
118 gpu::Batch *geom = mat_geom[i];
119 if (geom == nullptr) {
120 continue;
121 }
122
123 Material &material = material_array.materials[i];
124 GPUMaterial *gpu_material = material_array.gpu_materials[i];
125
126 if (material.has_volume) {
127 volume_call(material.volume_occupancy, inst_.scene, ob, geom, res_handle);
128 volume_call(material.volume_material, inst_.scene, ob, geom, res_handle);
129 has_volume = true;
130 /* Do not render surface if we are rendering a volume object
131 * and do not have a surface closure. */
132 if (!material.has_surface) {
133 continue;
134 }
135 }
136
137 geometry_call(material.capture.sub_pass, geom, res_handle);
138 geometry_call(material.overlap_masking.sub_pass, geom, res_handle);
139 geometry_call(material.prepass.sub_pass, geom, res_handle);
140 geometry_call(material.shading.sub_pass, geom, res_handle);
141 geometry_call(material.shadow.sub_pass, geom, res_handle);
142
143 geometry_call(material.planar_probe_prepass.sub_pass, geom, res_handle);
144 geometry_call(material.planar_probe_shading.sub_pass, geom, res_handle);
145 geometry_call(material.lightprobe_sphere_prepass.sub_pass, geom, res_handle);
146 geometry_call(material.lightprobe_sphere_shading.sub_pass, geom, res_handle);
147
148 is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
149 has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
150
151 ::Material *mat = GPU_material_get_material(gpu_material);
152 inst_.cryptomatte.sync_material(mat);
153
154 if (GPU_material_has_displacement_output(gpu_material)) {
155 inflate_bounds = math::max(inflate_bounds, mat->inflate_bounds);
156 }
157 }
158
159 if (has_volume) {
160 inst_.volume.object_sync(ob_handle);
161 }
162
163 if (inflate_bounds != 0.0f) {
164 inst_.manager->update_handle_bounds(res_handle, ob_ref, inflate_bounds);
165 }
166
167 inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
168
169 inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
170 inst_.cryptomatte.sync_object(ob, res_handle);
171}
172
173bool SyncModule::sync_sculpt(Object *ob, ObjectHandle &ob_handle, const ObjectRef &ob_ref)
174{
175 if (!inst_.use_surfaces) {
176 return false;
177 }
178
179 bool pbvh_draw = BKE_sculptsession_use_pbvh_draw(ob, inst_.rv3d) && !inst_.is_image_render;
180 if (!pbvh_draw) {
181 return false;
182 }
183
184 ResourceHandleRange res_handle = inst_.manager->unique_handle_for_sculpt(ob_ref);
185
186 bool has_motion = false;
187 MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
188
189 bool is_alpha_blend = false;
190 bool has_transparent_shadows = false;
191 bool has_volume = false;
192 float inflate_bounds = 0.0f;
193 for (SculptBatch &batch :
195 {
196 gpu::Batch *geom = batch.batch;
197 if (geom == nullptr) {
198 continue;
199 }
200
201 Material &material = material_array.materials[batch.material_slot];
202
203 if (material.has_volume) {
204 volume_call(material.volume_occupancy, inst_.scene, ob, geom, res_handle);
205 volume_call(material.volume_material, inst_.scene, ob, geom, res_handle);
206 has_volume = true;
207 /* Do not render surface if we are rendering a volume object
208 * and do not have a surface closure. */
209 if (material.has_surface == false) {
210 continue;
211 }
212 }
213
214 geometry_call(material.capture.sub_pass, geom, res_handle);
215 geometry_call(material.overlap_masking.sub_pass, geom, res_handle);
216 geometry_call(material.prepass.sub_pass, geom, res_handle);
217 geometry_call(material.shading.sub_pass, geom, res_handle);
218 geometry_call(material.shadow.sub_pass, geom, res_handle);
219
220 geometry_call(material.planar_probe_prepass.sub_pass, geom, res_handle);
221 geometry_call(material.planar_probe_shading.sub_pass, geom, res_handle);
222 geometry_call(material.lightprobe_sphere_prepass.sub_pass, geom, res_handle);
223 geometry_call(material.lightprobe_sphere_shading.sub_pass, geom, res_handle);
224
225 is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
226 has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
227
228 GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot];
229 ::Material *mat = GPU_material_get_material(gpu_material);
230 inst_.cryptomatte.sync_material(mat);
231
232 if (GPU_material_has_displacement_output(gpu_material)) {
233 inflate_bounds = math::max(inflate_bounds, mat->inflate_bounds);
234 }
235 }
236
237 if (has_volume) {
238 inst_.volume.object_sync(ob_handle);
239 }
240
241 inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
242
243 inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
244 inst_.cryptomatte.sync_object(ob, res_handle);
245
246 return true;
247}
248
250
251/* -------------------------------------------------------------------- */
254
255void SyncModule::sync_pointcloud(Object *ob, ObjectHandle &ob_handle, const ObjectRef &ob_ref)
256{
257 const int material_slot = POINTCLOUD_MATERIAL_NR;
258
259 ResourceHandleRange res_handle = inst_.manager->unique_handle(ob_ref);
260
261 bool has_motion = inst_.velocity.step_object_sync(
262 ob_handle.object_key, ob_ref, ob_handle.recalc, res_handle);
263
264 Material &material = inst_.materials.material_get(
265 ob, has_motion, material_slot - 1, MAT_GEOM_POINTCLOUD);
266
267 auto drawcall_add = [&](MaterialPass &matpass, bool dual_sided = false) {
268 if (matpass.sub_pass == nullptr) {
269 return;
270 }
271 PassMain::Sub &object_pass = matpass.sub_pass->sub("Point Cloud Sub Pass");
272 gpu::Batch *geometry = pointcloud_sub_pass_setup(object_pass, ob, matpass.gpumat);
273 if (dual_sided) {
274 /* WORKAROUND: Hack to generate backfaces. Should also be baked into the Index Buf too at
275 * some point in the future. */
276 object_pass.push_constant("ptcloud_backface", false);
277 object_pass.draw(geometry, res_handle);
278 object_pass.push_constant("ptcloud_backface", true);
279 object_pass.draw(geometry, res_handle);
280 }
281 else {
282 object_pass.push_constant("ptcloud_backface", false);
283 object_pass.draw(geometry, res_handle);
284 }
285 };
286
287 if (material.has_volume) {
288 /* Only support single volume material for now. */
289 drawcall_add(material.volume_occupancy, true);
290 drawcall_add(material.volume_material);
291 inst_.volume.object_sync(ob_handle);
292
293 /* Do not render surface if we are rendering a volume object
294 * and do not have a surface closure. */
295 if (material.has_surface == false) {
296 return;
297 }
298 }
299
300 drawcall_add(material.capture);
301 drawcall_add(material.overlap_masking);
302 drawcall_add(material.prepass);
303 drawcall_add(material.shading);
304 drawcall_add(material.shadow);
305
306 drawcall_add(material.planar_probe_prepass);
307 drawcall_add(material.planar_probe_shading);
308 drawcall_add(material.lightprobe_sphere_prepass);
309 drawcall_add(material.lightprobe_sphere_shading);
310
311 inst_.cryptomatte.sync_object(ob, res_handle);
312 GPUMaterial *gpu_material = material.shading.gpumat;
313 ::Material *mat = GPU_material_get_material(gpu_material);
314 inst_.cryptomatte.sync_material(mat);
315
316 if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
317 inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
318 }
319
320 inst_.manager->extract_object_attributes(res_handle, ob_ref, material.shading.gpumat);
321
322 inst_.shadows.sync_object(ob,
323 ob_handle,
324 res_handle,
326 material.has_transparent_shadows);
327}
328
330
331/* -------------------------------------------------------------------- */
334
335void SyncModule::sync_volume(Object *ob, ObjectHandle &ob_handle, const ObjectRef &ob_ref)
336{
337 if (!inst_.use_volumes) {
338 return;
339 }
340
341 ResourceHandleRange res_handle = inst_.manager->unique_handle(ob_ref);
342
343 const int material_slot = VOLUME_MATERIAL_NR;
344
345 /* Motion is not supported on volumes yet. */
346 const bool has_motion = false;
347
348 Material &material = inst_.materials.material_get(
349 ob, has_motion, material_slot - 1, MAT_GEOM_VOLUME);
350
352 return;
353 }
354
355 /* Do not render the object if there is no attribute used in the volume.
356 * This mimic Cycles behavior (see #124061). */
358 if (BLI_listbase_is_empty(&attr_list)) {
359 return;
360 }
361
362 auto drawcall_add =
363 [&](MaterialPass &matpass, gpu::Batch *geom, ResourceHandleRange res_handle) {
364 if (matpass.sub_pass == nullptr) {
365 return false;
366 }
367 PassMain::Sub *object_pass = volume_sub_pass(
368 *matpass.sub_pass, inst_.scene, ob, matpass.gpumat);
369 if (object_pass != nullptr) {
370 object_pass->draw(geom, res_handle);
371 return true;
372 }
373 return false;
374 };
375
376 /* Use bounding box tag empty spaces. */
377 gpu::Batch *geom = inst_.volume.unit_cube_batch_get();
378
379 bool is_rendered = false;
380 is_rendered |= drawcall_add(material.volume_occupancy, geom, res_handle);
381 is_rendered |= drawcall_add(material.volume_material, geom, res_handle);
382
383 if (!is_rendered) {
384 return;
385 }
386
387 inst_.manager->extract_object_attributes(res_handle, ob_ref, material.volume_material.gpumat);
388
389 inst_.volume.object_sync(ob_handle);
390}
391
393
394/* -------------------------------------------------------------------- */
397
399 ObjectHandle &ob_handle,
400 const ObjectRef &ob_ref,
401 ResourceHandleRange res_handle,
402 ModifierData *modifier_data,
403 ParticleSystem *particle_sys)
404{
405 if (!inst_.use_curves) {
406 return;
407 }
408
409 int mat_nr = CURVES_MATERIAL_NR;
410 if (particle_sys != nullptr) {
411 mat_nr = particle_sys->part->omat;
412 }
413
414 if (!res_handle.is_valid()) {
415 /* For curve objects. */
416 res_handle = inst_.manager->unique_handle(ob_ref);
417 }
418
419 bool has_motion = inst_.velocity.step_object_sync(
420 ob_handle.object_key, ob_ref, ob_handle.recalc, res_handle, modifier_data, particle_sys);
421 Material &material = inst_.materials.material_get(ob, has_motion, mat_nr - 1, MAT_GEOM_CURVES);
422
423 auto drawcall_add = [&](MaterialPass &matpass) {
424 if (matpass.sub_pass == nullptr) {
425 return;
426 }
427 if (particle_sys != nullptr) {
428 PassMain::Sub &sub_pass = matpass.sub_pass->sub("Hair SubPass");
429 gpu::Batch *geometry = hair_sub_pass_setup(
430 sub_pass, inst_.scene, ob_ref, particle_sys, modifier_data, matpass.gpumat);
431 sub_pass.draw(geometry, res_handle);
432 }
433 else {
434 PassMain::Sub &sub_pass = matpass.sub_pass->sub("Curves SubPass");
435 const char *error = nullptr;
436 gpu::Batch *geometry = curves_sub_pass_setup(
437 sub_pass, inst_.scene, ob, error, matpass.gpumat);
438 if (error) {
439 inst_.info_append(error);
440 }
441 sub_pass.draw(geometry, res_handle);
442 }
443 };
444
445 if (material.has_volume) {
446 /* Only support single volume material for now. */
447 drawcall_add(material.volume_occupancy);
448 drawcall_add(material.volume_material);
449 inst_.volume.object_sync(ob_handle);
450 /* Do not render surface if we are rendering a volume object
451 * and do not have a surface closure. */
452 if (material.has_surface == false) {
453 return;
454 }
455 }
456
457 drawcall_add(material.capture);
458 drawcall_add(material.overlap_masking);
459 drawcall_add(material.prepass);
460 drawcall_add(material.shading);
461 drawcall_add(material.shadow);
462
463 drawcall_add(material.planar_probe_prepass);
464 drawcall_add(material.planar_probe_shading);
465 drawcall_add(material.lightprobe_sphere_prepass);
466 drawcall_add(material.lightprobe_sphere_shading);
467
468 inst_.cryptomatte.sync_object(ob, res_handle);
469 GPUMaterial *gpu_material = material.shading.gpumat;
470 ::Material *mat = GPU_material_get_material(gpu_material);
471 inst_.cryptomatte.sync_material(mat);
472
473 if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
474 inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
475 }
476
477 inst_.manager->extract_object_attributes(res_handle, ob_ref, material.shading.gpumat);
478
479 inst_.shadows.sync_object(ob,
480 ob_handle,
481 res_handle,
483 material.has_transparent_shadows);
484}
485
487
489 ObjectRef &ob_ref,
490 ObjectHandle ob_handle,
491 HairHandleCallback callback)
492{
493 int sub_key = 1;
494
496 if (md->type == eModifierType_ParticleSystem) {
497 ParticleSystem *particle_sys = reinterpret_cast<ParticleSystemModifierData *>(md)->psys;
498 ParticleSettings *part_settings = particle_sys->part;
499 /* Only use the viewport drawing mode for material preview. */
500 const int draw_as = (part_settings->draw_as == PART_DRAW_REND || !inst.is_viewport()) ?
501 part_settings->ren_as :
502 part_settings->draw_as;
503 if (draw_as != PART_DRAW_PATH ||
505 {
506 continue;
507 }
508
509 ObjectHandle particle_sys_handle = ob_handle;
510 particle_sys_handle.object_key = ObjectKey(ob_ref, sub_key++);
511 particle_sys_handle.recalc = particle_sys->recalc;
512
513 callback(particle_sys_handle, *md, *particle_sys);
514 }
515 }
516}
517
518} // namespace blender::eevee
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:3068
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
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:690
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:893
void push_constant(const char *name, const float &data)
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
A running instance of the engine.
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:89
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_curves(Object *ob, ObjectHandle &ob_handle, const ObjectRef &ob_ref, ResourceHandleRange res_handle={}, ModifierData *modifier_data=nullptr, ParticleSystem *particle_sys=nullptr)
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 @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
static void error(const char *str)
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, const char *&r_error, 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:104
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 volume_call(MaterialPass &matpass, Scene *scene, Object *ob, gpu::Batch *geom, ResourceHandleRange res_handle)
Definition eevee_sync.cc:69
static void geometry_call(PassMain::Sub *sub_pass, gpu::Batch *geom, ResourceHandleRange resource_handle)
Definition eevee_sync.cc:60
void foreach_hair_particle_handle(Instance &inst, ObjectRef &ob_ref, ObjectHandle ob_handle, HairHandleCallback callback)
FunctionRef< void(ObjectHandle, ModifierData &, ParticleSystem &)> HairHandleCallback
Definition eevee_sync.hh:70
T max(const T &a, const T &b)
ListBase modifiers
ParticleSettings * part
Vector< GPUMaterial * > gpu_materials
MaterialPass lightprobe_sphere_shading
MaterialPass lightprobe_sphere_prepass
i
Definition text_draw.cc:230