Skip to content

Raytracing a polygon mesh

julia
using Krang
import GLMakie as GLMk
using GeometryBasics
using FileIO

metric = Krang.Kerr(0.99) # Kerr metric with a spin of 0.99
θo = 90/180*π # Inclination angle of the observer
ρmax = 12.0 # Horizontal and Vertical extent of the screen
sze = 100 # Resolution of the screen is sze x sze

camera = Krang.SlowLightIntensityCamera(metric, θo, -ρmax, ρmax, -ρmax, ρmax, sze)
SlowLightIntensityCamera{Float64, Matrix{Krang.SlowLightIntensityPixel{Float64}}}(Kerr{Float64}(1.0, 0.99), Krang.SlowLightIntensityScreen{Float64, Matrix{Krang.SlowLightIntensityPixel{Float64}}}((-12.0, 12.0), (-12.0, 12.0), Krang.SlowLightIntensityPixel{Float64}[Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-12.0, -12.0), (-17.811393086775468 - 3.6622313808008166e-17im, 0.3222351305493678 + 1.2554506945771609e-15im, 1.5419781346644301 - 1.2759301128716357e-15im, 15.947179821561672 + 5.7101732102483e-17im), 0.10027124075812203, 0.20054248151624407, 3.1948265198800945, 7.300113474580925, -2.1933076951002244, -13.17634564256269, -0.2458426263266534, -0.14259682643912724, (0.0, 0.18519854383797518), (5.102694996447269e-18, 0.2621141790545372), (1.4968675014460734e-15, 0.04636852782576966), 1.5707963267948966, 144.0, 12.0) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-12.0, -11.757575757575758), (-17.638476027306 - 2.5119566969130612e-17im, 0.31478822909250326 + 8.454330522229745e-16im, 1.5466851612338912 - 8.596354078342111e-16im, 15.777002636979606 + 3.932192258036724e-17im), 0.101372414125879, 0.202744828251758, 3.16735588607714, 7.200050727203687, -2.1843464618842914, -13.041084896738482, -0.24555855578357275, -0.1430989095121752, (0.0, 0.18708517002259337), (5.207905202559688e-18, 0.26212388077819737), (1.497074218783015e-15, 0.04588827118022064), 1.5707963267948966, 138.24058769513314, 12.0) … Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-12.0, 11.757575757575758), (-17.638476027306 - 2.5119566969130612e-17im, 0.31478822909250326 + 8.454330522229745e-16im, 1.5466851612338912 - 8.596354078342111e-16im, 15.777002636979606 + 3.932192258036724e-17im), 0.101372414125879, 0.202744828251758, 3.16735588607714, 7.200050727203687, -2.1843464618842914, -13.041084896738482, -0.24555855578357275, -0.1430989095121752, (0.0, 0.18708517002259337), (5.207905202559688e-18, 0.26212388077819737), (1.497074218783015e-15, 0.04588827118022064), 1.5707963267948966, 138.24058769513314, 12.0) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-12.0, 12.0), (-17.811393086775468 - 3.6622313808008166e-17im, 0.3222351305493678 + 1.2554506945771609e-15im, 1.5419781346644301 - 1.2759301128716357e-15im, 15.947179821561672 + 5.7101732102483e-17im), 0.10027124075812203, 0.20054248151624407, 3.1948265198800945, 7.300113474580925, -2.1933076951002244, -13.17634564256269, -0.2458426263266534, -0.14259682643912724, (0.0, 0.18519854383797518), (5.102694996447269e-18, 0.2621141790545372), (1.4968675014460734e-15, 0.04636852782576966), 1.5707963267948966, 144.0, 12.0); Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-11.757575757575758, -12.0), (-17.640437321470174 - 2.4530065262927946e-17im, 0.3305713202666105 + 8.45498564627043e-16im, 1.534155704198172 - 8.593965268063113e-16im, 15.775710297005391 + 3.842802744219619e-17im), 0.1013823110504783, 0.2027646221009566, 3.2477381116067705, 7.025903203700722, -2.182974372020287, -13.040840967779726, -0.2535489935759499, -0.14584785744144382, (0.0, 0.18707522107719277), (5.102694996447354e-18, 0.26752176320486787), (1.4669344203343482e-15, 0.047793721890844104), 1.5707963267948966, 144.0, 11.757575757575758) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-11.757575757575758, -11.757575757575758), (-17.465724293757646 - 2.5252190636852947e-17im, 0.32306161221907637 + 8.542281192425115e-16im, 1.5388774673628065 - 8.68697217553463e-16im, 15.603785214175762 + 3.9721288947804355e-17im), 0.10251985582662307, 0.20503971165324614, 3.2192884868709597, 6.92595757190612, -2.173824128209073, -12.904166251891354, -0.2532463985867103, -0.14637960398006838, (0.0, 0.1890203905949582), (5.207905202559685e-18, 0.2675319714243842), (1.4665239682731889e-15, 0.047328338742640384), 1.5707963267948966, 138.24058769513314, 11.757575757575758) … Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-11.757575757575758, 11.757575757575758), (-17.465724293757646 - 2.5252190636852947e-17im, 0.32306161221907637 + 8.542281192425115e-16im, 1.5388774673628065 - 8.68697217553463e-16im, 15.603785214175762 + 3.9721288947804355e-17im), 0.10251985582662307, 0.20503971165324614, 3.2192884868709597, 6.92595757190612, -2.173824128209073, -12.904166251891354, -0.2532463985867103, -0.14637960398006838, (0.0, 0.1890203905949582), (5.207905202559685e-18, 0.2675319714243842), (1.4665239682731889e-15, 0.047328338742640384), 1.5707963267948966, 138.24058769513314, 11.757575757575758) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (-11.757575757575758, 12.0), (-17.640437321470174 - 2.4530065262927946e-17im, 0.3305713202666105 + 8.45498564627043e-16im, 1.534155704198172 - 8.593965268063113e-16im, 15.775710297005391 + 3.842802744219619e-17im), 0.1013823110504783, 0.2027646221009566, 3.2477381116067705, 7.025903203700722, -2.182974372020287, -13.040840967779726, -0.2535489935759499, -0.14584785744144382, (0.0, 0.18707522107719277), (5.102694996447354e-18, 0.26752176320486787), (1.4669344203343482e-15, 0.047793721890844104), 1.5707963267948966, 144.0, 11.757575757575758); … ; Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (11.757575757575758, -12.0), (-17.781479386402786 - 4.969222631444887e-17im, 0.26163540322435885 + 1.2663858277683034e-15im, 1.9482024385129888 - 1.3015057232471788e-15im, 15.57164154466544 + 8.48121217933244e-17im), 0.103156828843341, 0.206313657686682, -1.7925822533610245, 23.940178550610657, -2.206246964058812, -12.98400431167325, -0.12329863072332145, -0.090263065858183, (0.0, 0.18707522107719277), (5.102694996447354e-18, 0.26752176320486787), (1.4669344203343482e-15, 0.047793721890844104), 1.5707963267948966, 144.0, -11.757575757575758) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (11.757575757575758, -11.757575757575758), (-17.609506000215994 - 3.408011043629016e-17im, 0.25504723925106276 + 8.529391086302426e-16im, 1.959574258655218 - 8.774316195876013e-16im, 15.394884502309713 + 5.857262139364886e-17im), 0.10437921921156745, 0.2087584384231349, -1.7722671921105388, 23.738179537197063, -2.1976301247423478, -12.845399511775305, -0.12290682708752478, -0.09028812494436153, (0.0, 0.1890203905949582), (5.207905202559685e-18, 0.2675319714243842), (1.4665239682731889e-15, 0.047328338742640384), 1.5707963267948966, 138.24058769513314, -11.757575757575758) … Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (11.757575757575758, 11.757575757575758), (-17.609506000215994 - 3.408011043629016e-17im, 0.25504723925106276 + 8.529391086302426e-16im, 1.959574258655218 - 8.774316195876013e-16im, 15.394884502309713 + 5.857262139364886e-17im), 0.10437921921156745, 0.2087584384231349, -1.7722671921105388, 23.738179537197063, -2.1976301247423478, -12.845399511775305, -0.12290682708752478, -0.09028812494436153, (0.0, 0.1890203905949582), (5.207905202559685e-18, 0.2675319714243842), (1.4665239682731889e-15, 0.047328338742640384), 1.5707963267948966, 138.24058769513314, -11.757575757575758) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (11.757575757575758, 12.0), (-17.781479386402786 - 4.969222631444887e-17im, 0.26163540322435885 + 1.2663858277683034e-15im, 1.9482024385129888 - 1.3015057232471788e-15im, 15.57164154466544 + 8.48121217933244e-17im), 0.103156828843341, 0.206313657686682, -1.7925822533610245, 23.940178550610657, -2.206246964058812, -12.98400431167325, -0.12329863072332145, -0.090263065858183, (0.0, 0.18707522107719277), (5.102694996447354e-18, 0.26752176320486787), (1.4669344203343482e-15, 0.047793721890844104), 1.5707963267948966, 144.0, -11.757575757575758); Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (12.0, -12.0), (-17.952668704272526 - 3.2765377669138564e-17im, 0.25561836422800255 + 8.357723444881215e-16im, 1.9534780245174446 - 8.5861149839102065e-16im, 15.743572315527079 + 5.560453157203775e-17im), 0.10200223134145532, 0.20400446268291064, -1.7809590013311702, 24.074212683041594, -2.2160995622595325, -13.12017807786004, -0.12114996795799929, -0.08885191284558384, (0.0, 0.18519854383797518), (5.102694996447269e-18, 0.2621141790545372), (1.4968675014460734e-15, 0.04636852782576966), 1.5707963267948966, 144.0, -12.0) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (12.0, -11.757575757575758), (-17.7824416240653 - 5.053263097256706e-17im, 0.24910086974177226 + 1.2662896490723065e-15im, 1.9646605627738465 - 1.3020934455761203e-15im, 15.568680191549678 + 8.63364274763809e-17im), 0.1031843291537721, 0.2063686583075442, -1.7612081103544948, 23.875316012316453, -2.207649485347096, -12.98305147895367, -0.12077580730248855, -0.08887616558388427, (0.0, 0.18708517002259337), (5.207905202559688e-18, 0.26212388077819737), (1.497074218783015e-15, 0.04588827118022064), 1.5707963267948966, 138.24058769513314, -12.0) … Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (12.0, 11.757575757575758), (-17.7824416240653 - 5.053263097256706e-17im, 0.24910086974177226 + 1.2662896490723065e-15im, 1.9646605627738465 - 1.3020934455761203e-15im, 15.568680191549678 + 8.63364274763809e-17im), 0.1031843291537721, 0.2063686583075442, -1.7612081103544948, 23.875316012316453, -2.207649485347096, -12.98305147895367, -0.12077580730248855, -0.08887616558388427, (0.0, 0.18708517002259337), (5.207905202559688e-18, 0.26212388077819737), (1.497074218783015e-15, 0.04588827118022064), 1.5707963267948966, 138.24058769513314, -12.0) Krang.SlowLightIntensityPixel{Float64}(Kerr{Float64}(1.0, 0.99), (12.0, 12.0), (-17.952668704272526 - 3.2765377669138564e-17im, 0.25561836422800255 + 8.357723444881215e-16im, 1.9534780245174446 - 8.5861149839102065e-16im, 15.743572315527079 + 5.560453157203775e-17im), 0.10200223134145532, 0.20400446268291064, -1.7809590013311702, 24.074212683041594, -2.2160995622595325, -13.12017807786004, -0.12114996795799929, -0.08885191284558384, (0.0, 0.18519854383797518), (5.102694996447269e-18, 0.2621141790545372), (1.4968675014460734e-15, 0.04636852782576966), 1.5707963267948966, 144.0, -12.0)]), (Inf, 1.5707963267948966))

