Proste generowanie sceny z wykorzystaniem sledzenia promieni

This commit is contained in:
zymon 2024-01-20 14:56:37 +01:00
parent 93ab7d8546
commit dc450860f3
3 changed files with 120 additions and 0 deletions

View file

@ -1,11 +1,15 @@
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
ImageView = "86fae568-95e7-573e-a6b2-d8a6b900c9ef"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc"
StackViews = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

88
SimpleRayTracer.jl Normal file
View file

@ -0,0 +1,88 @@
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

28
rt.jl Normal file
View file

@ -0,0 +1,28 @@
using BenchmarkTools
using LinearAlgebra
using Rotations
# using Images
using Colors
using GLMakie
##
include("SimpleRayTracer.jl")
world = SimpleRayTracer.World(RGB(.1,.5,.5))
push!(world, SimpleRayTracer.Sphere(Vec3(-2.5, 0.0, 0.0), 2.0, RGB(1, 0, 0)))
push!(world, SimpleRayTracer.Sphere(Vec3( 2.5, 0.0, 0.0), 2.0, RGB(0, 1, 0)))
push!(world, SimpleRayTracer.Sphere(Vec3( 0.0, 0.0, 2.5), 2.0, RGB(0, 0, 1)))
camera = SimpleRayTracer.OrthogonalCamera(
Vec3(0.0, 0.0, -5.0),
RotXYZ(0.0, 0.0, 0.0),
(5.0, 5.0)
)
resolution = (256, 256)
img = [SimpleRayTracer.trace_ray(world, ray).color for ray in SimpleRayTracer.get_rays(camera, resolution)];
fig = Figure(size=resolution)
ax = Axis(fig[1,1], aspect=1)
image!(ax, img)