From dc450860f356d002448131b7e3a919bce14b4993 Mon Sep 17 00:00:00 2001 From: zymon Date: Sat, 20 Jan 2024 14:56:37 +0100 Subject: [PATCH] Proste generowanie sceny z wykorzystaniem sledzenia promieni --- Project.toml | 4 +++ SimpleRayTracer.jl | 88 ++++++++++++++++++++++++++++++++++++++++++++++ rt.jl | 28 +++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 SimpleRayTracer.jl create mode 100644 rt.jl diff --git a/Project.toml b/Project.toml index 57447ab..2571e9f 100644 --- a/Project.toml +++ b/Project.toml @@ -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" diff --git a/SimpleRayTracer.jl b/SimpleRayTracer.jl new file mode 100644 index 0000000..c32d879 --- /dev/null +++ b/SimpleRayTracer.jl @@ -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 diff --git a/rt.jl b/rt.jl new file mode 100644 index 0000000..864a443 --- /dev/null +++ b/rt.jl @@ -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)