/
camera.jl
168 lines (131 loc) · 5.18 KB
/
camera.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
export Camera, get_primary_rays
# ------ #
# Camera #
# ------ #
"""
FixedCameraParams
The Parameters of the [`Camera`](@ref) which should not be updated in inverse rendering
are wrapped into this object.
### Fields:
* `vup` - Stores the World UP Vector (In most cases this is the Y-Axis Vec3(0.0, 1.0, 0.0))
* `width` - Width of the image to be rendered
* `height` - Height of the image to be rendered
"""
struct FixedCameraParams{T} <: FixedParams
vup::Vec3{T}
width::Int
height::Int
end
Base.show(io::IO, fcp::FixedCameraParams) =
print(io, " Fixed Parameters:\n World UP - ", fcp.vup,
"\n Screen Dimensions - ", fcp.height, " × ", fcp.width)
Base.zero(fcp::FixedCameraParams) = FixedCameraParams(zero(fcp.vup), zero(fcp.width),
zero(fcp.height))
"""
Camera
The Perspective View Camera Model
### Fields:
* `lookfrom` - Position of the Camera in 3D World Space
* `lookat` - Point in the 3D World Space where the Camera is Pointing
* `vfov` - Field of View of the Camera
* `focus` - The focal length of the Camera
* `fixedparams` - An instance of [`FixedCameraParams`](@ref)
### Available Constructors:
* `Camera(;lookfrom = Vec3(0.0f0), lookat = Vec3(0.0f0),
vup = Vec3(0.0f0, 1.0f0, 0.0f0), vfov = 90.0f0,
focus = 1.0f0, width = 128, height = 128)`
* `Camera(lookfrom::Vec3{T}, lookat::Vec3{T}, vup::Vec3{T}, vfov::R,
focus::R, width::Int, height::Int) where {T<:AbstractArray, R<:Real}`
"""
struct Camera{T}
lookfrom::Vec3{T}
lookat::Vec3{T}
vfov::T
focus::T
fixedparams::FixedCameraParams{T}
end
Base.show(io::IO, cam::Camera) =
print(io, "CAMERA Configuration:\n Lookfrom - ", cam.lookfrom,
"\n Lookat - ", cam.lookat, "\n Field of View - ", cam.vfov[],
"\n Focus - ", cam.focus[], "\n", cam.fixedparams)
@diffops Camera
Camera(;lookfrom = Vec3(0.0f0), lookat = Vec3(0.0f0),
vup = Vec3(0.0f0, 1.0f0, 0.0f0), vfov = 90.0f0,
focus = 1.0f0, width = 128, height = 128) =
Camera(lookfrom, lookat, vup, vfov, focus, width, height)
function Camera(lookfrom::Vec3{T}, lookat::Vec3{T}, vup::Vec3{T}, vfov::R,
focus::R, width::Int, height::Int) where {T<:AbstractArray, R<:Real}
fixedparams = FixedCameraParams(vup, width, height)
return Camera(lookfrom, lookat, [vfov], [focus], fixedparams)
end
"""
get_primary_rays(c::Camera)
Takes the configuration of the camera and returns the origin and the direction
of the primary rays.
"""
function get_primary_rays(c::Camera)
width = c.fixedparams.width
height = c.fixedparams.height
vup = c.fixedparams.vup
vfov = c.vfov[]
focus = c.focus[]
aspect_ratio = width / height
half_height = tan(deg2rad(vfov / 2))
half_width = typeof(half_height)(aspect_ratio * half_height)
origin = c.lookfrom
w = normalize(c.lookfrom - c.lookat)
u = normalize(cross(vup, w))
v = normalize(cross(w, u))
# Lower Left Corner
llc = origin - half_width * focus * u - half_height * focus * v - w
hori = 2 * half_width * focus * u
vert = 2 * half_height * focus * v
s = repeat((collect(0:(width - 1)) .+ 0.5f0) ./ width, outer = height)
t = repeat((collect((height - 1):-1:0) .+ 0.5f0) ./ height, inner = width)
direction = normalize(llc + s * hori + t * vert - origin)
return (origin, direction)
end
"""
get_transformation_matrix(c::Camera)
Returns the `camera_to_world` transformation matrix. This is used for transforming
the coordinates of a Point in 3D Camera Space to 3D World Space using the
[`camera2world`](@ref) function.
"""
function get_transformation_matrix(c::Camera{T}) where {T}
forward = normalize(c.lookfrom - c.lookat)
right = normalize(cross(c.fixedparams.vup, forward))
up = normalize(cross(forward, right))
return [ right.x[] right.y[] right.z[] zero(eltype(T));
up.x[] up.y[] up.z[] zero(eltype(T));
forward.x[] forward.y[] forward.z[] zero(eltype(T));
c.lookfrom.x[] c.lookfrom.y[] c.lookfrom.z[] one(eltype(T))]
end
"""
compute_screen_coordinates(c::Camera, film_aperture::Tuple,
inch_to_mm::Real = 25.4)
Computes the coordinates of the 4 corners of the screen and returns
`top`, `right`, `bottom`, and `left`.
"""
function compute_screen_coordinates(c::Camera, film_aperture::Tuple,
inch_to_mm::Real = 25.4)
width = c.fixedparams.width
height = c.fixedparams.height
vfov = c.vfov[]
focus = c.focus[]
film_aspect_ratio = film_aperture[1] / film_aperture[2]
device_aspect_ratio = width / height
top = ((film_aperture[2] * inch_to_mm / 2) / focus)
right = ((film_aperture[1] * inch_to_mm / 2) / focus)
xscale = 1
yscale = 1
if film_aspect_ratio > device_aspect_ratio
xscale = device_aspect_ratio / film_aspect_ratio
else
yscale = film_aspect_ratio / device_aspect_ratio
end
right *= xscale
top *= yscale
bottom = -top
left = -right
return top, right, bottom, left
end