Blender V5.0
eevee_world.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
8
9#include "BKE_lib_id.hh"
10#include "BKE_node.hh"
13#include "NOD_shader.h"
14
15#include "eevee_instance.hh"
16
17namespace blender::eevee {
18
19/* -------------------------------------------------------------------- */
23
24World::~World()
25{
26 if (default_world_ != nullptr) {
27 BKE_id_free(nullptr, default_world_);
28 }
29}
30
31::World *World::default_world_get()
32{
33 if (default_world_ == nullptr) {
34 default_world_ = BKE_id_new_nomain<::World>("EEVEE default world");
35 default_world_->nodetree = bke::node_tree_add_tree_embedded(
36 nullptr, &default_world_->id, "World Nodetree", ntreeType_Shader->idname);
37
38 BLI_listbase_clear(&default_world_->gpumaterial);
39 }
40 return default_world_;
41}
42
43::World *World::scene_world_get()
44{
45 return (inst_.scene->world != nullptr) ? inst_.scene->world : default_world_get();
46}
47
49{
50 /* No sun extraction during baking. */
51 if (inst_.is_baking()) {
52 return 0.0;
53 }
54
55 float sun_threshold = scene_world_get()->sun_threshold;
56 if (inst_.use_studio_light()) {
57 /* Do not call `lookdev_world_.intensity_get()` as it might not be initialized yet. */
58 sun_threshold *= inst_.v3d->shading.studiolight_intensity;
59 }
60 return sun_threshold;
61}
62
63void World::sync()
64{
65 bool has_update = false;
66
67 WorldHandle wo_handle = {0};
68 if (inst_.scene->world != nullptr) {
69 /* Detect world update before overriding it. */
70 wo_handle = inst_.sync.sync_world(*inst_.scene->world);
71 has_update = wo_handle.recalc != 0;
72 }
73
74 bool wait_ready = true; // TODO !inst_.is_image_render;
75
76 /* Sync volume first since its result can override the surface world. */
77 sync_volume(wo_handle, wait_ready);
78
79 ::World *bl_world;
80 if (inst_.use_studio_light()) {
81 has_update |= lookdev_world_.sync(LookdevParameters(inst_.v3d));
82 bl_world = lookdev_world_.world_get();
83 }
84 else if ((inst_.view_layer->layflag & SCE_LAY_SKY) == 0) {
85 bl_world = default_world_get();
86 }
87 else if (has_volume_absorption_) {
88 bl_world = default_world_get();
89 }
90 else {
91 bl_world = scene_world_get();
92 }
93
94 ::World *world_override = DEG_get_evaluated(inst_.depsgraph, inst_.view_layer->world_override);
95 if (world_override) {
96 bl_world = world_override;
97 }
98
99 bNodeTree *ntree = (bl_world->nodetree) ? bl_world->nodetree : default_world_get()->nodetree;
100
101 {
102 if (has_volume_absorption_) {
103 /* Replace world by black world. */
104 bl_world = default_world_get();
105 }
106 }
107
108 /* We have to manually test here because we have overrides. */
109 ::World *orig_world = DEG_get_original(bl_world);
110 if (assign_if_different(prev_original_world, orig_world)) {
111 has_update = true;
112 }
113
114 inst_.light_probes.sync_world(bl_world, has_update);
115
116 if (inst_.is_viewport() && has_update) {
117 /* Catch lookdev viewport properties updates. */
118 inst_.sampling.reset();
119 }
120
121 GPUMaterial *gpumat = inst_.shaders.world_shader_get(
122 bl_world, ntree, MAT_PIPE_DEFERRED, !wait_ready);
123
124 if (GPU_material_status(gpumat) == GPU_MAT_FAILED) {
125 bl_world = default_world_get();
126 ntree = bl_world->nodetree;
127 gpumat = inst_.shaders.world_shader_get(bl_world, ntree, MAT_PIPE_DEFERRED, !wait_ready);
128 }
129 if (GPU_material_status(gpumat) == GPU_MAT_QUEUED) {
130 is_ready_ = false;
131 return;
132 }
133 is_ready_ = true;
134
135 inst_.manager->register_layer_attributes(gpumat);
136
137 float opacity = inst_.use_studio_light() ? lookdev_world_.background_opacity_get() :
138 inst_.film.background_opacity_get();
139 float background_blur = inst_.use_studio_light() ? lookdev_world_.background_blur_get() : 0.0;
140
141 inst_.pipelines.background.sync(gpumat, opacity, background_blur);
142 inst_.pipelines.world.sync(gpumat);
143}
144
145void World::sync_volume(const WorldHandle &world_handle, bool wait_ready)
146{
147 /* Studio lights have no volume shader. */
148 ::World *world = inst_.use_studio_light() ? nullptr : inst_.scene->world;
149
150 GPUMaterial *gpumat = nullptr;
151
152 /* Only the scene world nodetree can have volume shader. */
153 if (world && world->nodetree) {
154 gpumat = inst_.shaders.world_shader_get(
155 world, world->nodetree, MAT_PIPE_VOLUME_MATERIAL, !wait_ready);
156 }
157
158 bool had_volume = has_volume_;
159
160 if (gpumat && (GPU_material_status(gpumat) == GPU_MAT_SUCCESS)) {
161 has_volume_ = GPU_material_has_volume_output(gpumat);
162 has_volume_scatter_ = GPU_material_flag_get(gpumat, GPU_MATFLAG_VOLUME_SCATTER);
163 has_volume_absorption_ = GPU_material_flag_get(gpumat, GPU_MATFLAG_VOLUME_ABSORPTION);
164 }
165 else {
166 has_volume_ = has_volume_absorption_ = has_volume_scatter_ = false;
167 }
168
169 /* World volume needs to be always synced for correct clearing of parameter buffers. */
170 inst_.pipelines.world_volume.sync(gpumat);
171
172 if (has_volume_ || had_volume) {
173 inst_.volume.world_sync(world_handle);
174 }
175}
176
178
179} // namespace blender::eevee
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ SCE_LAY_SKY
@ GPU_MAT_QUEUED
@ GPU_MAT_FAILED
@ GPU_MAT_SUCCESS
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
GPUMaterialStatus GPU_material_status(GPUMaterial *mat)
@ GPU_MATFLAG_VOLUME_SCATTER
@ GPU_MATFLAG_VOLUME_ABSORPTION
bool GPU_material_has_volume_output(GPUMaterial *mat)
struct blender::bke::bNodeTreeType * ntreeType_Shader
GPUMaterial * world_shader_get(::World *blender_world, bNodeTree *nodetree, eMaterialPipeline pipeline_type, bool deferred_compilation)
void world_sync(const WorldHandle &world_handle)
World(Instance &inst)
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4098
bool assign_if_different(T &old_value, T new_value)
struct World * world
struct bNodeTree * nodetree
float sun_threshold