-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
EEVEE-Next: Add operator to convert a world volume to mesh
EEVEE-Next world volume are infinite like Cycles. EEVEE-Classic world volumes end at the clip_end of the camera/viewport. This can lead to confusion as it would render different then expected. This PR adds an operator to convert a world volume into a mesh volume. The operator can be found in the shader editor (world mode) and in the properties panel/World/Volume. **Why an operator?** As this alters the content of the scene we want the artist to be in control of the conversion. Doing it automatic lead to a lot of complexity and cases that might not be expected by the user. Pull Request: https://projects.blender.org/blender/blender/pulls/119734
- Loading branch information
1 parent
5a76ba9
commit f01e84e
Showing
8 changed files
with
228 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ | |
"uvcalc_transform", | ||
"vertexpaint_dirt", | ||
"view3d", | ||
"world", | ||
"wm", | ||
] | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import bpy | ||
import bmesh | ||
|
||
|
||
class WORLD_OT_convert_volume_to_mesh(bpy.types.Operator): | ||
""" | ||
Convert the volume of a world to a mesh. | ||
The world's volume used to be rendered by EEVEE Legacy. Conversion is needed for it to render properly""" | ||
bl_label = "Convert Volume" | ||
bl_options = {'REGISTER', 'UNDO'} | ||
bl_idname = "world.convert_volume_to_mesh" | ||
|
||
@classmethod | ||
def poll(cls, context): | ||
world = cls._world_get(context) | ||
if not world or not world.use_nodes: | ||
return False | ||
|
||
ntree = world.node_tree | ||
node = ntree.get_output_node('EEVEE') | ||
return bool(node.inputs['Volume'].links) | ||
|
||
def execute(self, context): | ||
cls = self.__class__ | ||
world = cls._world_get(context) | ||
view_layer = context.view_layer | ||
|
||
world_tree = world.node_tree | ||
world_output = world_tree.get_output_node('EEVEE') | ||
name = f"{world.name}_volume" | ||
|
||
collection = bpy.data.collections.new(name) | ||
view_layer.layer_collection.collection.children.link(collection) | ||
|
||
# Add World Volume Mesh object to scene | ||
mesh = bpy.data.meshes.new(name) | ||
object = bpy.data.objects.new(name, mesh) | ||
object.display.show_shadows = False | ||
|
||
bm = bmesh.new() | ||
bmesh.ops.create_icosphere(bm, subdivisions=0, radius=1e5) | ||
bm.to_mesh(mesh) | ||
bm.free() | ||
|
||
# Remove all non-essential attributes | ||
for attribute in mesh.attributes: | ||
if attribute.is_internal or attribute.is_required: | ||
continue | ||
mesh.attributes.remove(attribute) | ||
|
||
material = bpy.data.materials.new(name) | ||
mesh.materials.append(material) | ||
material.use_nodes = True | ||
volume_tree = material.node_tree | ||
for node in volume_tree.nodes: | ||
if node.type != 'OUTPUT_MATERIAL': | ||
volume_tree.nodes.remove(node) | ||
volume_output = volume_tree.get_output_node('EEVEE') | ||
|
||
links_to_add = [] | ||
self.__sync_rna_properties(volume_output, world_output) | ||
self.__sync_node_input( | ||
volume_tree, | ||
volume_output, | ||
volume_output.inputs['Volume'], | ||
world_output, | ||
world_output.inputs['Volume'], | ||
links_to_add) | ||
self.__sync_links(volume_tree, links_to_add) | ||
|
||
# Add transparent volume for other render engines | ||
if volume_output.target == 'EEVEE': | ||
all_output = volume_tree.nodes.new(type="ShaderNodeOutputMaterial") | ||
transparent = volume_tree.nodes.new(type="ShaderNodeBsdfTransparent") | ||
volume_tree.links.new(transparent.outputs[0], all_output.inputs[0]) | ||
|
||
# Remove all volume links from the world node tree. | ||
for link in world_output.inputs['Volume'].links: | ||
world_tree.links.remove(link) | ||
|
||
collection.objects.link(object) | ||
object.select_set(True) | ||
view_layer.objects.active = object | ||
|
||
world.use_eevee_finite_volume = False | ||
|
||
return {"FINISHED"} | ||
|
||
@staticmethod | ||
def _world_get(context): | ||
if hasattr(context, 'world'): | ||
return context.world | ||
return context.scene.world | ||
|
||
def __sync_node_input( | ||
self, | ||
dst_tree: bpy.types.NodeTree, | ||
dst_node: bpy.types.Node, | ||
dst_socket: bpy.types.NodeSocket, | ||
src_node: bpy.types.Node, | ||
src_socket: bpy.types.NodeSocket, | ||
links_to_add) -> None: | ||
self.__sync_rna_properties(dst_socket, src_socket) | ||
for src_link in src_socket.links: | ||
src_linked_node = src_link.from_node | ||
dst_linked_node = self.__sync_node(dst_tree, src_linked_node, links_to_add) | ||
|
||
from_socket_index = src_node.outputs.find(src_link.from_socket.name) | ||
dst_tree.links.new( | ||
dst_linked_node.outputs[from_socket_index], | ||
dst_socket | ||
) | ||
|
||
def __sync_node(self, dst_tree: bpy.types.NodeTree, src_node: bpy.types.Node, links_to_add) -> bpy.types.Node: | ||
""" | ||
Find the counter part of the src_node in dst_tree. When found return the counter part. When not found | ||
create the counter part, sync it and return the created node. | ||
""" | ||
if src_node.name in dst_tree.nodes: | ||
return dst_tree.nodes[src_node.name] | ||
|
||
dst_node = dst_tree.nodes.new(src_node.bl_idname) | ||
|
||
self.__sync_rna_properties(dst_node, src_node) | ||
self.__sync_node_inputs(dst_tree, dst_node, src_node, links_to_add) | ||
return dst_node | ||
|
||
def __sync_rna_properties(self, dst, src) -> None: | ||
for rna_prop in src.bl_rna.properties: | ||
if rna_prop.is_readonly: | ||
continue | ||
|
||
attr_name = rna_prop.identifier | ||
if attr_name in ['bl_idname', 'bl_static_type']: | ||
continue | ||
setattr(dst, attr_name, getattr(src, attr_name)) | ||
|
||
def __sync_node_inputs( | ||
self, | ||
dst_tree: bpy.types.NodeTree, | ||
dst_node: bpy.types.Node, | ||
src_node: bpy.types.Node, | ||
links_to_add) -> None: | ||
for index in range(len(src_node.inputs)): | ||
src_socket = src_node.inputs[index] | ||
dst_socket = dst_node.inputs[index] | ||
self.__sync_node_input(dst_tree, dst_node, dst_socket, src_node, src_socket, links_to_add) | ||
|
||
def __sync_links(self, dst_tree: bpy.types.NodeTree, links_to_add) -> None: | ||
pass | ||
|
||
|
||
classes = ( | ||
WORLD_OT_convert_volume_to_mesh, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters