Git Product home page Git Product logo

ray-tracer-challenge's Introduction

Ray Tracer Challenge

This project is a simple Zig implementation of the ray tracer described in The Ray Tracer Challenge.

You can find an interactive demo of this ray tracer online at sinclam.github.io/ray-tracer-challenge.

Status

  • Chapter 1 - Tuples, Points, and Vectors
  • Chapter 2 - Drawing on a Canvas
  • Chapter 3 - Matrices
  • Chapter 4 - Matrix Transformations
  • Chapter 5 - Ray-Sphere Intersections
  • Chapter 6 - Light and Shading
  • Chapter 7 - Making a Scene
  • Chapter 8 - Shadows
  • Chapter 9 - Planes
  • Chapter 10 - Patterns
  • Chapter 11 - Reflection and Refraction
  • Chapter 12 - Cubes
  • Chapter 13 - Cylinders
  • Chapter 14 - Groups
  • Chapter 15 - Triangles
  • Chapter 16 - Constructive Solid Geometry (CSG)
  • Chapter 17 - Next Steps
  • A1 - Rendering the Cover Image
  • Bonus Chapter - Rendering soft shadows
  • Bonus Chapter - Bounding boxes and hierarchies
  • Bonus Chapter - Texture mapping

Examples

Fresnel

Patterns

Reflection and Refraction

Cubes

Groups

Teapot

Teapot model from https://groups.csail.mit.edu/graphics/classes/6.837/F03/models/teapot.obj.

Dragons

Dragon model from http://raytracerchallenge.com/bonus/assets/dragon.zip.

Nefertiti

Nefertiti bust model from https://github.com/alecjacobson/common-3d-test-models/blob/master/data/nefertiti.obj.

Constructive Solid Geometry

Earth

Earth texture from https://planetpixelemporium.com/earth.html.

Skybox

Lancellotti Chapel texture from http://www.humus.name/index.php?page=Textures.

Building from source

To build for native:

zig build -Doptimize=ReleaseFast

To target the web (populating www/ with the all the site's files):

zig build --sysroot [emsdk]/upstream/emscripten -Dtarget=wasm32-emscripten -Dcpu=generic+bulk_memory+atomics+simd128 -Doptimize=ReleaseFast
    && sed -i'' -e 's/_emscripten_return_address,/() => {},/g' www/ray-tracer-challenge.js

Performance profiling

Although the ray tracer is not (yet) heavily optimized (e.g. it does not yet leverage Zig's SIMD builtins), it is still very fast—faster in fact on a single thread than almost every other Ray Tracer Challenge implementation on multiple threads I've compared with. And there is still significant room for optimization.

The optimizations I do make are largely informed by profilers. When built for native, the binary can be profiled with valgrind --tool=callgrind and the results inspected with qcachegrind, which works well enough. Unfortunately, Valgrind's troubled state on macOS, combined with Zig's incomplete Valgrind support, means profiling is not always simple. For example, I've seen Valgrind erroneously run into SIGILL and the like. Using std.heap.raw_c_allocator on native seems to fix most of these issues.

The ray tracer currently runs about 2x slower on WebAssembly than on native, which is reasonable. I use Firefox's "performance" tab in the developer tools for profiling on the web.

I also use hyperfine for benchmarking.

Benchmarks

Below are some benchmarks for scenes that can be found on the website. These benchmarks are not rigorously controlled and averaged, but rather a general overview of speeds for various scenes. They may also change depending significantly between Zig compiler versions. For example, I noticed a perfromance regression of up to 25% going from 0.11.0 to the WIP 0.12.0 (perhaps related to this similar issue). The best way to get a feel for the performance is to try things out yourself!

All benchmarks were done on a 2019 MacBook Pro (2.6Ghz, 6-Core Intel i7; 16GB RAM; macOS 12.6.7). WASM specific benchmarks were done on Firefox 117 using 6 web workers (the maximum number of web workers Firefox will run in parallel, even on my 12 logical CPU system 🤷‍♂️). Native runs used 12 threads.

The 'WASM Preheated' category refers to renders done with the scene pre-built (scene description already parsed, objects and bounding boxes already made, textures already loaded, etc.), which is supported on the site through the arrow key camera movememnt. This preheating is irrelevant for simple scenes, but gives massive speedups for scenes that load textures or construct BVHs.

Also note that renders on the website are periodically polled for completion. Renders may actually complete up to 100ms before the reported time, which affects the benchmarks for very short renders.

Scene Resolution Native WASM WASM Preheated
Cover Scene 1280x1280 1.413 s 2.408 s 2.299 s
Cubes 600x300 0.225 s 0.418 s 0.407 s
Cylinders 800x400 0.111 s 0.221 s 0.109 s
Reflection and Refraction 400x200 0.113 s 0.213 s 0.205 s
Fresnel 600x600 0.283 s 0.429 s 0.411 s
Groups 600x200 0.091 s 0.217 s 0.202 s
Teapot 250x150 0.175 s 0.413 s 0.210 s
Dragons 500x200 6.957 s 12.663 s 2.492 s
Nefertiti 300x500 4.827 s 6.358 s 3.036 s
Constructive Solid Geometry 1280x720 0.267s 1.920 s 1.792 s
Earth 800x400 0.095 s 0.212 s 0.103 s
Skybox 800x400 1.466 s 1.531 s 0.102 s
Raytracer REPL Default 1280x720 0.210 s 0.220 s 0.209 s

Other implementations

There are many great implementations of the Ray Tracer Challenge. At many points throughout the project, I referred to others to verify my implementation, draw inspiration, or compare performance. I recommend you check out the following ray tracers:

Known limitations

The website for this project uses the SharedArrayBuffer type, which requires certain HTTP headers to be set, something that GitHub Pages does not support. To get around this, I use coi-serviceworker, which has the disadvantage of not working in Private/Incognito sessions.

Some devices (mobile phones in particular) may not have enough memory to render some of the scenes on the website, especially the "Skybox" scene.

ray-tracer-challenge's People

Contributors

sinclam avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

ray-tracer-challenge's Issues

Reduce unneeded copying

Rendering the cover image currently takes around 15 seconds and can be cut to around 12.5 seconds by tinkering with the allocator. This performance is ok for a single threaded renderer, but not great. Here's a peek into the call graph for the cover image render.

image

Unsurprisingly, storing a Shape(T) instead of a *const Shape(T) in an Intersection(T) is causing huge memory overhead with unnecessary copying. This could also be the cause of the renderer's hideous WASM performace if the compiler is not emitting bulk memory operations.

Less obvious is the huge amount of time spent in __gttf2, a soft-float routine. Why on earth is the compiler emitting calls to soft-float functions? It looks like the calls are due to the C allocator, so when I stop linking libc (i.e. for WASM), this should (hopefuly?) not be an issue.

Anyway, these major performance hits needs to resolved.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.