Blender V4.5
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
25{
26 bNodeTree *ntree = bke::node_tree_add_tree(nullptr, "World Nodetree", ntreeType_Shader->idname);
27 bNode *background = bke::node_add_static_node(nullptr, *ntree, SH_NODE_BACKGROUND);
29 bNodeSocket *background_out = bke::node_find_socket(*background, SOCK_OUT, "Background");
30 bNodeSocket *output_in = bke::node_find_socket(*output, SOCK_IN, "Surface");
31 bke::node_add_link(*ntree, *background, *background_out, *output, *output_in);
33
34 color_socket_ =
35 (bNodeSocketValueRGBA *)bke::node_find_socket(*background, SOCK_IN, "Color")->default_value;
36 ntree_ = ntree;
37}
38
44
46{
47 /* WARNING: This function is not thread-safe. Which is not a problem for the moment. */
48 copy_v3_fl3(color_socket_->value, wo->horr, wo->horg, wo->horb);
49 return ntree_;
50}
51
53
54/* -------------------------------------------------------------------- */
58
59World::~World()
60{
61 if (default_world_ != nullptr) {
62 BKE_id_free(nullptr, default_world_);
63 }
64}
65
66::World *World::default_world_get()
67{
68 if (default_world_ == nullptr) {
69 default_world_ = BKE_id_new_nomain<::World>("EEVEE default world");
70 default_world_->horr = default_world_->horg = default_world_->horb = 0.0f;
71 default_world_->use_nodes = 0;
72 default_world_->nodetree = nullptr;
73 BLI_listbase_clear(&default_world_->gpumaterial);
74 }
75 return default_world_;
76}
77
78::World *World::scene_world_get()
79{
80 return (inst_.scene->world != nullptr) ? inst_.scene->world : default_world_get();
81}
82
84{
85 /* No sun extraction during baking. */
86 if (inst_.is_baking()) {
87 return 0.0;
88 }
89
90 float sun_threshold = scene_world_get()->sun_threshold;
91 if (inst_.use_studio_light()) {
92 /* Do not call `lookdev_world_.intensity_get()` as it might not be initialized yet. */
93 sun_threshold *= inst_.v3d->shading.studiolight_intensity;
94 }
95 return sun_threshold;
96}
97
98void World::sync()
99{
100 bool has_update = false;
101
102 WorldHandle wo_handle = {0};
103 if (inst_.scene->world != nullptr) {
104 /* Detect world update before overriding it. */
105 wo_handle = inst_.sync.sync_world(*inst_.scene->world);
106 has_update = wo_handle.recalc != 0;
107 }
108
109 bool wait_ready = true; // TODO !inst_.is_image_render;
110
111 /* Sync volume first since its result can override the surface world. */
112 sync_volume(wo_handle, wait_ready);
113
114 ::World *bl_world;
115 if (inst_.use_studio_light()) {
116 has_update |= lookdev_world_.sync(LookdevParameters(inst_.v3d));
117 bl_world = lookdev_world_.world_get();
118 }
119 else if ((inst_.view_layer->layflag & SCE_LAY_SKY) == 0) {
120 bl_world = default_world_get();
121 }
122 else if (has_volume_absorption_) {
123 bl_world = default_world_get();
124 }
125 else {
126 bl_world = scene_world_get();
127 }
128
129 bNodeTree *ntree = (bl_world->nodetree && bl_world->use_nodes) ?
130 bl_world->nodetree :
131 default_tree.nodetree_get(bl_world);
132
133 {
134 if (has_volume_absorption_) {
135 /* Replace world by black world. */
136 bl_world = default_world_get();
137 }
138 }
139
140 /* We have to manually test here because we have overrides. */
141 ::World *orig_world = DEG_get_original(bl_world);
142 if (assign_if_different(prev_original_world, orig_world)) {
143 has_update = true;
144 }
145
146 inst_.light_probes.sync_world(bl_world, has_update);
147
148 if (inst_.is_viewport() && has_update) {
149 /* Catch lookdev viewport properties updates. */
150 inst_.sampling.reset();
151 }
152
153 GPUMaterial *gpumat = inst_.shaders.world_shader_get(
154 bl_world, ntree, MAT_PIPE_DEFERRED, !wait_ready);
155
156 if (GPU_material_status(gpumat) == GPU_MAT_FAILED) {
157 bl_world = default_world_get();
158 ntree = default_tree.nodetree_get(bl_world);
159 gpumat = inst_.shaders.world_shader_get(bl_world, ntree, MAT_PIPE_DEFERRED, !wait_ready);
160 }
161 if (GPU_material_status(gpumat) == GPU_MAT_QUEUED) {
162 is_ready_ = false;
163 return;
164 }
165 is_ready_ = true;
166
167 inst_.manager->register_layer_attributes(gpumat);
168
169 float opacity = inst_.use_studio_light() ? lookdev_world_.background_opacity_get() :
170 inst_.film.background_opacity_get();
171 float background_blur = inst_.use_studio_light() ? lookdev_world_.background_blur_get() : 0.0;
172
173 inst_.pipelines.background.sync(gpumat, opacity, background_blur);
174 inst_.pipelines.world.sync(gpumat);
175}
176
177void World::sync_volume(const WorldHandle &world_handle, bool wait_ready)
178{
179 /* Studio lights have no volume shader. */
180 ::World *world = inst_.use_studio_light() ? nullptr : inst_.scene->world;
181
182 GPUMaterial *gpumat = nullptr;
183
184 /* Only the scene world nodetree can have volume shader. */
185 if (world && world->nodetree && world->use_nodes) {
186 gpumat = inst_.shaders.world_shader_get(
187 world, world->nodetree, MAT_PIPE_VOLUME_MATERIAL, !wait_ready);
188 }
189
190 bool had_volume = has_volume_;
191
192 if (gpumat && (GPU_material_status(gpumat) == GPU_MAT_SUCCESS)) {
193 has_volume_ = GPU_material_has_volume_output(gpumat);
194 has_volume_scatter_ = GPU_material_flag_get(gpumat, GPU_MATFLAG_VOLUME_SCATTER);
195 has_volume_absorption_ = GPU_material_flag_get(gpumat, GPU_MATFLAG_VOLUME_ABSORPTION);
196 }
197 else {
198 has_volume_ = has_volume_absorption_ = has_volume_scatter_ = false;
199 }
200
201 /* World volume needs to be always synced for correct clearing of parameter buffers. */
202 inst_.pipelines.world_volume.sync(gpumat);
203
204 if (has_volume_ || had_volume) {
205 inst_.volume.world_sync(world_handle);
206 }
207}
208
210
211} // 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:1500
#define SH_NODE_OUTPUT_WORLD
#define SH_NODE_BACKGROUND
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
T * DEG_get_original(T *id)
@ SOCK_OUT
@ SOCK_IN
@ SCE_LAY_SKY
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
@ GPU_MATFLAG_VOLUME_SCATTER
@ GPU_MATFLAG_VOLUME_ABSORPTION
@ GPU_MAT_QUEUED
@ GPU_MAT_FAILED
@ GPU_MAT_SUCCESS
bool GPU_material_has_volume_output(GPUMaterial *mat)
struct blender::bke::bNodeTreeType * ntreeType_Shader
bNodeTree * nodetree_get(::World *world)
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)
#define output
#define MEM_SAFE_FREE(v)
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2864
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3804
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:4087
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
Definition node.cc:4362
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4996
void node_tree_free_embedded_tree(bNodeTree *ntree)
Definition node.cc:4724
bool assign_if_different(T &old_value, T new_value)
struct World * world
struct bNodeTree * nodetree
float horg
short use_nodes
float horb
float sun_threshold
float horr