Repository navigation
[BUG] blender_export: transparent_background removes the environment light (metals render black) and directional light positions are silently ignored #956
Description
A note before you read on: I'm a hardware engineer, not a Blender/Python person,
as you may remember from my previous (considerably less technical) bug reports :-).
Full transparency: the analysis below was done by an AI assistant (Claude) while it
was setting up our KiBot CI. I did drive and check the process myself: I saw the
black renders, watched the A/B screenshots being produced from the exact
configs quoted below, and the fixes genuinely solved it in our CI image. But if you
ask me pointed questions about Blender internals I'll be out of my depth quickly;
I'll relay them to the assistant and come back with answers. I figured a
well-documented report was still more useful to you than no report at all, so please
take it with the appropriate grain of salt.
Describe the bug
Two findings in blender_scripts/blender_export.py (KiBot 1.9.1, Blender 4.2.4 LTS):
-
transparent_background: trueremoves the environment light, metals render
black. Two different things are involved in Blender: the world (the environment
sphere around the scene, used by Cycles for indirect lighting and for what shiny
surfaces reflect) and the film (film_transparent, an output setting that writes
alpha 0 where no object is seen, without touching the lighting). In the script the
background1/2gradient is implemented as the world, and the code does
if transparent_background: film_transparent = Trueelse
create_background_gradient(): with the option on, no world is created at all, the
scene is surrounded by black. Diffuse surfaces (mask, packages) are still lit by the
sun, but metallic materials (ENIG pads and rails, solder, pins) only reflect their
environment, so they render near-black. This is independent of the view transform
(same result with the default AgX and withStandard). -
SUN/SPOT/AREA light positions are silently ignored.
BlenderLightOptions
documentspos_x/pos_y/pos_zfor every light type, but the script only sets
light_ob.location = pos. For directional lights Blender uses the object's
rotation, not its location, so every configured sun position produces the same
straight-down sun (default rotation). Two configs with very different sun positions
give byte-identical renders (RMS difference 0.00).
To Reproduce
Issue 1, two outputs identical except transparent_background:
outputs:
- name: opaque
type: blender_export
options:
light: [{name: sun, type: SUN, pos_x: '-size', pos_y: 'size', pos_z: 'size*4', energy: 4}]
render_options:
samples: 40
resolution_x: 1920
resolution_y: 1080
transparent_background: false # default: gradient drawn AND used as world
background1: '#8a8378'
background2: '#e8e2d4'
point_of_view: [{view: top, rotate_x: 40, rotate_z: 10}]
outputs: [{type: render, output: '%i_opaque.%x'}]
- name: transparent
type: blender_export
extends: opaque
options:
render_options:
samples: 40
resolution_x: 1920
resolution_y: 1080
transparent_background: true # no world is created: metals reflect black
background1: '#8a8378'
background2: '#e8e2d4'
point_of_view: [{view: top, rotate_x: 40, rotate_z: 10}]
outputs: [{type: render, output: '%i_transparent.%x'}](render_options and point_of_view are repeated because extends merges options
one level deep.)
Issue 2, two outputs identical except the sun position:
# A # B
light: [{name: sun, type: SUN, light: [{name: sun, type: SUN,
pos_x: '-size', pos_y: 'size', pos_x: '-size*0.25', pos_y: 'size*0.25',
pos_z: 'size*4', energy: 1}] pos_z: 'size*5', energy: 1}]Run as kibot -c project.kibot.yaml -b board.kicad_pcb -d out opaque transparent
(issue 1) or with the two outputs A and B (issue 2). The board is a client design I can't publish; it is a 6-layer ENIG
PCB whose stackup copper_finish "ENIG" is correctly propagated to the .pcb3d
(pcb2blender applies its ENIG material, so metals are what shows the problem). Neither
issue depends on the board; I can prepare a minimal public example if useful.
Expected behavior
- A transparent background should only change the output alpha, not the lighting:
the world should stay what it is with an opaque background. Verified fix: keep
creating the gradient world and only add the transparent film on top, i.e. replace
theelif transparent_background ... else: create_background_gradientbranches
with:
else:
# The gradient is also the environment light: keep it even when the
# film is transparent, otherwise metals reflect a black world
create_background_gradient(render.get('background1', '#66667F'), render.get('background2', '#CCCCE5'))
if render.get('transparent_background'):
r.film_transparent = True
r.image_settings.color_mode = 'RGBA'With this the output keeps its transparent alpha (corners alpha 0) and the board is
lit as with an opaque background: mean luminance of the opaque pixels 27.9 -> 114.3,
bright metal pixels 0.1 % -> 23.7 % (screenshot below). An optional world colour or
HDRI decoupled from the visible background would be a nice extra, not needed for the
fix.
pos_x/pos_y/pos_zshould aim directional lights at the board. One-line fix after
light_ob.location = pos:
if typ in ('SUN', 'SPOT', 'AREA'):
light_ob.rotation_euler = (-mathutils.Vector(pos)).to_track_quat('-Z', 'Y').to_euler()With this, configs A and B above produce genuinely different lighting (RMS 9.1),
letting users control the specular highlights on solder fillets.
Screenshots
All screenshots are crops of the same region of the board (client design). The red
boxes are the spots where the colours quoted below each image were measured.
Issue 1, same scene and view transform, gradient background vs transparent background:
Issue 1, stock script vs the fix above, transparent background (checkerboard = alpha 0):
Issue 2, configs A and B before the fix (byte-identical):
Issue 2, after the fix:
Environment (please complete the following information):
- CI/CD workflow: self-hosted GitLab CI (docker executor).
- GitHub action: no.
- Docker image:
ghcr.io/inti-cmnb/kicad10_auto_full:dev_1.9.1-dc4733c_k10.0.4_d13.2_b4.2.4LTS
(KiBot 1.9.1, KiCad 10.0.4, Blender 4.2.4 LTS, Debian 13.2). Both findings were
reproduced on an image whose only additions are thekicad-packages3dDebian package
andpatch; the fixes were applied afterwards as a downstream patch on
blender_export.py. Dockerfile available on request. - Desktop: not tested (renders are produced by the CI image only).
Additional context
We currently carry the fixes as a downstream patch in our CI image (light aiming and
an optional HDRI world that survives transparent_background). Happy to prepare a PR
if the approach suits you.
Activity
[-]blender_export: transparent_background removes the environment light (metals render black) and directional light positions are silently ignored[/-][+][BUG] blender_export: transparent_background removes the environment light (metals render black) and directional light positions are silently ignored[/+]