Import external mesh

julia
bunny_mesh = translate(
    rotate(
        scale(
            load(download("https://graphics.stanford.edu/~mdfisher/Data/Meshes/bunny.obj", "bunny.obj")), 100
        ),π/2, 1.0, 0.0, 0.0
    ), 2.0,7.0,-10.0
);

Ray trace the mesh embedded in the Kerr space time. The emission picked up by a ray will be the sum of all the intersections of the ray with the mesh The mesh is embedded in the space-time by assuming the world coordinates of the mesh is the same as the Boyer-Lindquist coordinates of the space time. The ray tracing is done by scanning over the image one line at a time

Let us now ray trace the image to see what the mesh looks like from the observer's perspective.

julia
intersections = raytrace(camera, bunny_mesh);

And plot the image with GLMakie,

julia
fig = GLMk.Figure()
ax = GLMk.Axis(fig[1,1], aspect=1)
GLMk.heatmap!(ax, intersections, colormap=:afmhot);

save("mesh_geometry_example.png", fig);

Below is a short plotting routine that generates a video showing the scene from three different perspectives, and live renders the image.

julia
fig = GLMk.Figure()
ax1 = GLMk.Axis3(fig[1,1], aspect=(1,1,1), title="Top view of scene", elevation = π/2, azimuth = π)
ax2 = GLMk.Axis3(fig[1,2], aspect=(1,1,1), title="Side view of scene", elevation = 0.0, azimuth =/2)
ax3 = GLMk.Axis3(fig[2,1], aspect=(1,1,1), title="Isometric view of scene")

