Camera
Camera
class is used to configure the camera settings
for the rendering.
Positioning
We use a right-handed spherical coordinate system for camera positioning.
from fdray import *
Scene(
Camera(longitude=30, latitude=40),
LightSource(0, ColorName.WHITE), # at camera location
Cylinder(0, (1, 0, 0), 0.1, Color("red")),
Cylinder(0, (0, 1, 0), 0.1, Color("green")),
Cylinder(0, (0, 0, 1), 0.1, Color("blue")),
).render(width=300, height=300)
In the above figure, the camera is positioned at:
- Longitude: 30 degrees
- Latitude: 40 degrees
The camera position is determined through a two-step transformation:
- First, rotate 30 degrees counterclockwise from the x-axis toward the y-axis in the x-y plane
- Then, elevate 40 degrees from that position toward the z-axis
This coordinate system allows for intuitive camera positioning:
- Longitude controls the horizontal rotation around the scene
- Latitude controls the vertical angle from the ground plane
Implementation
The camera implementation is based on the following Qiita article:
- Title: Efficient Camera Settings in POV-Ray
- Author: @Hyrodium (Yuto Horikawa)
- URL: https://qiita.com/Hyrodium/items/af91b1ddb8ea2c4359c2
- Date: 2017-12-07
This implementation adopts the spherical coordinate system and uses the calculation methods for direction, right, and up vectors as proposed in the article. The sky parameter is also included as it's essential for proper orientation.
View scale
The view_scale
parameter controls how much of the scene is visible
in the rendered image. It functions similarly to adjusting a camera's
field of view.
view_scale = 1 |
view_scale = 2 |
view_scale = 3 |
---|---|---|
![]() |
![]() |
![]() |
def scene_view_scale(view_scale: float):
return Scene(
Camera(0, 0, view_scale=view_scale),
LightSource(0, Color("white")),
Cylinder("-y", "y", 0.2, Color("green")),
Cylinder("-2*y", "2*y", 0.15, Color("green")),
Cylinder("-3*y", "3*y", 0.1, Color("green")),
Cylinder("-z", "z", 0.2, Color("blue")),
Cylinder("-2*z", "2*z", 0.15, Color("blue")),
Cylinder("-3*z", "3*z", 0.1, Color("blue")),
Torus(1, 0.1, Color("purple", 0.5)).rotate("90*z"),
Torus(2, 0.1, Color("gold", 0.5)).rotate("90*z"),
Torus(3, 0.1, Color("cyan", 0.5)).rotate("90*z"),
Background(Color("gray")),
).render(width=150, height=150)
Basic Operation
- A larger view scale shows more of the scene by "zooming out"
- A smaller view scale shows less of the scene by "zooming in"
Technical Implementation
- The coordinate range rendered extends from
-view_scale
to+view_scale
- Directly affects the apparent size of objects in the scene
- Controls the viewing frustum without changing camera position
Parameter Relationships
- Independent of camera position and orientation (longitude, latitude)
- Works in conjunction with the camera's distance parameter
Distance
The distance
parameter controls the camera's perspective effect.
This parameter significantly affects how the 3D scene is rendered,
particularly the perspective distortion.
distance = 3 |
distance = 10 |
distance = 30 |
---|---|---|
![]() |
![]() |
![]() |
def scene_distance(distance: float):
return Scene(
Camera(15, 10, view_scale=2, distance=distance),
LightSource((1, 20, 40), Color("white")),
Box(-1, 1, Color("green", 0.8)),
Background(Color("gray", 0.2)),
).render(width=200, height=200)
Visual Effects
When distance is small
- Creates a fisheye lens-like effect
- Produces strong perspective distortion
- Objects appear more curved at the edges
- Similar to viewing through a wide-angle lens
When distance is large
- Approaches orthogonal projection
- Reduces perspective distortion
- Creates a more natural depth perception
- Similar to viewing through a telephoto lens
Technical Details
The distance
parameter:
- Affects the perspective matrix calculation
- Does not change the actual size of objects, only their apparent perspective
- Represents the distance between the camera position (
camera_pos
) and the object's center (center
) - Smaller distances bring the camera closer to the object, creating stronger perspective effects
- Larger distances move the camera away from the object, resulting in a more orthogonal-like view
Important Notes
- The
distance
parameter only affects perspective, not object size - Smaller distances create more dramatic perspective effects
- Larger distances create more natural, less distorted views
- The effect is similar to changing the focal length of a camera lens
Orbital Location
Calculate a position in orbit around the camera's location
Imagine tilting your head up (angle
) and then rotating
counter-clockwise (rotation
):
- First, move
forward
along viewing direction (0: atcamera.location
, 1: atcamera.look_at
). Negative values move behind the camera. - Then, tilt up from viewing direction by
angle
degrees - Finally, rotate counter-clockwise from up by
rotation
degrees (0: up, 90: left, 180: down, 270: right)
from math import asin, degrees, sqrt
def render(camera: Camera, *args):
return Scene(
camera,
LightSource(0, "white"),
Cylinder(0, "2*x", 0.02, Color("red")),
Cylinder(0, "2*y", 0.02, Color("green")),
Cylinder(0, "2*z", 0.02, Color("blue")),
*args,
).render(width=300, height=300)
distance = 4
camera = Camera(0, 0, view_scale=2.5, look_at=(0, 0, 0), distance=distance)
norm = sqrt(distance**2 + 2**2)
angle = degrees(asin(2 / norm))
p1 = camera.orbital_location(norm / distance, angle, -90)
s1 = Sphere(p1, 0.2, Color("purple", 0.5))
p2 = camera.orbital_location(0.5, angle, -90)
s2 = Sphere(p2, 0.05, Color("orange", 0.5))
render(camera, s1, s2)
Rendered image from x axis | Top view (y-z plane) |
---|---|
![]() |