Nodes: Remove "Use Nodes" in Shader Editor for World

Part of https://projects.blender.org/blender/blender/pulls/141278

Blend files compatibility:
If a World exists and "Use Nodes" is disabled, we add new nodes to the
existing node tree (or create one if it doesn't) that emulates the
behavior of a world without a node tree. This ensures backward and
forward compatibility.

Python API compatibility:
- `world.use_nodes` was removed from Python API => **Breaking change**
- `world.color` is still being used by Workbench, so it stays there,
although it has no effect anymore when using Cycles or EEVEE.

Python API changes:
Creating a World using `bpy.data.worlds.new()` now creates a World with
 an empty (embedded) node tree. This was necessary to enable Python
scripts to add nodes without having to create a node tree (which is
currently not possible, because World node trees are embedded).

Pull Request: https://projects.blender.org/blender/blender/pulls/142342
This commit is contained in:
Habib Gahbiche
2025-07-28 14:06:08 +02:00
parent 272178d001
commit 445eceb02a
23 changed files with 184 additions and 192 deletions

View File

@@ -12,20 +12,17 @@ from bpy.app.translations import pgettext_tip as tip_
class CYCLES_OT_use_shading_nodes(Operator):
"""Enable nodes on a material, world or light"""
"""Enable nodes on a material or light"""
bl_idname = "cycles.use_shading_nodes"
bl_label = "Use Nodes"
@classmethod
def poll(cls, context):
return (getattr(context, "material", False) or getattr(context, "world", False) or
getattr(context, "light", False))
return (getattr(context, "material", False) or getattr(context, "light", False))
def execute(self, context):
if context.material:
context.material.use_nodes = True
elif context.world:
context.world.use_nodes = True
elif context.light:
context.light.use_nodes = True

View File

@@ -1456,7 +1456,7 @@ class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
def panel_node_draw(layout, id_data, output_type, input_name):
from bpy_extras.node_utils import find_node_input
if not id_data.use_nodes:
if not isinstance(id_data, bpy.types.World) and not id_data.use_nodes:
layout.operator("cycles.use_shading_nodes", icon='NODETREE')
return False

View File

@@ -1639,9 +1639,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
/* create nodes */
if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
b_world.node_tree())
{
if (new_viewport_parameters.use_scene_world && b_world && b_world.node_tree()) {
BL::ShaderNodeTree b_ntree(b_world.node_tree());
add_nodes(scene, b_engine, b_data, b_scene, graph.get(), b_ntree);

View File

@@ -16,7 +16,7 @@ class WORLD_OT_convert_volume_to_mesh(bpy.types.Operator):
@classmethod
def poll(cls, context):
world = cls._world_get(context)
if not world or not world.use_nodes:
if not world:
return False
ntree = world.node_tree

View File

@@ -120,25 +120,21 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
world = context.world
layout.prop(world, "use_nodes", icon='NODETREE')
layout.separator()
layout.use_property_split = True
if world.use_nodes:
ntree = world.node_tree
node = ntree.get_output_node('EEVEE')
ntree = world.node_tree
node = ntree.get_output_node('EEVEE')
if node:
input = find_node_input(node, "Surface")
if input:
layout.template_node_view(ntree, node, input)
else:
layout.label(text="Incompatible output node")
if node:
input = find_node_input(node, "Surface")
if input:
layout.template_node_view(ntree, node, input)
else:
layout.label(text="No output node")
layout.label(text="Incompatible output node")
else:
layout.prop(world, "color")
layout.label(text="No output node")
class EEVEE_WORLD_PT_volume(WorldButtonsPanel, Panel):
@@ -151,7 +147,7 @@ class EEVEE_WORLD_PT_volume(WorldButtonsPanel, Panel):
def poll(cls, context):
engine = context.engine
world = context.world
return world and world.use_nodes and (engine in cls.COMPAT_ENGINES)
return world and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout

View File

@@ -99,7 +99,8 @@ class NODE_HT_header(Header):
if snode_id:
row = layout.row()
row.prop(snode_id, "use_nodes")
if snode.shader_type != 'WORLD':
row.prop(snode_id, "use_nodes")
if world and world.use_eevee_finite_volume:
row.operator("world.convert_volume_to_mesh", emboss=False, icon='WORLD', text="Convert Volume")

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 42
#define BLENDER_FILE_SUBVERSION 43
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -2951,7 +2951,7 @@ static void image_walk_id_all_users(
}
case ID_WO: {
World *world = (World *)id;
if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
if (world->nodetree && !skip_nested_nodes) {
image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback);
}
image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback);

View File

@@ -19,6 +19,7 @@
#include "DNA_rigidbody_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_world_types.h"
#include "BLI_listbase.h"
#include "BLI_math_numbers.hh"
@@ -1236,6 +1237,59 @@ static void update_format_media_type(ImageFormatData *format)
}
}
static void do_version_world_remove_use_nodes(Main *bmain, World *world)
{
if (world->use_nodes == true) {
return;
}
/* Users defined a world node tree, but deactivated it by disabling "Use Nodes". So we
* simulate the same effect by creating a new World Output node and setting it to active. */
bNodeTree *ntree = world->nodetree;
if (ntree == nullptr) {
/* In case the world was defined through Python API it might have been missing a node tree. */
ntree = blender::bke::node_tree_add_tree_embedded(
bmain, &world->id, "World Node Tree Versioning", "ShaderNodeTree");
}
bNode *old_output = nullptr;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (STREQ(node->idname, "ShaderNodeOutputWorld") && (node->flag & NODE_DO_OUTPUT)) {
old_output = node;
old_output->flag &= ~NODE_DO_OUTPUT;
}
}
bNode *new_output = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_OUTPUT_WORLD);
new_output->flag |= NODE_DO_OUTPUT;
bNode *background = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_BACKGROUND);
version_node_add_link(*ntree,
*background,
*blender::bke::node_find_socket(*background, SOCK_OUT, "Background"),
*new_output,
*blender::bke::node_find_socket(*new_output, SOCK_IN, "Surface"));
bNodeSocket *color_sock = blender::bke::node_find_socket(*background, SOCK_IN, "Color");
color_sock->default_value_typed<bNodeSocketValueRGBA>()->value[0] = world->horr;
color_sock->default_value_typed<bNodeSocketValueRGBA>()->value[1] = world->horg;
color_sock->default_value_typed<bNodeSocketValueRGBA>()->value[2] = world->horb;
color_sock->default_value_typed<bNodeSocketValueRGBA>()->value[3] = 1.0f;
if (old_output != nullptr) {
/* Position the newly created node after the old output. Assume the old output node is at
* the far right of the node tree. */
background->location[0] = old_output->location[0] + 1.5f * old_output->width;
background->location[1] = old_output->location[1];
}
new_output->location[0] = background->location[0] + 2.0f * background->width;
new_output->location[1] = background->location[1];
bNode *frame = blender::bke::node_add_static_node(nullptr, *ntree, NODE_FRAME);
background->parent = frame;
new_output->parent = frame;
}
void do_versions_after_linking_500(FileData *fd, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 9)) {
@@ -1692,6 +1746,12 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 43)) {
LISTBASE_FOREACH (World *, world, &bmain->worlds) {
do_version_world_remove_use_nodes(bmain, world);
}
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@@ -68,7 +68,6 @@ LookdevWorld::LookdevWorld()
bke::node_add_link(*ntree, *background, *background_out, *output, *output_in);
bke::node_set_active(*ntree, *output);
world->use_nodes = true;
world->nodetree = ntree;
/* Create a dummy image data block to hold GPU textures generated by studio-lights. */

View File

@@ -16,41 +16,6 @@
namespace blender::eevee {
/* -------------------------------------------------------------------- */
/** \name Default Material
*
* \{ */
DefaultWorldNodeTree::DefaultWorldNodeTree()
{
bNodeTree *ntree = bke::node_tree_add_tree(nullptr, "World Nodetree", ntreeType_Shader->idname);
bNode *background = bke::node_add_static_node(nullptr, *ntree, SH_NODE_BACKGROUND);
bNode *output = bke::node_add_static_node(nullptr, *ntree, SH_NODE_OUTPUT_WORLD);
bNodeSocket *background_out = bke::node_find_socket(*background, SOCK_OUT, "Background");
bNodeSocket *output_in = bke::node_find_socket(*output, SOCK_IN, "Surface");
bke::node_add_link(*ntree, *background, *background_out, *output, *output_in);
bke::node_set_active(*ntree, *output);
color_socket_ =
(bNodeSocketValueRGBA *)bke::node_find_socket(*background, SOCK_IN, "Color")->default_value;
ntree_ = ntree;
}
DefaultWorldNodeTree::~DefaultWorldNodeTree()
{
bke::node_tree_free_embedded_tree(ntree_);
MEM_SAFE_FREE(ntree_);
}
bNodeTree *DefaultWorldNodeTree::nodetree_get(::World *wo)
{
/* WARNING: This function is not thread-safe. Which is not a problem for the moment. */
copy_v3_fl3(color_socket_->value, wo->horr, wo->horg, wo->horb);
return ntree_;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name World
*
@@ -67,9 +32,9 @@ World::~World()
{
if (default_world_ == nullptr) {
default_world_ = BKE_id_new_nomain<::World>("EEVEE default world");
default_world_->horr = default_world_->horg = default_world_->horb = 0.0f;
default_world_->use_nodes = 0;
default_world_->nodetree = nullptr;
default_world_->nodetree = bke::node_tree_add_tree_embedded(
nullptr, &default_world_->id, "World Nodetree", ntreeType_Shader->idname);
BLI_listbase_clear(&default_world_->gpumaterial);
}
return default_world_;
@@ -131,9 +96,7 @@ void World::sync()
bl_world = world_override;
}
bNodeTree *ntree = (bl_world->nodetree && bl_world->use_nodes) ?
bl_world->nodetree :
default_tree.nodetree_get(bl_world);
bNodeTree *ntree = (bl_world->nodetree) ? bl_world->nodetree : default_world_get()->nodetree;
{
if (has_volume_absorption_) {
@@ -181,7 +144,7 @@ void World::sync_volume(const WorldHandle &world_handle, bool wait_ready)
GPUMaterial *gpumat = nullptr;
/* Only the scene world nodetree can have volume shader. */
if (world && world->nodetree && world->use_nodes) {
if (world && world->nodetree) {
gpumat = inst_.shaders.world_shader_get(
world, world->nodetree, MAT_PIPE_VOLUME_MATERIAL, !wait_ready);
}

View File

@@ -24,27 +24,6 @@ namespace blender::eevee {
class Instance;
/* -------------------------------------------------------------------- */
/** \name Default World Node-Tree
*
* In order to support worlds without node-tree we reuse and configure a standalone node-tree that
* we pass for shader generation. The GPUMaterial is still stored inside the World even if
* it does not use a node-tree.
* \{ */
class DefaultWorldNodeTree {
private:
bNodeTree *ntree_;
bNodeSocketValueRGBA *color_socket_;
public:
DefaultWorldNodeTree();
~DefaultWorldNodeTree();
/** Configure a default node-tree with the given world. */
bNodeTree *nodetree_get(::World *world);
};
/** \} */
/* -------------------------------------------------------------------- */
@@ -63,8 +42,6 @@ class World {
private:
Instance &inst_;
DefaultWorldNodeTree default_tree;
/* Used to detect if world change. */
::World *prev_original_world = nullptr;

View File

@@ -94,6 +94,8 @@ World *ED_preview_prepare_world(Main *pr_main,
const World *world,
ID_Type id_type,
ePreviewRenderMethod pr_method);
World *ED_preview_prepare_world_simple(Main *bmain);
void ED_preview_world_simple_set_rgb(World *world, const float color[4]);
void ED_preview_shader_job(const bContext *C,
void *owner,

View File

@@ -370,6 +370,40 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
return sp->worldcopy;
}
World *ED_preview_prepare_world_simple(Main *pr_main)
{
using namespace blender::bke;
World *world = BKE_world_add(pr_main, "SimpleWorld");
bNodeTree *ntree = world->nodetree;
ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &world->id, "World Nodetree", "ShaderNodeTree");
bNode *background = node_add_node(nullptr, *ntree, "ShaderNodeBackground");
bNode *output = node_add_node(nullptr, *ntree, "ShaderNodeOutputWorld");
node_add_link(*world->nodetree,
*background,
*node_find_socket(*background, SOCK_OUT, "Background"),
*output,
*node_find_socket(*output, SOCK_IN, "Surface"));
node_set_active(*ntree, *output);
world->nodetree = ntree;
return world;
}
void ED_preview_world_simple_set_rgb(World *world, const float color[4])
{
BLI_assert(world != nullptr);
bNode *background = blender::bke::node_find_node_by_name(*world->nodetree, "Background");
BLI_assert(background != nullptr);
auto color_socket = static_cast<bNodeSocketValueRGBA *>(
blender::bke::node_find_socket(*background, SOCK_IN, "Color")->default_value);
copy_v4_v4(color_socket->value, color);
}
static ID *duplicate_ids(ID *id, const bool allow_failure)
{
if (id == nullptr) {
@@ -534,17 +568,16 @@ static Scene *preview_prepare_scene(
else if (sce->world && sp->pr_method != PR_ICON_RENDER) {
/* Use a default world color. Using the current
* scene world can be slow if it has big textures. */
sce->world->use_nodes = false;
sce->world = ED_preview_prepare_world_simple(sp->bmain);
/* Use brighter world color for grease pencil. */
if (sp->pr_main == G_pr_main_grease_pencil) {
sce->world->horr = 1.0f;
sce->world->horg = 1.0f;
sce->world->horb = 1.0f;
const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
ED_preview_world_simple_set_rgb(sce->world, white);
}
else {
sce->world->horr = 0.05f;
sce->world->horg = 0.05f;
sce->world->horb = 0.05f;
const float dark[4] = {0.05f, 0.05f, 0.05f, 0.05f};
ED_preview_world_simple_set_rgb(sce->world, dark);
}
}
@@ -601,10 +634,9 @@ static Scene *preview_prepare_scene(
if (sce->world) {
/* Only use lighting from the light. */
sce->world->use_nodes = false;
sce->world->horr = 0.0f;
sce->world->horg = 0.0f;
sce->world->horb = 0.0f;
sce->world = ED_preview_prepare_world_simple(pr_main);
const float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
ED_preview_world_simple_set_rgb(sce->world, black);
}
BKE_view_layer_synced_ensure(sce, view_layer);

View File

@@ -983,7 +983,6 @@ static wmOperatorStatus new_world_exec(bContext *C, wmOperator * /*op*/)
else {
wo = BKE_world_add(bmain, CTX_DATA_(BLT_I18NCONTEXT_ID_WORLD, "World"));
ED_node_shader_default(C, &wo->id);
wo->use_nodes = true;
}
/* hook into UI */

View File

@@ -538,12 +538,13 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
/* Emission */
bNode *shader, *output;
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, id, "Shader Nodetree", ntreeType_Shader->idname);
bNode *shader, *output;
if (GS(id->name) == ID_WO) {
World *world = (World *)id;
ntree = world->nodetree;
shader = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_BACKGROUND);
output = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_OUTPUT_WORLD);
@@ -799,9 +800,7 @@ void ED_node_set_active(
}
LISTBASE_FOREACH (World *, wo, &bmain->worlds) {
if (wo->nodetree && wo->use_nodes &&
blender::bke::node_tree_contains_tree(*wo->nodetree, *ntree))
{
if (wo->nodetree && blender::bke::node_tree_contains_tree(*wo->nodetree, *ntree)) {
GPU_material_free(&wo->gpumaterial);
}
}

View File

@@ -212,14 +212,10 @@ static Scene *preview_prepare_scene(const Main *bmain,
scene_preview->r.cfra = scene_orig->r.cfra;
/* Setup the world. */
scene_preview->world = ED_preview_prepare_world(
pr_main, scene_preview, scene_orig->world, ID_MA, PR_BUTS_RENDER);
scene_preview->world = ED_preview_prepare_world_simple(pr_main);
ED_preview_world_simple_set_rgb(scene_preview->world, float4{0.05f, 0.05f, 0.05f, 0.05f});
BLI_addtail(&pr_main->materials, mat_copy);
scene_preview->world->use_nodes = false;
scene_preview->world->horr = 0.05f;
scene_preview->world->horg = 0.05f;
scene_preview->world->horb = 0.05f;
ED_preview_set_visibility(pr_main, scene_preview, view_layer, preview_type, PR_BUTS_RENDER);

View File

@@ -53,62 +53,55 @@ void WorldData::init()
pxr::GfVec3f color(1.0f, 1.0f, 1.0f);
ID_LOG("%s", world->id.name);
if (world->use_nodes) {
/* TODO: Create nodes parsing system */
/* TODO: Create nodes parsing system */
bNode *output_node = ntreeShaderOutputNode(world->nodetree, SHD_OUTPUT_ALL);
if (!output_node) {
return;
}
const Span<bNodeSocket *> input_sockets = output_node->input_sockets();
bNodeSocket *input_socket = nullptr;
bNode *output_node = ntreeShaderOutputNode(world->nodetree, SHD_OUTPUT_ALL);
if (!output_node) {
return;
for (auto *socket : input_sockets) {
if (STREQ(socket->name, "Surface")) {
input_socket = socket;
break;
}
const Span<bNodeSocket *> input_sockets = output_node->input_sockets();
bNodeSocket *input_socket = nullptr;
}
if (!input_socket) {
return;
}
if (input_socket->directly_linked_links().is_empty()) {
return;
}
bNodeLink const *link = input_socket->directly_linked_links()[0];
for (auto *socket : input_sockets) {
if (STREQ(socket->name, "Surface")) {
input_socket = socket;
break;
}
}
if (!input_socket) {
return;
}
if (input_socket->directly_linked_links().is_empty()) {
return;
}
bNodeLink const *link = input_socket->directly_linked_links()[0];
bNode *input_node = link->fromnode;
if (input_node->type_legacy != SH_NODE_BACKGROUND) {
return;
}
bNode *input_node = link->fromnode;
if (input_node->type_legacy != SH_NODE_BACKGROUND) {
return;
}
const bNodeSocket &color_input = input_node->input_by_identifier("Color");
const bNodeSocket &strength_input = input_node->input_by_identifier("Strength");
const bNodeSocket &color_input = input_node->input_by_identifier("Color");
const bNodeSocket &strength_input = input_node->input_by_identifier("Strength");
float const *strength = strength_input.default_value_typed<float>();
float const *input_color = color_input.default_value_typed<float>();
intensity = strength[1];
color = pxr::GfVec3f(input_color[0], input_color[1], input_color[2]);
float const *strength = strength_input.default_value_typed<float>();
float const *input_color = color_input.default_value_typed<float>();
intensity = strength[1];
color = pxr::GfVec3f(input_color[0], input_color[1], input_color[2]);
if (!color_input.directly_linked_links().is_empty()) {
bNode *color_input_node = color_input.directly_linked_links()[0]->fromnode;
if (ELEM(color_input_node->type_legacy, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) {
NodeTexImage *tex = static_cast<NodeTexImage *>(color_input_node->storage);
Image *image = (Image *)color_input_node->id;
if (image) {
std::string image_path = cache_or_get_image_file(
scene_delegate_->bmain, scene_delegate_->scene, image, &tex->iuser);
if (!image_path.empty()) {
texture_file = pxr::SdfAssetPath(image_path, image_path);
}
if (!color_input.directly_linked_links().is_empty()) {
bNode *color_input_node = color_input.directly_linked_links()[0]->fromnode;
if (ELEM(color_input_node->type_legacy, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) {
NodeTexImage *tex = static_cast<NodeTexImage *>(color_input_node->storage);
Image *image = (Image *)color_input_node->id;
if (image) {
std::string image_path = cache_or_get_image_file(
scene_delegate_->bmain, scene_delegate_->scene, image, &tex->iuser);
if (!image_path.empty()) {
texture_file = pxr::SdfAssetPath(image_path, image_path);
}
}
}
}
else {
intensity = 1.0f;
color = pxr::GfVec3f(world->horr, world->horg, world->horb);
}
if (texture_file.GetAssetPath().empty()) {
float fill_color[4] = {color[0], color[1], color[2], 1.0f};

View File

@@ -233,7 +233,7 @@ void world_material_to_dome_light(const USDExportParams &params,
WorldNtreeSearchResults res(params, stage);
if (scene->world->use_nodes && scene->world->nodetree) {
if (scene->world->nodetree) {
/* Find the world output. */
bNode *output = nullptr;
const bNodeTree *ntree = scene->world->nodetree;
@@ -255,8 +255,8 @@ void world_material_to_dome_light(const USDExportParams &params,
}
else {
res.world_intensity = 1.0f;
copy_v3_v3(res.world_color, &scene->world->horr);
res.background_found = !is_zero_v3(res.world_color);
zero_v3(res.world_color);
res.background_found = false;
}
if (!(res.background_found || res.env_tex_found)) {
@@ -356,10 +356,6 @@ void dome_light_to_world_material(const USDImportParams &params,
return;
}
if (!scene->world->use_nodes) {
scene->world->use_nodes = true;
}
if (!scene->world->nodetree) {
scene->world->nodetree = bke::node_tree_add_tree_embedded(
nullptr, &scene->world->id, "Shader Nodetree", "ShaderNodeTree");

View File

@@ -78,7 +78,8 @@ typedef struct World {
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
short pr_texture, use_nodes;
short pr_texture;
short use_nodes DNA_DEPRECATED;
char _pad[4];
/* previews */

View File

@@ -522,6 +522,9 @@ static World *rna_Main_worlds_new(Main *bmain, const char *name)
World *world = BKE_world_add(bmain, safe_name);
id_us_min(&world->id);
world->nodetree = blender::bke::node_tree_add_tree_embedded(
bmain, &world->id, "World Node Tree", "ShaderNodeTree");
WM_main_add_notifier(NC_ID | NA_ADDED, nullptr);
return world;

View File

@@ -70,21 +70,6 @@ static void rna_World_draw_update(Main * /*bmain*/, Scene * /*scene*/, PointerRN
WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
}
static void rna_World_use_nodes_update(bContext *C, PointerRNA *ptr)
{
World *wrld = (World *)ptr->data;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
if (wrld->use_nodes && wrld->nodetree == nullptr) {
ED_node_shader_default(C, &wrld->id);
}
DEG_relations_tag_update(bmain);
rna_World_update(bmain, scene, ptr);
rna_World_draw_update(bmain, scene, ptr);
}
void rna_World_lightgroup_get(PointerRNA *ptr, char *value)
{
LightgroupMembership *lgm = ((World *)ptr->owner_id)->lightgroup;
@@ -258,13 +243,6 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based worlds");
prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "use_nodes", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes to render the world");
RNA_def_property_update(prop, 0, "rna_World_use_nodes_update");
/* Lightgroup Membership */
prop = RNA_def_property(srna, "lightgroup", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(

View File

@@ -934,8 +934,10 @@ def render_output(scene, bounds, filepath):
scene.render.filepath = filepath
world = bpy.data.worlds.new(name_gen)
world.color = 1.0, 1.0, 1.0
world.use_nodes = False
output = world.node_tree.nodes.new("ShaderNodeOutputWorld")
background = world.node_tree.nodes.new("ShaderNodeBackground")
world.node_tree.links.new(output.outputs["Surface"], background.outputs["Surface"])
background.inputs["Color"].default_value = 1.0, 1.0, 1.0, 1.0
scene.world = world
# Some space around the edges.