ax = GLMk.Axis(fig[2,2], aspect=1, title="Heatmap of ray intersections with mesh")

for a in [ax1, ax2, ax3]
    GLMk.xlims!(a, (-10, 10))
    GLMk.ylims!(a, (-10, 10))
    GLMk.zlims!(a, (-10, 10))
    GLMk.hidedecorations!(a)
end

GLMk.hidedecorations!(ax)
sphere = GLMk.Sphere(GLMk.Point(0.0,0.0,0.0), horizon(metric)) # Sphere to represent black hole
lines_to_plot = Krang.generate_ray.(camera.screen.pixels, 100) # 100 is the number of steps to take along the ray

img = zeros(sze, sze)
recording = GLMk.record(fig, "mesh.mp4", 1:sze*sze, framerate=120) do i
    line = lines_to_plot[i]

    img[i] = intersections[i]

    GLMk.empty!(ax)
    GLMk.empty!(ax1)
    GLMk.empty!(ax2)
    GLMk.empty!(ax3)

    for a in [ax1, ax2, ax3]
        GLMk.mesh!(a, bunny_mesh, color=[parse(GLMk.Colorant, "rgba(0%, 50%, 70%,1.0)") for tri in bunny_mesh.position], colormap = :blues, transparency=true)
        GLMk.mesh!(a, sphere, color=:black)
    end

    GLMk.lines!(ax3, line, color=:red)
    GLMk.heatmap!(ax, img, colormap=:afmhot, colorrange=(0, 8))
end
"mesh.mp4"

This page was generated using Literate.jl.