Scene Setup Module
Functions for configuring Blender scenes, cameras, lighting, and atmosphere.
This module provides all the tools needed to set up professional terrain visualizations in Blender, from camera positioning to HDRI lighting.
Background Plane
- src.terrain.scene_setup.create_background_plane(camera, mesh_or_meshes, distance_below=50.0, color='#F5F5F0', size_multiplier=2.0, receive_shadows=False, flat_color=False, roughness=1.0)[source]
Create a background plane for Blender terrain renders.
Creates a plane mesh positioned below the terrain that fills the camera view. The plane is sized to fill the camera’s frustum with a safety margin and positioned below the lowest point of the terrain mesh(es).
This is useful for adding a clean background color to terrain renders without drop shadows (by default) or with shadows for depth effect.
- Parameters:
camera – Blender camera object to size plane relative to
mesh_or_meshes – Single mesh object or list of mesh objects to position plane below. The plane will be positioned below the lowest Z point.
distance_below (float) – Distance below the lowest mesh point to place the plane (default: 50.0 units)
color (str | tuple) – Color for the background plane as hex string (e.g., “#F5F5F0”) or RGB tuple (default: eggshell white #F5F5F0)
size_multiplier (float) – How much larger than camera frustum to make the plane, for safety margin (default: 2.0, makes plane 2x frustum size)
receive_shadows (bool) – Whether the plane receives shadows from objects (default: False for clean background)
flat_color (bool) – If True, use emission shader for exact color that ignores scene lighting. If False (default), use Principled BSDF that responds to lighting (darker colors may appear lighter due to ambient light).
roughness (float) – Material roughness value 0.0-1.0 when flat_color=False (default: 1.0 = fully matte). Lower values (0.3-0.5) make the surface less affected by ambient light. Only used when flat_color=False.
- Returns:
Blender plane object with material applied and positioned
- Raises:
ValueError – If camera or mesh is invalid
RuntimeError – If called outside of Blender environment
- Return type:
Object
Used in Combined Render: Full-Featured Example for clean backgrounds.
Example:
background = create_background_plane( camera, terrain_mesh, distance_below=50.0, color="#F5F5F0", receive_shadows=True )
Camera Setup
- src.terrain.scene_setup.setup_camera(camera_angle, camera_location, scale, focal_length=50, camera_type='PERSP')[source]
Configure camera for terrain visualization.
- Parameters:
camera_angle – Tuple of (x,y,z) rotation angles in radians
camera_location – Tuple of (x,y,z) camera position
scale – Camera scale value (ortho_scale for orthographic cameras)
focal_length – Camera focal length in mm (default: 50, used only for perspective)
camera_type – Camera type ‘PERSP’ (perspective) or ‘ORTHO’ (orthographic) (default: ‘PERSP’)
- Returns:
Camera object
- Raises:
ValueError – If camera_type is not ‘PERSP’ or ‘ORTHO’
Basic camera creation and configuration.
- src.terrain.scene_setup.position_camera_relative(mesh_obj, direction='south', distance=1.5, elevation=0.5, look_at='center', camera_type='ORTHO', sun_angle=0, sun_energy=0, sun_azimuth=None, sun_elevation=None, focal_length=50, ortho_scale=1.2, distance_mode='diagonal', center_in_frame=True)[source]
Position camera relative to mesh(es) using intuitive cardinal directions.
Simplifies camera positioning by using natural directions (north, south, etc.) instead of absolute Blender coordinates. The camera is automatically positioned relative to the mesh bounds and rotated to point at the mesh center.
Supports multiple meshes by computing a combined bounding box that encompasses all provided mesh objects. This is useful for dual terrain renders or scenes with multiple terrain meshes that need to be viewed together.
- Parameters:
mesh_obj – Blender mesh object or list of mesh objects to position camera relative to. If a list is provided, a combined bounding box is computed.
direction –
Compass direction using 16-wind compass rose, one of: Cardinal: ‘north’, ‘south’, ‘east’, ‘west’ Primary intercardinal: ‘northeast’, ‘southeast’, ‘southwest’, ‘northwest’ Secondary intercardinal: ‘north-northeast’, ‘east-northeast’, ‘east-southeast’,
’south-southeast’, ‘south-southwest’, ‘west-southwest’, ‘west-northwest’, ‘north-northwest’
Special: ‘above’ (directly overhead), ‘above-tilted’ (overhead but angled) Default: ‘south’
distance – Distance multiplier relative to mesh diagonal (e.g., 1.5 means 1.5x mesh_diagonal away). Default: 1.5
elevation – Height as fraction of mesh diagonal added to Z position (0.0 = ground level, 1.0 = mesh_diagonal above ground). Default: 0.5
look_at – Where camera points - ‘center’ to point at mesh center, or tuple (x, y, z) for custom target. Default: ‘center’
camera_type – ‘ORTHO’ (orthographic) or ‘PERSP’ (perspective). Default: ‘ORTHO’
sun_angle – Angular diameter of sun in degrees (affects shadow softness). Default: 0 (no light)
sun_energy – Intensity of sun light. Default: 0 (no light created unless > 0)
sun_azimuth – Direction sun comes FROM in degrees (0=North, 90=East, 180=South, 270=West)
sun_elevation – Angle of sun above horizon in degrees (0=horizon, 90=overhead)
focal_length – Camera focal length in mm (perspective cameras only). Default: 50
ortho_scale – Multiplier for orthographic camera scale relative to mesh diagonal. Higher values zoom out (show more area), lower values zoom in. Only affects orthographic cameras. Default: 1.2
distance_mode –
How to interpret the distance parameter. Options: ‘diagonal’ (default): distance relative to mesh diagonal (scale-independent, backward compat) ‘fit’: photographer-friendly framing mode where distance=1.0 fits mesh in frame,
and camera distance adjusts with elevation to maintain framing
center_in_frame – If True, adjust look_at target to center the mesh’s 2D projection in the camera frame, not just point at the 3D geometric center. This accounts for perspective distortion and viewing angles. Default: True
- Returns:
Camera object
- Raises:
ValueError – If direction is not recognized or camera_type is invalid
Smart camera positioning using cardinal directions (north, south, east, west, above). Used in Combined Render: Full-Featured Example.
Example:
position_camera_relative( camera, terrain_mesh, direction='south', distance_multiplier=2.0, elevation_angle=2.5, tilt_angle=0 )
- src.terrain.scene_setup.calculate_camera_frustum_size(camera_type, aspect_ratio, ortho_scale=None, fov_degrees=None, distance=None)[source]
Calculate the visible area of a camera at a given distance.
Computes the width and height of the camera’s frustum (visible area) at a specified distance. Works with both orthographic and perspective cameras.
For orthographic cameras, the frustum size depends on the ortho_scale parameter. For perspective cameras, the frustum size depends on the FOV and distance from the camera.
- Parameters:
camera_type (str) – Type of camera - “ORTHO” for orthographic or “PERSP” for perspective
aspect_ratio (float) – Render aspect ratio (width / height, typically 16/9 or similar)
ortho_scale (float) – Scale value for orthographic cameras (required for ORTHO type)
fov_degrees (float) – Field of view in degrees for perspective cameras (required for PERSP type)
distance (float) – Distance from camera for frustum calculation (required for PERSP type)
- Returns:
(width, height) of the camera frustum in Blender units
- Return type:
- Raises:
ValueError – If camera_type is invalid or required parameters are missing
TypeError – If parameters have incorrect types
Examples
>>> # Orthographic camera with 2x ortho_scale and 16:9 aspect ratio >>> w, h = calculate_camera_frustum_size("ORTHO", 16/9, ortho_scale=2.0) >>> print(f"Width: {w:.2f}, Height: {h:.2f}") Width: 2.00, Height: 1.12
>>> # Perspective camera with 49.13° FOV at 10 units distance >>> w, h = calculate_camera_frustum_size("PERSP", 16/9, fov_degrees=49.13, distance=10.0) >>> # Result width and height depend on FOV and distance
Calculate camera field of view for precise framing.
Lighting
- src.terrain.scene_setup.setup_two_point_lighting(sun_azimuth=225.0, sun_elevation=30.0, sun_energy=7.0, sun_angle=1.0, sun_color=(1.0, 0.85, 0.6), fill_azimuth=45.0, fill_elevation=60.0, fill_energy=0.0, fill_angle=3.0, fill_color=(0.7, 0.8, 1.0))[source]
Set up two-point lighting with primary sun and optional fill light.
Creates professional-quality lighting for terrain visualization: - Primary sun: Creates shadows and defines form (warm color by default) - Fill light: Softens shadows, adds depth (cool color by default)
The warm/cool color contrast creates a natural outdoor lighting look similar to golden hour photography.
- Parameters:
sun_azimuth (float) – Direction sun comes FROM in degrees (0=N, 90=E, 180=S, 270=W). Default: 225° (southwest, afternoon sun)
sun_elevation (float) – Sun angle above horizon in degrees (0=horizon, 90=overhead). Default: 30° (mid-afternoon)
sun_energy (float) – Sun light strength. Default: 7.0
sun_angle (float) – Sun angular size in degrees (smaller=sharper shadows). Default: 1.0°
sun_color (tuple) – RGB tuple for sun color. Default: (1.0, 0.85, 0.6) warm golden
fill_azimuth (float) – Direction fill light comes FROM in degrees. Default: 45° (northeast, opposite sun)
fill_elevation (float) – Fill light angle above horizon in degrees. Default: 60° (higher angle for even fill)
fill_energy (float) – Fill light strength. Default: 0.0 (no fill light). Set to ~1-3 for subtle fill, ~5+ for strong fill.
fill_angle (float) – Fill light angular size in degrees. Default: 3.0° (softer than sun)
fill_color (tuple) – RGB tuple for fill color. Default: (0.7, 0.8, 1.0) cool blue
- Returns:
List of created light objects (1-2 lights depending on fill_energy)
- Return type:
Examples
>>> # Basic sun-only lighting >>> lights = setup_two_point_lighting(sun_azimuth=180, sun_elevation=45)
>>> # Sun with fill for softer shadows >>> lights = setup_two_point_lighting( ... sun_azimuth=225, sun_elevation=30, sun_energy=7, ... fill_energy=2, fill_azimuth=45, fill_elevation=60 ... )
>>> # Low sun for dramatic shadows >>> lights = setup_two_point_lighting(sun_elevation=10)
Traditional two-point lighting with sun and fill lights.
- src.terrain.scene_setup.setup_hdri_lighting(sun_elevation=30.0, sun_rotation=225.0, sun_intensity=1.0, sun_size=0.545, air_density=1.0, visible_to_camera=False, camera_background=None, sky_strength=None)[source]
Set up HDRI-style sky lighting using Blender’s Nishita sky model.
Creates realistic sky lighting that contributes to ambient illumination without being visible in the final render (by default).
The Nishita sky model provides physically-based atmospheric scattering for natural-looking outdoor lighting.
- Parameters:
sun_elevation (float) – Sun elevation angle in degrees (0=horizon, 90=overhead)
sun_rotation (float) – Sun rotation/azimuth in degrees (0=front, 180=back)
sun_intensity (float) – Multiplier for sun disc brightness in sky texture (default: 1.0)
sun_size (float) – Angular diameter of sun disc in degrees (default: 0.545 = real sun). Larger values create softer shadows, smaller values create sharper shadows.
air_density (float) – Atmospheric density (default: 1.0, higher=hazier)
visible_to_camera (bool) – If False, sky is invisible but still lights scene
camera_background (tuple) – RGB tuple for background color when sky is invisible. Default None = use transparent (black behind scene). Use (0.9, 0.9, 0.9) for light gray if using atmosphere.
sky_strength (float) – Overall sky emission strength (ambient light level). If None, defaults to sun_intensity for backwards compatibility.
- Returns:
The configured world object
- Return type:
bpy.types.World
Environment-based HDRI lighting for photorealistic results. Used in Combined Render: Full-Featured Example.
Example:
setup_hdri_lighting( hdri_path='path/to/hdri.exr', strength=1.0, rotation=0.0 )
- src.terrain.scene_setup.setup_light(location=(1, 1, 2), angle=2, energy=3, rotation_euler=None, azimuth=None, elevation=None)[source]
Create and configure sun light for terrain visualization.
Sun position can be specified either with rotation_euler (raw Blender angles) or with the more intuitive azimuth/elevation system:
azimuth: Direction the sun comes FROM, in degrees clockwise from North (0=North, 90=East, 180=South, 270=West)
elevation: Angle above horizon in degrees (0=horizon, 90=directly overhead)
If azimuth and elevation are provided, they override rotation_euler.
- Parameters:
location – Tuple of (x,y,z) light position (default: (1, 1, 2))
angle – Angular diameter of sun in degrees (default: 2, affects shadow softness)
energy – Energy/intensity of sun light (default: 3)
rotation_euler – Tuple of (x,y,z) rotation angles in radians (legacy, use azimuth/elevation)
azimuth – Direction sun comes FROM in degrees (0=North, 90=East, 180=South, 270=West)
elevation – Angle above horizon in degrees (0=horizon, 90=overhead)
- Returns:
Sun light object
Create individual Blender lights (sun, spot, area, point).
- src.terrain.scene_setup.setup_world_atmosphere(density=0.0002, scatter_color=(1, 1, 1, 1), anisotropy=0.8)[source]
Set up world volume for atmospheric effects.
This function is additive - it preserves any existing Surface shader (like HDRI lighting) and only adds a Volume shader for atmospheric fog.
Note: Density is per-Blender-unit. For terrain scenes that are 100-500 units across, use very low values (0.0001-0.001). Higher values will make the scene very dark or completely black.
- Parameters:
density – Density of the atmospheric volume (default: 0.0002, very subtle) For stronger fog: 0.001. For barely visible haze: 0.0001
scatter_color – RGBA color tuple for scatter (default: white)
anisotropy – Direction of scatter from -1 to 1 (default: 0.8 for forward scatter, creates sun halo effect similar to real atmosphere)
- Returns:
The configured world object
- Return type:
bpy.types.World
Add atmospheric scattering effects.
Example:
setup_world_atmosphere( density=0.0002, scatter_color=(1, 1, 1, 1), anisotropy=0.8 )
Scene Management
- src.terrain.scene_setup.clear_scene()[source]
Clear all objects from the Blender scene.
Resets the scene to factory settings (empty scene) and removes all default objects. Useful before importing terrain meshes to ensure a clean workspace.
- Raises:
RuntimeError – If Blender module (bpy) is not available.
Remove all objects from the scene before setting up.
- src.terrain.scene_setup.setup_camera_and_light(camera_angle, camera_location, scale, sun_angle=2, sun_energy=3, focal_length=50, camera_type='PERSP')[source]
Configure camera and main light for terrain visualization.
Convenience function that calls setup_camera() and setup_light().
- Parameters:
camera_angle – Tuple of (x,y,z) rotation angles in radians
camera_location – Tuple of (x,y,z) camera position
scale – Camera scale value (ortho_scale for orthographic cameras)
sun_angle – Angle of sun light in degrees (default: 2)
sun_energy – Energy/intensity of sun light (default: 3)
focal_length – Camera focal length in mm (default: 50, used only for perspective)
camera_type – Camera type ‘PERSP’ (perspective) or ‘ORTHO’ (orthographic) (default: ‘PERSP’)
- Returns:
(camera object, sun light object)
- Return type:
Legacy combined camera+light setup (consider using individual functions instead).
Utilities
- src.terrain.scene_setup.create_matte_material(name='BackgroundMaterial', color='#F5F5F0', material_roughness=1.0, receive_shadows=False, flat_color=False)[source]
Create a matte material for backgrounds.
Creates either a physically-based matte material or a flat emission material. The flat option is useful when you want an exact color that doesn’t respond to scene lighting (e.g., for studio-style backgrounds).
- Parameters:
name (str) – Name for the material (default: “BackgroundMaterial”)
color (str | tuple) – Color as hex string (e.g., “#F5F5F0”) or RGB tuple (default: eggshell white)
material_roughness (float) – Roughness value 0.0-1.0, 1.0 = fully matte (default: 1.0). Only used when flat_color=False.
receive_shadows (bool) – Whether the material receives shadows (default: False). Only used when flat_color=False.
flat_color (bool) – If True, use pure emission shader for exact color regardless of lighting. The rendered color will match the input color exactly. If False (default), use Principled BSDF which responds to lighting.
- Returns:
Blender Material object configured as specified
- Return type:
Material
Note
This function requires Blender and the bpy module to be available. Call only from within a Blender environment.
- Raises:
RuntimeError – If called outside of Blender environment
- Parameters:
- Return type:
Material
Create matte materials for background objects.
- src.terrain.scene_setup.hex_to_rgb(hex_color)[source]
Convert hex color string to normalized RGB tuple.
Converts hex color strings in various formats (#RRGGBB, #RGB, with or without #) to normalized RGB tuples with values in range 0.0-1.0.
- Parameters:
hex_color (str) – Hex color string in format: - “#RRGGBB” (e.g., “#F5F5F0”) - “#RGB” (e.g., “#FFF”) - “RRGGBB” or “RGB” (without #)
- Returns:
Tuple of (r, g, b) floats in range 0.0-1.0
- Raises:
ValueError – If hex_color format is invalid or contains invalid characters
- Return type:
Examples
>>> r, g, b = hex_to_rgb("#F5F5F0") # Eggshell white >>> r, g, b = hex_to_rgb("FFF") # Pure white >>> r, g, b = hex_to_rgb("#000000") # Pure black
Convert hex color strings to RGB tuples.
Example:
r, g, b = hex_to_rgb("#F5F5F0") # Eggshell white