SBWO/SimpleRayTracer.jl

89 lines
2 KiB
Julia
Raw Normal View History

module SimpleRayTracer
using LinearAlgebra
using Images
using GeometryBasics
using Rotations
export OrthogonalCamera
export World, Ray
export Sphere
abstract type AbstractCamera end
abstract type AbstractObject end
struct OrthogonalCamera{T<:AbstractFloat} <: AbstractCamera
origin::Vec3{T}
rotation::RotXYZ{T}
size::Tuple{T, T}
# function OrthogonalCamera(o, θ, s)
# new(o, RotXYZ(0.0, 0.0, 0.0), s)
# end
end
function get_rays(camera::OrthogonalCamera, resolution::Tuple{I, I}) where {I<:Integer}
X, Y = camera.size
rx, ry = resolution
origins = [Vec3(x, y, 0.0) + camera.origin for x = LinRange(-X, X, rx), y = LinRange(-Y, Y, ry)]
[Ray(o, Vec3(0.0, 0.0, 1.0)) for o in origins]
end
struct Ray{T<:AbstractFloat}
origin::Vec3{T}
direction::Vec3{T}
# function Ray{T}(o, d) where {T<:AbstractFloat}
# new(o, d |> normalize)
# end
end
struct HitInfo
hit::Bool
color::RGB{N0f8}
end
struct World
objects::Vector
background::RGB{N0f8}
function World(color)
new([], color)
end
end
Base.push!(w::World, x::AbstractObject) = push!(w.objects, x)
struct Sphere{T<:AbstractFloat} <: AbstractObject
origin::Vec3{T}
radius::T
color::RGB{N0f8}
end
function check_hit(ray::Ray{T}, sphere::Sphere{T})::Tuple{Bool, T} where {T <: AbstractFloat}
p = ray.origin - sphere.origin
a = dot(ray.direction, ray.direction)
b = 2 * dot(p, ray.direction)
c = dot(p, p) - sphere.radius^2
Δ = b^2 - 4a*c
Δ < 0.0 && return false, -1.0
x, z = -b/(2a), Δ/(2a)
t = x - z
t = t < eps() ? x + z : t
return t < eps() ? (false, -1.0) : (true, t)
end
function trace_ray(world::World, ray::Ray)::HitInfo
mindist = Float64 |> typemax |> prevfloat
hit = false
color = world.background
for obj in world.objects
hit, dist = check_hit(ray, obj)
if hit && dist < mindist
mindist = dist
hit = true
color = obj.color
end
end
return HitInfo(hit, color)
end
end