diff --git a/.gitignore b/.gitignore index ba39cc5..8741257 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +.CondaPkg Manifest.toml diff --git a/CondaPkg.toml b/CondaPkg.toml new file mode 100644 index 0000000..5143d94 --- /dev/null +++ b/CondaPkg.toml @@ -0,0 +1,4 @@ +channels = ["conda-forge"] + +[pip.deps] +opencv-python = "" diff --git a/SimpleRayTracer.jl b/SimpleRayTracer.jl index c32d879..ef168e1 100644 --- a/SimpleRayTracer.jl +++ b/SimpleRayTracer.jl @@ -1,6 +1,8 @@ module SimpleRayTracer using LinearAlgebra +using StaticArrays + using Images using GeometryBasics using Rotations @@ -14,20 +16,47 @@ abstract type AbstractObject end struct OrthogonalCamera{T<:AbstractFloat} <: AbstractCamera origin::Vec3{T} - rotation::RotXYZ{T} size::Tuple{T, T} + rotation::RotXYZ{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} + R = camera.rotation 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] + Nx, Ny = resolution + screen_pixel_position = [Vec3(x, y, 0.0) + camera.origin for y = LinRange(Y/2, -Y/2, Ny), x = LinRange(-X/2, X/2, Nx)] + [Ray(p, Vec3(0.0, 0.0, 1.0)) for p in screen_pixel_position] end +struct PinHoleCamera{T<:AbstractFloat} <: AbstractCamera + origin::Vec3{T} + distance::T + base::SMatrix{3, 3, T} + size::Tuple{T, T} +end + +function PinHoleCamera(origin, lookAt, up, distance, size) + w = origin - lookAt |> normalize + u = cross(up, w) |> normalize + v = cross(w, u) + B = [u v w] + PinHoleCamera(origin, distance, B, size) +end + +function get_rays(camera::PinHoleCamera, resolution::Tuple{I, I}) where {I<:Integer} + origin = camera.origin + d = camera.distance + X, Y = camera.size + B = camera.base + Nx, Ny = resolution + [Ray(origin, normalize(B*Vec3(x, y, -d))) for y = LinRange(Y/2, -Y/2, Ny), x = LinRange(-X/2, X/2, Nx)] +end + + + struct Ray{T<:AbstractFloat} origin::Vec3{T} direction::Vec3{T} @@ -85,4 +114,9 @@ function trace_ray(world::World, ray::Ray)::HitInfo return HitInfo(hit, color) end +function render(world, camera, resolution) + rays = get_rays(camera, resolution) + [trace_ray(world, ray).color for ray in rays]; +end + end diff --git a/rt.jl b/rt.jl index 864a443..e4c506d 100644 --- a/rt.jl +++ b/rt.jl @@ -2,7 +2,8 @@ using BenchmarkTools using LinearAlgebra using Rotations -# using Images +using Images +using GeometryBasics using Colors using GLMakie @@ -10,19 +11,30 @@ 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))) +push!(world, SimpleRayTracer.Sphere(Vec3(-4.0, 0.0, 0.0), 2.0, RGB(1, 0, 0))) +push!(world, SimpleRayTracer.Sphere(Vec3( 4.0, 0.0, 0.0), 2.0, RGB(0, 1, 0))) +push!(world, SimpleRayTracer.Sphere(Vec3( 0.0, 0.0, 3.0), 2.0, RGB(0, 0, 1))) camera = SimpleRayTracer.OrthogonalCamera( Vec3(0.0, 0.0, -5.0), + (20.0, 10.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)]; +camera = SimpleRayTracer.PinHoleCamera( + Vec3(0.0, 1.0, -8.0), + Vec3(0.0, 0.0, 0.0), + Vec3(0.0, 1.0, 0.0), + 1.0, + (4.0, 2.0), +) +resolution = (512, 256); +img = SimpleRayTracer.render(world, camera, resolution); +# img |> size fig = Figure(size=resolution) -ax = Axis(fig[1,1], aspect=1) -image!(ax, img) +ax = GLMakie.Axis(fig[1,1], aspect=2) +image!(ax, img |> rotr90) + + +Images.save("test.png", img)