Skip to content

About

Apex is the first in a series of Pixelsonly Racing product visualization scenes for Blender.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Apex Studio for Blender

A Pixelsonly Racing product photography scene.

A Python script that builds a complete studio product photography scene in Blender from a single execution. Apex is the first in a series of Pixelsonly Racing product viz scenes — designed for the brand's dark, premium aesthetic (matte black products on a #1F1F21 cyclorama backdrop) and calibrated for fist-to-shoebox accessories at close camera distance.

The script handles the studio. You handle the product.


What this produces

A single execution gives you a reusable .blend template with:

  • A seamless cyclorama backdrop in the Pixelsonly Racing brand color (#1F1F21)
  • A calibrated four-light rig that creates proper rim separation on dark-on-dark products
  • A 100mm camera with shallow DoF, auto-tracking the subject
  • Cycles + Metal + OpenImageDenoise rendering at 4096×4096
  • AgX color management with a subtle contrast curve
  • Four configured view layers producing three layered compositing passes — product, backdrop, and shadow — for free recompositing in any image editor

Open the template, import your product, render, done.

Blender viewport of Apex Studio from Pixelsonly Racing


About the Apex name

In motorsport, the apex is the inside point of a corner — the moment a driver hits the perfect line, the geometric peak of the turn. It's also the word for the top of anything: peak, summit, first.

Apex is the first Pixelsonly Racing studio scene and sets the visual standard for everything that follows — hence the name. Subsequent studios will follow the same motorsport-themed convention, each with a name evoking a different part of the racing world. Naming them individually makes it clear at a glance which workflow and aesthetic you're loading, and keeps templates from getting confused as the library grows.


Features

  • One-script setup. Builds the entire scene from a fresh Blender file in under a second.
  • Calibrated for product viz scale. Light energies tuned for fist-to-shoebox products at 0.5m camera distance (~2W baseline, not the studio-strobe values most tutorials suggest).
  • Layered compositing output. Three separate PNGs (product on alpha / backdrop solid / shadow on alpha) drop straight into your image editor as a layer stack.
  • Dark-on-dark optimized. Backdrop material and rim lighting designed for matte black products on #1F1F21 without losing silhouette definition.
  • Track To everywhere. Camera and all four lights aim at a single Subject_Anchor empty, so moving any of them keeps the product in focus and centered.
  • One-handle lighting orbit. Rotate the Light_Rig parent empty to spin the entire light setup around the product.
  • Pre-calibrated materials. Two default product materials included — Product_MatteBlack (powder coat) and Product_StainlessSteel (polished hardware) — ready to assign to imported geometry.
  • Mac-first development. Tested on Apple Silicon with Metal acceleration. Should work cross-platform but device setup may differ.

Requirements

Component Required Notes
Blender 5.1.1 or newer API targets 5.1; 5.0 and earlier untested
OS macOS (tested) Linux/Windows should work; device setup may need adjustment
GPU Apple Silicon strongly recommended Cycles + Metal at 4K renders in ~30s on M4 Max
RAM 16 GB minimum 64 GB ideal for working with HDRIs and large products
Disk ~5 GB free For rendered output

Reference development environment:

  • Blender 5.1.1
  • macOS Tahoe 26.5
  • Mac Studio M4 Max, 64 GB RAM
  • Cycles render engine with Metal GPU

Repository structure

.
├── README.md                  ← this file
├── apex_studio_scene.py       ← the scene builder script
├── templates/                 ← (suggested) save built templates here
│   └── apex_template.blend
├── renders/                   ← script outputs render here by default
│   ├── product_0001.png
│   ├── backdrop_0001.png
│   └── shadow_0001.png
└── reference/                 ← (suggested) calibration shots, example renders

Quick start

  1. Clone this repository: git clone https://github.com/pixelsonly-racing/blender-studio-apex.git
  2. Open Blender 5.1.1+, then File > New > General to start from a clean slate
  3. Switch to the Scripting workspace (top tabs)
  4. In the text editor: Text > Open, then select apex_studio_scene.py
  5. Press Alt+P (⌥P on Mac) to run, or click the play button
  6. The scene builds. File > Save As templates/apex_template.blend — that's your reusable base for any Pixelsonly Racing product rendered in the Apex aesthetic.

After this, you only need to re-run the script if you want to rebuild the template from scratch with new defaults. For routine product work, just open the template.


Workflow per product

1. Export from Fusion 360

In Fusion, right-click your component → Save as Mesh:

Setting Value
Format OBJ
Refinement Custom
Surface Deviation 0.005 mm
Normal Deviation 10°
Structure One File

Tighter values are fine for hero close-ups; the above is calibrated to avoid visible faceting on curved surfaces under 4K rendering without producing absurdly heavy files.

2. Set up a working file

  1. Open apex_template.blend
  2. File > Save As a new working file named after the product (preserves the template)

3. Import the product

File > Import > Wavefront (.obj)

Import setting Value Why
Forward Axis Y Matches Fusion's coordinate system
Up Axis Z Matches Fusion's coordinate system
Scale 0.001 (typically) Fusion exports in mm; Blender uses meters. Verify with N panel Dimensions after import — should match real product size in mm

If dimensions look way off, try scale 0.01 (cm-based Fusion docs) or 0.0254 (inch-based). When in doubt, set scale to 1.0, check the natural dimensions, and divide.

4. Place the product in the scene

  1. In the Outliner, drag the imported mesh into the Product collection
  2. Open Material Properties and assign the appropriate default material to each material slot:
    • Product_MatteBlack for powder-coated body parts — Pixelsonly Racing's signature finish
    • Product_StainlessSteel for hardware (bolts, screws, machined edges, stainless components)
  3. Build custom materials for any other surfaces (anodized aluminum, brass, painted accents, etc.) — Blender's Principled BSDF can match most real-world materials with a handful of values

5. Center the camera on the product

Subject_Anchor defaults to z=0 (floor level). To center the camera/lights on your specific product's visual center:

Option A — manual: Select Subject_Anchor, press N, set Location Z to roughly half the product's height in meters (e.g., 0.025 for a 50mm tall product).

Option B — automatic: With the imported product selected, open the Scripting workspace's Python Console and run:

snap_anchor_to_object()

This snaps the anchor to the geometric center of the selected object.

6. Render

Hero shot:

Press F12. The full Cycles render appears in the render window. Save manually if you want this hero shot.

Layered compositing passes:

  1. In the Python Console, run setup_shadow_catcher_pass() with the product selected. This configures the backdrop as a shadow catcher and the product as a holdout for the shadow pass.
  2. Press F12 again.
  3. Three named PNGs appear in renders/:
    • product_0001.png — product on transparent background
    • backdrop_0001.png — clean brand-color backdrop
    • shadow_0001.png — just the contact shadow on transparent

Drag all three into Pixelmator Pro (or any image editor) as a layer stack:

  1. Open backdrop_0001.png as your base document
  2. Drag shadow_0001.png in as a layer above the backdrop; set blend mode to Multiply
  3. Drag product_0001.png in as the top layer
  4. Each layer is independently editable — change the backdrop tone, lift or darken the shadow, adjust the product without touching anything else

Configuration reference

All defaults live in the CONFIG dictionary at the top of the script. Edit and re-run to rebuild the template from scratch with new values.

Brand

Parameter Default Description
backdrop_hex "#1F1F21" Studio backdrop color; matches shop.pixelsonly.racing background
world_ambient_hex "#0A0A0B" Ambient color for the world environment
world_strength 0.05 World strength; keep low so the four-light rig does the actual lighting work

Subject

Parameter Default Description
subject_center_z 0.0 Initial anchor height in meters; reposition after import

Camera

Parameter Default Description
camera_focal_length 100 Lens focal length in mm; classic product viz length
camera_distance 0.55 Distance from subject in meters
camera_elevation 8 Angle above horizon in degrees
camera_fstop 8.0 Aperture; controls depth of field falloff

Render

Parameter Default Description
resolution (4096, 4096) Output dimensions in pixels
samples_max 1024 Max Cycles samples (adaptive sampling)
samples_min 64 Minimum samples per pixel
adaptive_threshold 0.005 Noise threshold; tighter = more samples in dark areas

Light energies (watts)

Parameter Default Description
key_energy 2.0 Key light (upper-left softbox), slight warmth
fill_energy 1.5 Fill light (right side), slight coolness
rim_back_energy 2.0 Rim light behind subject; draws silhouette against dark backdrop
rim_top_energy 1.5 Top accent for hardware highlights (bolts/screws)

A note on the watt values: Blender area light "Power" represents total radiant flux in watts. For a small product photographed close (0.5m), even single-digit wattages produce significant irradiance — much more than the hundreds of watts you'd see on a real studio strobe rated for several meters of working distance. If you find yourself reaching for 50W+ values, something is off with your scene scale.

Output

Parameter Default Description
render_output_dir "//renders/" Output path relative to the .blend file

Tips for adjustments

Camera movement

Studio_Cam has a Track To constraint pointing at Subject_Anchor, so any translation keeps the camera aimed at the product.

Shortcut What it does
G, Y, then drag or type Dolly along world Y (closer/farther from initial position)
G, Z, then drag or type Move up/down for high/low angle
G, X, then drag or type Side-to-side for 3/4 angle
G, Z, Z Same axis as before, but in the camera's local space
N panel → Item → Location Direct numeric editing for precise positioning

To orbit around the subject like a turntable, add an empty at the anchor's location, parent the camera to it (Ctrl+P → Object Keep Transform), and rotate the empty.

Lighting

The four lights live under Light_Rig, a parent empty. Rotate the rig to orbit the entire lighting setup around the product without touching individual lights:

Select Light_Rig → R, Z, [angle in degrees], Enter

Common adjustments:

What you want What to change
Darker backdrop, same product illumination Drop Rim_Back power; it spills most onto the floor
More silhouette separation Raise Rim_Back, but watch backdrop brightness
Hardware (bolts/screws) more visible Raise Rim_Top_Accent slightly
Softer overall feel Increase area light size in Object Data Properties without changing power
Punchier hero shot Switch view transform Look to "AgX - Punchy" in Render Properties → Color Management

Materials

The script creates three default materials, ready to use as-is or duplicate and tune per product.

Product_MatteBlack — powder-coated matte black aluminum, Pixelsonly Racing's signature finish:

  • Base Color #0A0A0A — very dark but not pure black, which would absorb all light and read flat
  • Roughness 0.45 — slightly satin, not perfectly matte
  • Metallic 0.0 — dielectric (paint/powder coat), not bare metal
  • Coat Weight 0.25 — subtle clearcoat for the powder-coat shimmer
  • Coat Roughness 0.2 — slightly diffused clearcoat highlights

Product_StainlessSteel — polished 304-grade stainless, for hardware (bolts, screws) and stainless components:

  • Base Color #E0E0E4 — slightly cool light gray; for metallic materials this represents the F0 reflectance color
  • Metallic 1.0 — full metal
  • Roughness 0.25 — polished but not mirror

To switch to other finishes, just adjust Roughness:

  • 0.15 — mirror polish
  • 0.40 — brushed/satin finish
  • 0.50–0.60 — industrial / heavily machined

For a true brushed look with directional reflections, enable Anisotropic (~0.5) and add an Anisotropic Rotation to align with the brush direction.

Backdrop_Mat is locked to maximum diffuse:

  • Roughness 0.95 — essentially no specular highlights from the lights
  • Specular IOR Level 0.1 — minimal dielectric specular contribution
  • Change Base Color to switch brand backdrop colors without touching anything else

Multi-material products

If your Fusion file has multiple bodies with different appearances, the OBJ import will create multiple material slots on the imported mesh. The slots will likely all have generic default materials.

To unify:

  1. Select the product
  2. In Material Properties, click each slot in the list
  3. Use the material dropdown to assign Product_MatteBlack (or your custom material) to each

To keep them separate (e.g., body in matte black, hardware in brushed aluminum), build a second material and assign it to the specific slots that represent those parts.


View layers and compositing passes

The scene creates four view layers, each rendering the scene with different visibility:

View Layer Output File What renders
Combined (saved manually via F12 render window) Hero shot with everything visible
Product_Only product_####.png Product on transparent background
Backdrop_Only backdrop_####.png Clean backdrop, no product
Shadow_Only shadow_####.png Contact shadow on transparent

The three layered passes write automatically to renders/ via File Output nodes in the Compositor when you hit F12 — no manual save needed.

Compositing the passes in Pixelmator Pro:

  1. Open backdrop_0001.png as your base document
  2. Drag shadow_0001.png in as a layer above the backdrop
  3. Set the shadow layer's blend mode to Multiply so it darkens the backdrop where the shadow falls
  4. Drag product_0001.png in as the top layer
  5. Each layer is independently editable: change the backdrop color, lift or darken the shadow opacity, mask the product, add highlights, etc.

Troubleshooting

Render looks identical regardless of light or world changes

You're in Material Preview mode, not Rendered. The viewport shading icons in the top-right of the 3D viewport look nearly identical. Material Preview uses Blender's built-in HDRI environment and ignores your world/light setup; Rendered uses the actual scene.

Click the rightmost sphere icon. Hover each one to confirm — the tooltip should say "Rendered."

Product imports tiny or huge

Fusion writes OBJ vertex coords in your document's units. Blender's OBJ importer assumes meters by default. For a Fusion document in millimeters (the default), set Import → Scale to 0.001. Verify with N panel Dimensions after import.

Product appears at the bottom of the camera frame

Subject_Anchor is at a different height than your product's visual center. Edit the anchor's Z location in the N panel to match, or run snap_anchor_to_object() with the product selected.

Product appears chrome/silver instead of matte black

  • The product has multiple material slots and only one got the matte black assignment
  • The material's Metallic is set to 1.0 instead of 0.0
  • The imported mesh still has its default Blender white material assigned

Check Material Properties carefully — each slot independently.

Backdrop reads as mid-gray instead of dark brand color

  • Verify Backdrop_Mat Roughness is 0.95 and Specular IOR Level is 0.1
  • Drop Rim_Back power; this is almost always the cause
  • Verify World Strength isn't bumped above 0.05

Hiding parent empty doesn't disable child lights

Blender behavior: hiding a parent collection or empty doesn't propagate to children. Either click each child light's visibility icon individually, or select all lights in the viewport and press H.

Camera scroll changes lens instead of zooming

This is expected in camera view. Use G, Y to dolly the camera physically closer.


Known limitations

  • Shadow catcher is per-object, not per-view-layer. The setup_shadow_catcher_pass() helper enables it globally; you need to toggle it off for hero renders and back on for the layered passes. A future version will likely solve this cleanly with duplicate backdrop geometry.
  • No HDRI environment by default. The scene relies entirely on the four-light rig plus a near-black world. Adding an HDRI variant is on the roadmap.
  • OBJ-only import path is tested. STEP files require a separate add-on (see STEP files below). FBX should work but is untested.
  • Single hero shot per render. No turntable or multi-angle setup; adding one is straightforward but currently manual.

STEP files

Blender 5.x has no native STEP import. If you want to skip OBJ and import STEP directly, the main options as of mid-2026:

  • SimLab STEP Importer — commercial, explicit Blender 5.1 + macOS support, 14-day trial
  • STEPmac (Gumroad) — macOS-specific, cheap, Apple Silicon builds available; 5.1 compatibility may need testing
  • FreeCAD as intermediary — free, reliable: open STEP in FreeCAD, export as OBJ, import into Blender

The OBJ-from-Fusion path is the simplest and most reliable workflow if your design source is Fusion.


Roadmap

Possible future work for the Apex studio, ordered roughly by usefulness:

  • v3: Clean shadow catcher via duplicate-backdrop geometry — no more manual toggling
  • v3: HDRI environment variant for products that benefit from environmental reflections
  • v3: Turntable rig for multi-angle product cards
  • v3: Operator-style installable Blender add-on instead of a one-shot script
  • Eventually: Multi-camera batch rendering for capturing several angles in a single render run

Sibling studios planned, each in its own repository under the pixelsonly org, following the same motorsport-themed naming convention:

  • Large-format scene — for the upcoming 24×36" metal track poster line; different scale, different lighting, name TBD
  • Lifestyle/context scene — context renders showing Pixelsonly Racing products integrated into sim rigs; name TBD

License

This project is licensed under the MIT License — see LICENSE for the full text.

Copyright © 2026 Ryan Lindsey / Pixelsonly Racing. All rights reserved.


Credits

Built for Pixelsonly Racing — premium sim racing accessories.

Calibrated against real renders of the DDU Link mount and other Pixelsonly Racing products on the brand backdrop.


Contributing

This is currently a single-author project supporting an internal Pixelsonly Racing product photography workflow, but contributions are welcome. If you adapt this for a different product category, brand backdrop, or output pipeline, open an issue or PR — the script's CONFIG dict is designed to be customized rather than forked.

About

Apex is the first in a series of Pixelsonly Racing product visualization scenes for Blender.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages