Show HN: I wrote a C++ ray tracer from scratch without AI

Posted by martiano 2 days ago

Counter153Comment64OpenOriginal

Comments

Comment by martiano 2 days ago

Hey HN,

5 years ago I was 17 and learning to code C/C++ in a coding bootcamp (42). One of the projects was a simple C ray tracer. I really enjoyed working on the project and always loved computer graphics, so I decided to create my own path tracer from scratch, in C++, without using any third-party libraries.

I ended up working on it consistently for over a year, then sporadically when CG excitement hit me again. Recently I polished it and completed some unfinished features and decided to make it public, finally. It's a C++20 Path Tracer with a CPU renderer. It is able to render good-looking images with reasonable performance and sample count.

Btw this was initially coded without AI, but I've used it for the recent clean up and features. This project is a personal favorite of mine, and it can improve a lot, so I'd love to hear your feedback.

Comment by hresvelgr 1 day ago

Great work, the examples look fantastic. I will say, it's misleading to put "without AI" in the title for you to then comment on your submission that you have in fact used it. While it may only be in a trivial capacity, you've still used it.

Comment by martiano 1 day ago

I get your point. I consider it fair with the disclaimer because the "manual" version was very similar to current but missing some love

Comment by mcronce 1 day ago

You think that an LLM provides "love"?

Comment by almostjazz 1 day ago

Maybe you could set your manual version as the main branch and then have a separate AI-cleaned branch on the side? I think the manual version part is what is exciting people and drawing them in. Even if it is worse or doesn't work!

Comment by smartmic 1 day ago

> Btw this was initially coded without AI, but I've used it for the recent clean up and features

Then it makes sense to update the submission title. To me it reads as if the project was written completely without the help of AI (which might be a quality badge to some), but it is not 100% true then.

Anyhow, cool project ;)

Comment by martiano 1 day ago

Thanks! I get your point about AI, but I think it's fair to say it's almost 100% AI free. I worked on it for ~15 months, vs 1 week now with AI. Previous results were quite similar

Comment by mywittyname 1 day ago

> 1 week now with AI

1 week is enough to build out a full-featured application with AI if you know what you're doing and are using proper tooling.

You may want to use a better metric to quantify what AI tooling did in the project.

Comment by gspr 1 day ago

> think it's fair to say it's almost 100% AI free.

So write "almost without AI" in the title, then!

Comment by socalgal2 1 day ago

My experience is 1 week of AI can = a year of by hand development.

Comment by applfanboysbgon 1 day ago

I am interested in hand-crafted software, and it feels deceptive when you put "no AI" in the title only to reveal there was. If you try to minimise its impact after, one wonders, if the impact was so minimal, why it was necessary. If you worked on it for 15 months without generated code, vs. 1 week with, why not finish the job? What was the purpose of introducing generated code in the last week, and could you not have taken a little more time to do it by hand given you already invested so much time into it?

Comment by pixelesque 1 day ago

JFYI: Your inverse ray direction calculation is not NaN-safe: if rays are completely axis-parallel in one dimension, so the direction value is 0.0 for that axis, you'll be doing the val / 0.0 which results in a NaN...

Also, as you're using full double/f64-precision all the time, you're leaving a fair bit of performance on the table: transcendentals (sin(), cos(), etc) in particular - can be a lot slower than when using f32, and generally double precision can be special-cased to particular areas of the renderer that need it (curve, sphere intersection, and some situations where volume scattering produces very small distances).

Comment by adrian17 1 day ago

> Also, as you're using full double/f64-precision all the time, you're leaving a fair bit of performance on the table

There's another issue that popped up on my quick naive profiling run: std::shared_ptr<Material> in the HitRecord/HittableLightSample is assigned/copied and destroyed a lot, and somehow these refcount operations show up as half of all samples on my profile (presumably because even if there's no hit and the pointer stays nullptr, the smart pointer still must check if there's anything to deallocate).

Comment by pixelesque 1 day ago

Yeah, passing std::shared_ptr by value in a multi-threaded setup can have a lot over overhead due to them being copied and destroyed a lot, and the fact that the atomic ref count value modifications effectively cause a write back to cache and can cause contention.

Should pass them by const refs really to avoid this.

Comment by cyber_kinetist 1 day ago

Or for a better alternative, just use plain old indices rather than shared pointers.

The scene is only going to be loaded / unloaded all at once, you can just load the data into contiguous arrays and index from them. No need to use shared_ptr since lifetimes aren't that complex.

Comment by pixelesque 1 day ago

Or just raw pointers, indeed.

std::shared_ptrs can also (because they're implicitly for sharing) alias, so the compiler has to assume the worst and emit loads in other cases, and there's no way (unless a newer C++ version has introduced it and I haven't noticed?) to use '__restrict__' with shared ptrs.

Comment by adrian17 1 day ago

[dead]

Comment by martiano 1 day ago

Implemented this and the other improvements suggested on the thread. Performance up by 20%! Thanks for the feedback. https://github.com/themartiano/luz/pull/3

Comment by deliveryboyman 1 day ago

What's the proper way to handle a zero in the direction vector when calculating the reciprocal direction? Should it evaluate to infinity?

Comment by pixelesque 1 day ago

Inverse is still 0.0 technically, but yes, there is a trick you can use with Inf and SIMD to mask them out, so Inf is sometimes used.

However, I'd just condition it for the moment.

so:

invDirX = dirX != 0.0 ? 1.0 / dirX : 0.0; etc, etc for each dimension.

Obviously doing the != 0.0 comparison is not great, as it suffers from potential issues again (especially if you have denormals), but you can generally get away with it I've found in most cases.

Comment by shinycode 1 day ago

Congrats on doing 42 and to have worked and shared your project, very nice results !

Comment by MyHonestOpinon 1 day ago

Amazing. What happened with your professional career ? Did this exercise help you out professionally ?

One of my worries about AI is that doing these deep dives are a lot harder to justify.

Comment by martiano 1 day ago

I just launched the project, so can't say it helped me professionally yet. Almost all of the time invested in this was pre-AI. I agree it's harder to justify those deep dives but still worth it if you do it alongside AI IMO.

Comment by MyHonestOpinon 1 day ago

Even if the project didn't become popular. Have you been able to use it as part of your portfolio to get a job, or move into academia ? Perhaps what you learned in the project was useful in some other way ?

Comment by martiano 1 day ago

I have used it when applying to some jobs but no success so far. I think this project was useful because it allowed me to go deeper than I ever had in code. I had very though issues that required me to ask in forums etc. I had a bug with ray-triangle intersection that took me 3 months to find the cause. So it was good training and it's a great project to have on my portfolio. I'm sure it can help me if I apply for something related to computer graphics and maybe gaming.

Comment by yardie 1 day ago

How did you like 42? Would you recommend it? I worked some great devs who came out of 42. They all wanted to be game developers. The industry is notoriously unreliable. So they pivoted to writing business software where the client actually pays you for more features. LOL.

Comment by manoji 1 day ago

Hey ! Great work , I wanted to try something like this as well to begin my journey into games and computer graphics . I would love to know what resources you used to learn.

Comment by martiano 1 day ago

The greatest resource I've found on the internet is the Ray Tracing in One Weekend series. (https://raytracing.github.io/) You can start there and go pretty far. Also you can mix random papers you'll find and eventually just testing and experimenting yourself.

Comment by pjmlp 1 day ago

Congratulations on achieving it.

Comment by ttoinou 1 day ago

Congrats ! Results look stunning

Comment by ssenssei 1 day ago

_" Btw this was initially coded without AI, but I've used it for the recent clean up and features. "_

???

Comment by wavemode 1 day ago

To be fair, the title is "I wrote a C++ ray tracer from scratch without AI", not "This C++ ray tracer, right now, contains no AI-written code"

It sounds to me like there is some point in this project's history when both of the following were true:

1) It was a C++ raytracer

2) It was entirely human-written

So technically there is no lie here.

Comment by ezekg 1 day ago

Wow, I also wrote a game 8 years ago and have been using AI to rebuild upon it. I'm excited to tell people that I wrote it from scratch without AI! Love these new rules!

Comment by rameerez 1 day ago

Look at the commit history.

Out of 557 total commits in the repo, 510 have been done before the past 2 weeks. All those (minus 5 in 2023-2024) have been done on or before July 2022, months before ChatGPT had even launched.

Out of the 47 commits in the last 2 weeks, 26 were README updates / CI / docs. The remaining 21 commits are clearly cleanups, speedups, bugfixes, and tangential features like Blender import/export. Which leaves us with 505/557 commits (90%) if we're not generous --or 531/557 commits (95%) in the best case-- of non-AI commits to the repo.

OP clearly wrote most of the project by hand and has just been cleaning things up for public release the last couple weeks. Exactly as he disclosed in his comment.

Comment by ezekg 1 day ago

I also wrote a huge chunk of my game by hand 8 years ago, but I wouldn't lead with 'it's built without AI' now because that would be disingenuous.

Comment by hardex 1 day ago

It all boils down to what each of you individually understands as "made with AI", which could be anything between using autocompletions and braindead vibecode.

Comment by Gud 1 day ago

So… it has been written with AI?

Comment by jasonjmcghee 1 day ago

This is (or at least used to be) a right of passage in the graphics world.

I think many people go through the very popular https://raytracing.github.io/

There was a big influx of this when Sebastian Lague did his video series on building a ray tracer.

Comment by pixelesque 1 day ago

And if you've decided you want to take it a bit more seriously, move on to:

https://www.pbrt.org/

which is effectively the bible, and has been for years (I wrote mine and moved into the VFX industry when the Second edition was still out! - I feel old now)

Comment by evilturnip 1 day ago

Ray tracing is one of those problems that is conceptually so simple, yet continues to take so much mindshare because of all the challenges to implementation.

Comment by Phelinofist 1 day ago

"Without AI" is the new "Written in Rust", SCNR

Comment by tmtvl 1 day ago

'Have you considered rewriting it without AI' seems like something I could see myself saying.

Comment by cultofmetatron 1 day ago

for anybody else interested in this undertaking, I recommend this book https://pragprog.com/titles/jbtracer/the-ray-tracer-challeng...

Comment by ahoka 1 day ago

Without AI is the new "in Rust".

Comment by ivanjermakov 1 day ago

Me too, but in TS/WebGPU: https://github.com/ivanjermakov/moonlight

Very fun! Packing data for GPU-side BVH was quite tricky.

Comment by martiano 1 day ago

Wow, pretty good. Why web?

Comment by ivanjermakov 1 day ago

Thanks! Wanted to tackle WebGPU for making browser games.

Comment by socalgal2 1 day ago

why not web? 1000x easier than native and 1000x easier to share

Comment by eleventen 1 day ago

A C++ ray tracer from scratch was the course project for my computer graphics class in 2016. I enjoyed the exercise immensely. Not nearly as robust as yours of course.

Comment by Quarrel 1 day ago

I basically was ready to come on and make a snarky comment like this. "I wrote one in the '90s!".

and then I saw the examples, and the feature set. I particularly like the blender-to-Luz export.

It seems great. Good luck to OP.

Comment by Alifatisk 1 day ago

> without AI

Now this is how you catch attention

Comment by glouwbug 1 day ago

I expect similar headlines like “I saved on token cost by hiring juniors” to come in soon too

Comment by gspr 1 day ago

Indeed. Until it turns out not to be true: https://news.ycombinator.com/item?id=48541543

Comment by Alifatisk 1 day ago

Bummer. I fell for clickbait as usual.

Comment by cute_boi 1 day ago

I just flagged this post. With AI i can write in 1 day, so what is the point here....?

Comment by chadgpt3 1 day ago

Flagged for misleading title, since you admitted to using AI.

Comment by rajhphuyal 1 day ago

Great work on such a technically challenging project.

Comment by sharpfuryz 1 day ago

Have you considered rewriting it in Rust? Not for any technical reason (I say it reflexively now)

Comment by martiano 1 day ago

Not really, but it would be fun. I really like Rust as well

Comment by ddtaylor 1 day ago

HN ongoing support and disdain for AI is perplexing.

Comment by brianolson 1 day ago

yup. me too. once upon a time that was a 2 week assignment in graphics class in college

Comment by py93 1 day ago

Very cool!

Comment by deadbabe 1 day ago

I think these kind of projects fail to impress these days, with or without AI.

You need a second order effect, like “I did X using this thing I built Y”, where X is the actual impressive part and the Y is just an implementation detail. Maybe like that Roman Empire Names thing.

Comment by itsthecourier 1 day ago

for the love of the game, very refreshing good ol' coding

Comment by throwpoaster 1 day ago

Nice, I once built a ray tracer without using an SQL database.

Comment by tuinorizn 1 day ago

[dead]