Perspective + orthographic cameras
This commit is contained in:
130
camera.odin
130
camera.odin
@@ -6,27 +6,95 @@ import "core:math/linalg"
|
|||||||
Camera :: struct {
|
Camera :: struct {
|
||||||
position: [3]f32,
|
position: [3]f32,
|
||||||
forward, up, right: [3]f32,
|
forward, up, right: [3]f32,
|
||||||
|
|
||||||
fov_degrees: f32,
|
|
||||||
near, far: f32,
|
near, far: f32,
|
||||||
|
yaw, pitch, roll: f32,
|
||||||
|
|
||||||
|
type: Camera_Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
create_camera :: proc(renderer: ^Renderer, position: [3]f32, forward, up: [3]f32, fov_degrees, near, far: f32) -> Camera {
|
Camera_Type :: union {
|
||||||
|
Camera_Perspective,
|
||||||
|
Camera_Orthographic,
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera_Perspective :: struct {
|
||||||
|
fov_degrees: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera_Orthographic :: struct {
|
||||||
|
height: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private) create_camera_base :: proc(
|
||||||
|
renderer: ^Renderer,
|
||||||
|
position: [3]f32,
|
||||||
|
forward, up: [3]f32,
|
||||||
|
near, far: f32,
|
||||||
|
type: Camera_Type,
|
||||||
|
yaw: f32 = 0, pitch: f32 = 0, roll: f32 = 0
|
||||||
|
) -> Camera
|
||||||
|
{
|
||||||
c: Camera
|
c: Camera
|
||||||
c.position = position
|
c.position = position
|
||||||
c.forward = forward
|
c.forward = forward
|
||||||
c.up = up
|
c.up = up
|
||||||
c.fov_degrees = fov_degrees
|
|
||||||
c.near = near
|
c.near = near
|
||||||
c.far = far
|
c.far = far
|
||||||
|
c.type = type
|
||||||
|
c.yaw = yaw
|
||||||
|
c.pitch = pitch
|
||||||
|
c.roll = roll
|
||||||
|
|
||||||
assert(c.forward != {})
|
assert(c.forward != {})
|
||||||
assert(c.up != {})
|
assert(c.up != {})
|
||||||
|
assert(c.near > 0)
|
||||||
|
assert(c.far > 0)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
create_camera_perspective :: proc(
|
||||||
|
renderer: ^Renderer,
|
||||||
|
position: [3]f32,
|
||||||
|
forward, up: [3]f32,
|
||||||
|
near, far: f32,
|
||||||
|
fov_degrees: f32,
|
||||||
|
yaw: f32 = 0, pitch: f32 = 0, roll: f32 = 0
|
||||||
|
) -> Camera
|
||||||
|
{
|
||||||
assert(fov_degrees > 0)
|
assert(fov_degrees > 0)
|
||||||
assert(near > 0)
|
assert(near > 0)
|
||||||
assert(far > 0)
|
assert(far > 0)
|
||||||
|
|
||||||
return c
|
return create_camera_base(
|
||||||
|
renderer, position, forward, up,
|
||||||
|
near, far,
|
||||||
|
Camera_Perspective {
|
||||||
|
fov_degrees = fov_degrees,
|
||||||
|
},
|
||||||
|
yaw, pitch, roll
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
create_camera_orthographic :: proc(
|
||||||
|
renderer: ^Renderer,
|
||||||
|
position: [3]f32,
|
||||||
|
forward, up: [3]f32,
|
||||||
|
near, far: f32,
|
||||||
|
height: f32,
|
||||||
|
yaw: f32 = 0, pitch: f32 = 0, roll: f32 = 0
|
||||||
|
) -> Camera
|
||||||
|
{
|
||||||
|
assert(height > 0)
|
||||||
|
|
||||||
|
return create_camera_base(
|
||||||
|
renderer, position, forward, up,
|
||||||
|
near, far,
|
||||||
|
Camera_Orthographic {
|
||||||
|
height = height,
|
||||||
|
},
|
||||||
|
yaw, pitch, roll
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get_camera_view_matrix :: proc(camera: ^Camera) -> (linalg.Matrix4f32, bool) {
|
get_camera_view_matrix :: proc(camera: ^Camera) -> (linalg.Matrix4f32, bool) {
|
||||||
@@ -48,23 +116,50 @@ get_camera_projection_matrix :: proc(renderer: ^Renderer, camera: ^Camera) -> (l
|
|||||||
}
|
}
|
||||||
|
|
||||||
projection_matrix := linalg.MATRIX4F32_IDENTITY
|
projection_matrix := linalg.MATRIX4F32_IDENTITY
|
||||||
projection_matrix *= linalg.matrix4_perspective(
|
|
||||||
linalg.to_radians(f32(camera.fov_degrees)),
|
switch t in camera.type {
|
||||||
get_aspect_ratio(renderer),
|
case Camera_Perspective: {
|
||||||
camera.near,
|
projection_matrix *= linalg.matrix4_perspective(
|
||||||
camera.far,
|
linalg.to_radians(f32(t.fov_degrees)),
|
||||||
flip_z_axis = true,
|
get_aspect_ratio(renderer),
|
||||||
)
|
camera.near,
|
||||||
|
camera.far,
|
||||||
|
flip_z_axis = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case Camera_Orthographic: {
|
||||||
|
half_h := t.height / 2
|
||||||
|
half_w := half_h * get_aspect_ratio(renderer)
|
||||||
|
|
||||||
|
projection_matrix *= linalg.matrix_ortho3d(
|
||||||
|
-half_w, half_w,
|
||||||
|
-half_h, half_h,
|
||||||
|
camera.near,
|
||||||
|
camera.far,
|
||||||
|
flip_z_axis = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return projection_matrix, true
|
return projection_matrix, true
|
||||||
}
|
}
|
||||||
|
|
||||||
rotate_camera :: proc(camera: ^Camera, yaw, pitch, roll: f32) {
|
rotate_camera :: proc(camera: ^Camera, yaw, pitch, roll: f32) {
|
||||||
pitch := clamp(pitch, -89.0, 89.0)
|
new_yaw := camera.yaw + yaw
|
||||||
|
new_pitch := camera.pitch + pitch
|
||||||
|
new_roll := camera.roll + roll
|
||||||
|
|
||||||
pitch_rad := linalg.to_radians(pitch)
|
set_camera_rotation(camera, new_yaw, new_pitch, new_roll)
|
||||||
yaw_rad := linalg.to_radians(yaw)
|
}
|
||||||
roll_rad := linalg.to_radians(roll)
|
|
||||||
|
set_camera_rotation :: proc(camera: ^Camera, yaw, pitch, roll: f32) {
|
||||||
|
camera.yaw = yaw
|
||||||
|
camera.pitch = pitch
|
||||||
|
camera.roll = roll
|
||||||
|
|
||||||
|
pitch_rad := linalg.to_radians(camera.pitch)
|
||||||
|
yaw_rad := linalg.to_radians(camera.yaw)
|
||||||
|
roll_rad := linalg.to_radians(camera.roll)
|
||||||
|
|
||||||
camera.forward = [3]f32{
|
camera.forward = [3]f32{
|
||||||
math.cos(pitch_rad) * math.cos(yaw_rad),
|
math.cos(pitch_rad) * math.cos(yaw_rad),
|
||||||
@@ -73,9 +168,9 @@ rotate_camera :: proc(camera: ^Camera, yaw, pitch, roll: f32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WORLD_UP :: [3]f32{0, 1, 0}
|
WORLD_UP :: [3]f32{0, 1, 0}
|
||||||
|
|
||||||
camera.right = linalg.normalize(linalg.cross(camera.forward, WORLD_UP))
|
camera.right = linalg.normalize(linalg.cross(camera.forward, WORLD_UP))
|
||||||
camera.up = linalg.normalize(linalg.cross(camera.right, camera.forward))
|
camera.up = linalg.normalize(linalg.cross(camera.right, camera.forward))
|
||||||
// TODO: SS - Support 'roll'.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_active_camera :: proc(renderer: ^Renderer, camera: ^Camera) {
|
set_active_camera :: proc(renderer: ^Renderer, camera: ^Camera) {
|
||||||
@@ -83,5 +178,6 @@ set_active_camera :: proc(renderer: ^Renderer, camera: ^Camera) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_active_camera :: proc(renderer: ^Renderer) -> ^Camera {
|
get_active_camera :: proc(renderer: ^Renderer) -> ^Camera {
|
||||||
|
assert(renderer != nil)
|
||||||
return renderer.active_camera
|
return renderer.active_camera
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user