4. Lights¶
Lighting transforms flat 3D scenes into vibrant, realistic visuals. In previous chapters, we did not explicitly set the lights because Vuer provides default lights. This chapter will show you how to upgrade that simple setup to professional, cinematic lighting like this:
The above scene uses a sophisticated four-light setup with warm/cool color contrast and soft shadows. Weâll learn how to build this step by step, starting with the fundamentals.
Light Types¶
Vuer provides six main light types. In our optimized scene above, we use AmbientLight, SpotLight, and RectAreaLight. Letâs explore all available types:
Click the show/hide button in the left-hand list to control the light switch and view the effects of different lights and their combinations.
Starting with Basic Lighting¶
Letâs start by understanding the two fundamental light types: ambient and directional.
AmbientLight - Global Base Lighting¶
Ambient light illuminates all objects uniformly from all directions, providing a base level of brightness.
Why Use Scene Instead of DefaultScene?
Youâll notice we use Scene (not DefaultScene) in the code examples throughout this chapter. DefaultScene includes rich defaults like HemisphereLightStage, Grid, SceneCamera, VR controls, etc. in its bgChildren.
Using the base Scene class gives you a blank canvas with no automatic lighting, ensuring that only the lights you explicitly define affect the scene. This allows you to see the precise effect of each light type.
Note: Use DefaultScene when you want sensible defaults. Use Scene with custom bgChildren for full control over your scene setup.
from vuer import Vuer, VuerSession
from vuer.schemas import Scene, Box, Sphere
from vuer.schemas import AmbientLight
app = Vuer()
@app.spawn(start=True)
async def main(session: VuerSession):
session.set @ Scene(
# ... your scene objects ...
up=[0, 1, 0],
rawChildren=[
# Only ambient light - notice how flat it looks
AmbientLight(
intensity=20,
color="#4a5568",
key="ambient-light",
),
],
)
await session.forever()
Key parameters: color (default: "#ffffff"), intensity (default: 0.5)
Key characteristics:
No shadows or direction
Prevents completely black areas
Objects appear flat without depth
Very performance-efficient
DirectionalLight - Adding Depth with Shadows¶
Directional light simulates distant light sources like the sun, casting parallel rays across the entire scene:
DirectionalLight(
intensity=1.0,
color="#ffffff",
position=[0, 5, 5], # Light comes from this direction
castShadow=True,
**{
"shadow-mapSize": [2048, 2048],
"shadow-camera-near": 0.5,
"shadow-camera-far": 50,
},
key="directional-light",
),
Key parameters: color, intensity (default: 0.5), position, castShadow (enable shadows)
Key characteristics:
Creates parallel rays like sunlight
Position indicates direction (not actual location)
Can cast sharp, defined shadows
Excellent for primary scene illumination
Additional Light Types¶
PointLight - Omnidirectional Light¶
Point lights emit in all directions from a single point, like a light bulb:
PointLight(
intensity=20,
color="#ffaa00",
position=[0, 0, 5], # Actual position in space
radius=0.1, # Size of debug sphere
showSphere=True, # Show sphere at light position
castShadow=True,
**{
"shadow-mapSize": [2048, 2048],
"shadow-camera-near": 0.5,
"shadow-camera-far": 50,
},
key="point-light",
)
Key parameters: color, intensity (default: 20), position, showSphere (display sphere at light position), castShadow (enable shadows)
Use cases: Light bulbs, torches, candles, magical orbs
SpotLight - Focused Beam¶
Spotlight creates a cone of light, perfect for dramatic focused illumination. The optimized scene at the top uses two spotlights: a warm orange key light (main illumination) and a cool blue rim light (edge highlight) to create professional, cinematic lighting with warm/cool color contrast:
SpotLight(
intensity=80,
color="#ff9f5a",
position=[0, 0, 5], # Light position
angle=0.5, # Cone angle in radians (Math.PI/3 â 1.047)
penumbra=0.8, # Edge softness (0-1), 0=sharp, 1=soft
distance=0, # Range (0 = infinite)
decay=2, # Light falloff rate
castShadow=True,
**{
"shadow-mapSize": [2048, 2048],
"shadow-camera-near": 0.5,
"shadow-camera-far": 50,
},
key="spot-light",
)
Key parameters: color, intensity, position, angle (cone angle in radians, default: Ï/3), penumbra (edge softness 0-1, default: 0), distance (range, 0=infinite), decay (falloff rate, default: 2), castShadow
Use cases: Flashlights, stage lighting, dramatic effects
HemisphereLight - Natural Outdoor Lighting¶
Hemisphere light simulates natural outdoor lighting with different sky and ground colors:
HemisphereLight(
skyColor="#87ceeb", # Sky (top) color
groundColor="#8b4513", # Ground (bottom) color
intensity=1.0,
key="hemisphere-light",
)
Key parameters: skyColor (top hemisphere color), groundColor (bottom hemisphere color), intensity (default: 1.0), helper
Note: Cannot cast shadows.
Use cases: Outdoor scenes, natural ambient light
RectAreaLight - Soft Area Lighting¶
Rectangular area lights emit from a surface, creating soft, realistic lighting. In our optimized scene, we use a RectAreaLight as the fill light with soft purple color (#e8d5ff) to reduce harsh shadows without eliminating them entirely:
RectAreaLight(
color="#e8d5ff",
intensity=8,
width=4, # Rectangle width
height=4, # Rectangle height
position=[0, 0, 5],
lookAt=[0, 0, 0], # Direction the light faces
key="rect-area-light",
),
Key parameters: color, intensity (default: 1.0), width, height, position, lookAt (direction to face), helper
Important: Only works with standard and physical materials. Cannot cast shadows.
Use cases: Softboxes, windows, studio lighting
Adding Shadows to Your Scene¶
Lighting and shadows always work together. In the scene at the beginning of this chapter, you may have noticed the soft, realistic shadows that add depth and dimension. To achieve that effect, we need to configure shadow properties alongside our lights.
Shadow Basics¶
For shadows to appear in your scene, you need three components:
Light source with
castShadow=True- The light must be configured to cast shadowsObjects with
castShadow=True- Objects that should create shadowsSurfaces with
receiveShadow=True- Surfaces (like floors) that display shadows
Key points:
Only
DirectionalLight,SpotLight, andPointLightcan cast shadowsAmbientLight,HemisphereLight, andRectAreaLightcannot cast shadowsObjects must use
lambert,phong,standard, orphysicalmaterials for shadows to workThe
basicmaterial type ignores all lighting and shadows
Shadow Camera Range Limitation¶
Even with castShadow=True configured, shadows have a limited range determined by the shadow camera. If your scene is large or objects are far from the light source, you may notice missing or clipped shadows.
Each light with shadows uses an internal âshadow cameraâ to render the shadow map. Objects outside this cameraâs view wonât cast shadows. This is why you might see:
Shadows suddenly cutting off at a certain distance
Missing shadows for objects far from the light
Incomplete shadows on large floor planes
When do you need shadow configuration?
Large scenes (objects spread over 10+ units)
Distant objects that need to cast shadows
SpotLight or DirectionalLight covering a wide area
When you notice shadows are clipped or missing
For small scenes with objects close together (within ~5-10 units), the default shadow camera usually works fine. For larger scenes, youâll need to configure the shadow camera range as shown below.
Advanced Shadow Configuration¶
For finer control over shadow quality and appearance, you can configure shadow properties using flattened attribute names:
DirectionalLight(
intensity=1.0,
position=[5, 5, 5],
castShadow=True,
**{
"shadow-mapSize": [2048, 2048], # Shadow resolution
"shadow-bias": -0.0001, # Prevents shadow artifacts
"shadow-camera-near": 0.5,
"shadow-camera-far": 500,
"shadow-camera-left": -10,
"shadow-camera-right": 10,
"shadow-camera-top": 10,
"shadow-camera-bottom": -10,
},
key="sun",
)
Note: Shadow properties use flattened attribute names with hyphens (e.g., shadow-mapSize, shadow-camera-far). Use the **{} unpacking syntax to pass these attributes.
Shadow quality settings:
mapSize=[512, 512]- Low quality, better performancemapSize=[1024, 1024]- Medium quality (default)mapSize=[2048, 2048]- High quality (recommended for final renders)mapSize=[4096, 4096]- Ultra quality, significant performance cost
Common shadow parameters:
bias- Prevents âshadow acneâ artifacts, typically-0.0001to-0.001radius- Softens shadow edges (only works with certain shadow types)camera.near/far- Controls shadow rendering rangecamera.fov(SpotLight) - Field of view for shadow cameracamera.left/right/top/bottom(DirectionalLight) - Defines shadow coverage area
Complete Example: Professional Lighting with Shadows¶
Letâs put everything together. The scene shown at the beginning of this chapter uses a four-light setup with shadow configuration to create professional, cinematic lighting. Hereâs the complete code:
Source Code
from vuer import Vuer, VuerSession
from vuer.schemas import Scene, Cylinder, Sphere, Octahedron, Torus, Box, Plane
from vuer.schemas import AmbientLight, SpotLight, RectAreaLight
app = Vuer()
@app.spawn(start=True)
async def main(session: VuerSession):
session.set @ Scene(
# Scene objects with castShadow enabled
Cylinder(
args=[0.8, 0.8, 0.5, 32],
position=[-3.5, 0.25, -1],
materialType="standard",
material=dict(
color="#4a3428",
roughness=0.96,
metalness=0
),
castShadow=True,
key="matte-cylinder",
),
Sphere(
args=[0.7, 32, 32],
position=[-3.5, 1.1, -1],
materialType="standard",
material=dict(
color="#6b4e3d",
roughness=1,
metalness=0,
), castShadow=True,
key="matte-sphere",
),
Octahedron(
args=[0.9, 0],
position=[-1.8, 1.5, 0.3],
rotation=[0, 0, 0.393],
materialType="physical",
material=dict(
color="#ffffff",
transmission=1,
thickness=0.8,
roughness=0,
ior=1.5,
),
castShadow=True,
key="glass-octahedron",
),
Torus(
args=[0.5, 0.15, 32, 64],
position=[0, 0.4, 0.8],
rotation=[1.571, 0, 0],
materialType="physical",
material=dict(
color="#d5e8ff",
transmission=0.93,
thickness=0.5,
roughness=0.08,
ior=1.45,
),
castShadow=True,
key="glass-torus",
),
Box(
args=[1.2, 1.2, 1.2],
position=[0.4, 0.5, -2],
materialType="standard",
material=dict(
color="#a17c50",
roughness=0.32,
metalness=0.75,
),
castShadow=True,
key="glossy-box",
),
Sphere(
args=[0.65, 32, 32],
position=[1.8, 0.7, 0],
materialType="standard",
material=dict(
color="#b8925f",
roughness=0.11,
metalness=0.75,
),
castShadow=True,
key="glossy-sphere",
),
# Floor and backdrop with receiveShadow
Plane(
args=[20, 20],
position=[0, 0, 0],
rotation=[-1.57, 0, 0],
materialType="standard",
material=dict(
map="https://raw.githubusercontent.com/vuer-ai/vuer/main/docs/_static/03_floor.jpg",
roughness=0.9,
),
receiveShadow=True,
key="floor",
),
Plane(
args=[20, 20],
position=[0, 0, -3],
materialType="standard",
material=dict(
map="https://raw.githubusercontent.com/vuer-ai/vuer/main/docs/_static/03_backdrop.jpg",
roughness=0.95,
),
receiveShadow=True,
key="backdrop",
),
up=[0, 1, 0],
rawChildren=[
# Four-light setup with shadows
AmbientLight(
intensity=0.15,
color="#4a5568",
key="ambient",
),
SpotLight(
position=[-5, 3, 5],
intensity=80,
angle=0.5,
penumbra=0.8,
color="#ff9f5a",
distance=0,
decay=2,
castShadow=True,
**{
"shadow-mapSize": [2048, 2048],
"shadow-camera-near": 0.5,
"shadow-camera-far": 50,
},
key="key-light",
),
SpotLight(
position=[4, 5, -6],
intensity=50,
angle=0.6,
penumbra=0.95,
color="#5aa0ff",
castShadow=True,
**{
"shadow-mapSize": [2048, 2048],
"shadow-camera-near": 0.5,
"shadow-camera-far": 50,
},
key="rim-light",
),
RectAreaLight(
position=[6, 2, 4],
intensity=8,
width=4,
height=4,
color="#e8d5ff",
key="fill-light",
)
],
)
await session.forever()
This example demonstrates the concepts covered in this chapter: multiple light types working together, shadow configuration for realistic depth, and careful balance of light intensities and colors to create professional, cinematic results.
Whatâs Next?¶
Now that you understand lighting, you can:
Continue with rendering:
Render Modes - Learn about different rendering modes
Post-processing Effects - Add bloom and other effects
Path Tracing - Create photorealistic renders
Explore interactive features:
Animation - Animate objects and cameras
Events and Interaction - Handle user clicks and input
VR/AR - Build immersive experiences
Quick lighting tips to remember:
Start with
AmbientLight(0.3) +DirectionalLight(1.0)Use
lambertorstandardmaterials to see lighting effectsAdd
castShadow=Trueand a floor withreceiveShadow=Truefor depthUse 3-5 lights maximum for good performance