Class: Ra::Camera

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ra/camera.rb

Overview

A camera produces rays used to generate pixels. By convention, the camera is positioned at the point <x=0,y=0,z=0>. The rays target an imaginary screen that exists at z=-1. The x,y values visible on the screen depend on the FOV and the width / height of the desired image.

A FOV represents the angel of the world visible to the camera. A default FOV is 90 degrees. This results in 2.0 by 2.0 of the world visible at z=-1.

A bigger FOV increases what in the world is visible to the camera. When FOV is 120 degrees then ~3.5 by ~3.5 world view visible through z=-1.

A smaller FOV decreases what in the world is visible to the camera. When FOV is 60 degrees then ~1.2 by ~1.2 world view is visible through z=-1.

The visible world view is then split into pixels bsaed on the l / w of the desired screen. The pixel size is calculated using these l / w dimensions. The pixels are defined to be evenly spaced within the visible world.

An example of a default 90 degree FOV and w=5 / h=4 results in pixels that are of size 0.4 (the greater of 2.0 / w=5 and 2.0 / h=4). With these dimensions rays are cast to the center of pixels evenly distrubted across the screen.

Constant Summary collapse

DEFAULT_W =
1280
DEFAULT_H =
1024
DEFAULT_FOV =
Math::PI / 3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(transform: Transform::IDENTITY, h: DEFAULT_H, w: DEFAULT_W, fov: DEFAULT_FOV) ⇒ Camera

Returns a new instance of Camera.

Parameters:

  • transform (Ra::Transform) (defaults to: Transform::IDENTITY)
  • h (Integer) (defaults to: DEFAULT_H)
  • w (Integer) (defaults to: DEFAULT_W)
  • fov (Numeric) (defaults to: DEFAULT_FOV)


53
54
55
56
57
58
# File 'lib/ra/camera.rb', line 53

def initialize(transform: Transform::IDENTITY, h: DEFAULT_H, w: DEFAULT_W, fov: DEFAULT_FOV)
  @transform = transform
  @h = h
  @w = w
  @fov = fov
end

Instance Attribute Details

#fovNumeric

Returns:

  • (Numeric)


39
40
41
# File 'lib/ra/camera.rb', line 39

def fov
  @fov
end

#hInteger

Returns:

  • (Integer)


31
32
33
# File 'lib/ra/camera.rb', line 31

def h
  @h
end

#transformRa::Transform

Returns:



43
44
45
# File 'lib/ra/camera.rb', line 43

def transform
  @transform
end

#wInteger

Returns:

  • (Integer)


35
36
37
# File 'lib/ra/camera.rb', line 35

def w
  @w
end

Instance Method Details

#each {|y, x, ray| ... } ⇒ Object

Yields:

  • (y, x, ray)

    y, x, ray

Yield Parameters:

  • y (Integer)
  • x (Integer)
  • ray (Ra::Ray)


64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ra/camera.rb', line 64

def each
  @h.times do |y|
    @w.times do |x|
      ray = ray(
        y:,
        x:,
      )
      yield(y, x, ray)
    end
  end
end

#half_hFloat

Returns:

  • (Float)


104
105
106
# File 'lib/ra/camera.rb', line 104

def half_h
  @half_h ||= @h < @w ? (half_view * @h / @w) : half_view
end

#half_viewFloat

Returns:

  • (Float)


94
95
96
# File 'lib/ra/camera.rb', line 94

def half_view
  @half_view ||= Math.tan(@fov / 2)
end

#half_wFloat

Returns:

  • (Float)


99
100
101
# File 'lib/ra/camera.rb', line 99

def half_w
  @half_w ||= @w < @h ? (half_view * @w / @h) : half_view
end

#p_sizeFloat

Returns:

  • (Float)


89
90
91
# File 'lib/ra/camera.rb', line 89

def p_size
  @p_size ||= half_w * 2 / w
end

#ray(x:, y:) ⇒ Ra::Ray

Parameters:

  • x (Numeric)
  • y (Numeric)

Returns:



79
80
81
82
83
84
85
86
# File 'lib/ra/camera.rb', line 79

def ray(x:, y:)
  pixel = transform.inverse * Vector[world_x(x:), world_y(y:), -1, Tuple::POINT]
  origin = transform.inverse * Vector[0, 0, 0, Tuple::POINT]

  direction = (pixel - origin).normalize

  Ray.new(origin:, direction:)
end