Skip to content

Commit

Permalink
ENH: use compositor to set solid background (#21)
Browse files Browse the repository at this point in the history
* Fixes #17

* Use the Blender compositor to mix in a user-specified
`rgba` tuple-based background color. Default for rendering
remains to not use compositing.

* Add a crude regression test to probe that the compositor
color setting properly propagates to the appropriate node.
We discussed doing image comparisons on actual renders on Monday
night, but I think we're hesitant because of technical issues
with doing so in i.e., GitHub actions runners.
  • Loading branch information
tylerjereddy authored Mar 1, 2025
1 parent b4ff75d commit d99edad
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
7 changes: 6 additions & 1 deletion ggmolvis/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .world import World, Location, Rotation
from . import SESSION
from .renderer import Renderer, MovieRenderer
from .compositor import _set_compositor_bg

class Camera(GGMolvisArtist):
"""Class for the camera."""
Expand Down Expand Up @@ -82,12 +83,16 @@ def render(self,
mode='image',
frame=None,
filepath=None,
resolution=(640, 360)):
resolution=(640, 360),
composite_bg_rgba=None):
"""Render the scene with this camera"""
bpy.context.scene.camera = self.object
if frame is not None:
bpy.context.scene.frame_set(frame)

if composite_bg_rgba is not None:
_set_compositor_bg(composite_bg_rgba)

if mode == 'image':
renderer = Renderer(resolution=resolution,
filepath=filepath)
Expand Down
31 changes: 31 additions & 0 deletions ggmolvis/compositor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import bpy


def _set_compositor_bg(rgba: tuple[float, float, float, float]):
"""
Set a solid output background color using the compositor.
Parameters
----------
rgba: tuple
The red, green, blue, and alpha float values to use
for the solid background color mixed in by the
compositor.
"""
scene = bpy.context.scene
scene.render.use_compositing = True
scene.use_nodes = True
nodes = scene.node_tree.nodes
links = scene.node_tree.links
nodes.clear()
render_layers = nodes.new(type="CompositorNodeRLayers")
composite = nodes.new(type="CompositorNodeComposite")
color_node = nodes.new(type="CompositorNodeValue")
mix_node = nodes.new(type="CompositorNodeMixRGB")
color_node.outputs[0].default_value = 1.0
mix_node.blend_type = 'MIX'
mix_node.inputs[0].default_value = 1.0
mix_node.inputs[1].default_value = rgba
links.new(render_layers.outputs['Alpha'], mix_node.inputs[0])
links.new(render_layers.outputs['Image'], mix_node.inputs[2])
links.new(mix_node.outputs[0], composite.inputs[0])
27 changes: 27 additions & 0 deletions ggmolvis/tests/test_compositor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import bpy
from ggmolvis import compositor


import pytest
from numpy.testing import assert_allclose



@pytest.mark.parametrize("rgba", [
(0.0, 0.0, 0.0, 1.0), # black
(0.3, 0.1, 0.9, 1.0), # mixture color
# compositor allows > 1.0 intensities
(5.0, 0.0, 0.0, 1.0),
])
def test_basic_background_setting(rgba):
# verify that a simple scene has its composited
# background "color" properly set
bpy.ops.scene.new(type='NEW')
bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, 0))
compositor._set_compositor_bg(rgba)
nodes = bpy.context.scene.node_tree.nodes
for n in nodes:
if "MixRGB" in n.bl_idname:
actual = n.inputs[1].default_value
assert_allclose(actual, rgba)
bpy.ops.scene.delete()

0 comments on commit d99edad

Please sign in to comment.