Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(object,render): add ambient occlusion effect #1174

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions blenderproc/python/renderer/RendererUtility.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,3 +918,38 @@ def set_render_devices(use_only_cpu: bool = False, desired_gpu_device_type: Unio
bpy.context.scene.cycles.device = "CPU"
bpy.context.preferences.addons['cycles'].preferences.compute_device_type = "NONE"
print("Using only the CPU for rendering")


def enable_ambient_occlusion(distance: float = 1.0, strength: float = 1.0):
""" Enables ambient occlusion in the scene. This can improve object part or point separation.

:param distance: Length of rays, defines how far away other faces give occlusion effect.
:param strength: The amount of ambient occlusion effect added to the scene.
"""
bpy.context.scene.view_layers['ViewLayer'].use_pass_ambient_occlusion = True
bpy.context.scene.world.light_settings.distance = distance
bpy.context.scene.use_nodes = True

nodes = bpy.context.scene.node_tree.nodes
render_layers_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeRLayers')
mix_rgb_node = nodes.new('CompositorNodeMixRGB')
mix_rgb_node.blend_type = 'MULTIPLY'
mix_rgb_node.inputs[0].default_value = strength

# Insert the mix-rgb node in between denoise and composite node, if a denoise node is present
links = bpy.context.scene.node_tree.links
try:
denoise_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeDenoise')
Utility.insert_node_instead_existing_link(links,
render_layers_node.outputs['Image'],
mix_rgb_node.inputs['Image'],
mix_rgb_node.outputs['Image'],
denoise_node.inputs['Image'])
except RuntimeError:
composite_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeComposite')
Utility.insert_node_instead_existing_link(links,
render_layers_node.outputs['Image'],
mix_rgb_node.inputs['Image'],
mix_rgb_node.outputs['Image'],
composite_node.inputs['Image'])
Comment on lines +941 to +954
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try:
denoise_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeDenoise')
Utility.insert_node_instead_existing_link(links,
render_layers_node.outputs['Image'],
mix_rgb_node.inputs['Image'],
mix_rgb_node.outputs['Image'],
denoise_node.inputs['Image'])
except RuntimeError:
composite_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeComposite')
Utility.insert_node_instead_existing_link(links,
render_layers_node.outputs['Image'],
mix_rgb_node.inputs['Image'],
mix_rgb_node.outputs['Image'],
composite_node.inputs['Image'])
try:
next_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeDenoise')
except RuntimeError:
next_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeComposite')
Utility.insert_node_instead_existing_link(links,
render_layers_node.outputs['Image'],
mix_rgb_node.inputs['Image'],
mix_rgb_node.outputs['Image'],
next_node.inputs['Image'])

Also, one new problem here is that when enabling/disabling diffusion afterwards, it will probably fail.
But making sure all possible combinations of ao and denoising function calls work, might also lead to a lot of complicated code.
Maybe we can just throw an exception in

render_layer_node = Utility.get_the_one_node_with_type(nodes, 'CompositorNodeRLayers')
, if the render layers are not directly connected to the composite node.
In this way we enforce to always set first the denoising and change ao afterwards.

links.new(render_layers_node.outputs['AO'], mix_rgb_node.inputs[2])
25 changes: 25 additions & 0 deletions blenderproc/python/types/MeshObjectUtility.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,31 @@ def add_auto_smooth_modifier(self, angle: float = 30.0):
modifier = self.blender_obj.modifiers["Smooth by Angle"]
modifier["Input_1"] = np.deg2rad(float(angle))

def add_ambient_occlusion(self, distance: float = 1.0, samples: int = 16, only_local: bool = False):
""" Adds an ambient occlusion effect to the object. This can improve object part or point separation.

:param distance: Length of rays, defines how far away other faces give occlusion effect.
:param samples: Number of rays to trace per shader evaluation.
:param only_local: Only consider the object itself when computing AO.
"""
for material in self.get_materials():
ao_node = material.new_node('ShaderNodeAmbientOcclusion')
ao_node.inputs['Distance'].default_value = distance
ao_node.samples = samples
ao_node.only_local = only_local

# Insert the ambient occlusion node in between the attribute node and the bsdf node, if present
try:
attribute_node = material.get_the_one_node_with_type('ShaderNodeAttribute')
bsdf_node = material.get_the_one_node_with_type('ShaderNodeBsdfPrincipled')
material.insert_node_instead_existing_link(attribute_node.outputs['Color'],
ao_node.inputs['Color'],
ao_node.outputs['Color'],
bsdf_node.inputs['Base Color'])
except RuntimeError:
ao_node.inputs['Color'].default_value = material.get_principled_shader_value('Base Color')
material.set_principled_shader_value('Base Color', ao_node.outputs['Color'])
Comment on lines +562 to +577
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go into the material class.


def mesh_as_trimesh(self) -> Trimesh:
""" Returns a trimesh.Trimesh instance of the MeshObject.

Expand Down