Ray Tracing Module

Hello everybody!

Another month has passed and I can now present yet another update for my Ray-Tracing module. Although I am currently head-deep into finals I’ve still managed to improve the rendering-process by alot! (prior post)

What has changed?

  • The Ray-Tracer is now wraped in a user-friendly module
  • Render times have been decreased by 458% on average
  • Colors have also been updated
  • Changing to native-luau code implemetation for math-operations like dot-product and more has lead to a performance gain by ~45% (thanks to @TheRealANDRO for mentioning this in my last post)

Performance Update

  • rendering 280x280 pixel scene in 0.068 seconds on average (before: 0.41 seconds on avg)
  • rendering 560x560 pixel scene in 0.092 (before: 1.2 seconds on avg)

About the module

I have managed to wrap the entire Ray-Tracing program into a module which is easy to use.

-- creating a render using the module:

-- creating settings
local myRenderSettings = RenderSettings.new()
myRenderSettings.renderDistance = 250 -- render distance in studs
myRenderSettings.reflectionDepth = 4    -- reflections per pixel
myRenderSettings.camera = workspace.CurrentCamera
myRenderSettings.implementQueue = true

-- creating the renderHandler
local threads = 20
local renderFrame: Frame = script.Parent.RenderFrame

local renderHandler = RenderModule.new(threads, renderFrame, myRenderSettings)

renderHandler.OnFinished:Connect(function(renderTime: number, renderResult: {number})
    -- you can decide whether you want to add post-processing effects like Anti-Aliasing or run custom shaders
    -- note that this part is still under developement
    local newResult = renderHandler:ApplyPostProcessing(renderResult, {"AntiAliasing"})

    -- now draw the image to the editableImage inside the renderFrame
    renderHandler:Draw(newResult, renderFrame.EditableImage)
end)

-- rendering the scene
renderHandler:Render()

-- when "implementQueue" is set to false in the RenderSettings the 
-- RenderHandler blocks any attempt of starting another render 
-- whilst the first one isn't finished. 
-- When set to "true", the renderHandler will add the request to a 
-- queue and process it once the prior renders have finished.
renderHandler:Render()

New Renders

Here are some new renders:

I hope you find this project as interesting as I do. I am looking forward from seeing some feedback from you, especially for the module and programming part.

I hope to release this module soon but I am still waiting for ROBLOX to publish EditableImages to the ROBLOX Client as this module would not work without them.

8 Likes

This is great! Glad to see you’ve improved greatly on the performance, have you also tried Parallel Luau? It might help you render other details in the image such as the skybox, without taking a big hit on the performance.

1 Like

I am already using Parallel Luau as indicated by the “threads” variable in the code example.
The module creates Actors which handle the given workload.

On a single thread a 560x560 render takes up to 5.5 seconds (which is still fast but nowhere near the 0.092 seconds on 20 threads.

Sadly every calculation has to be done on the CPU so this slows it down even further. At least it can “real-time” ray-trace a 100x100 scene @ 15 to 20 fps.

I created this module not with the intend to real-time ray trace, but rather to help developers out who want to have GFXs in their game. As of now the traditional way to achieve this is via exporting a scene to blender to then render it and upload the image to roblox again.
The module saves them from doing all of that as it can render smaller icons (for shop UIs or inventory) fast without having to worry about an image being falsely taken down by ROBLOX’s moderation.

But there is a lot that needs to be implement before this could become reality.
Refractions and global illumination are the next two big things which I am currently working on.

1 Like

I’m noticing you are using 20 threads specifically. Is it because that somehow 20 threads seem to just run the best for this sort of workload? From my testing ive reached a similar conclusion with my own ray tracer (18-22 threads performing the best).

I’ve rendered a 560 by 560 scene using 112 actors once, render-time way around 0.006 to 0.02 seconds. The thing is that no matter how fast the rendering process is, the drawing also takes some time. Meaning using more than 20 threads for the renders I do would make no difference in display-time.

Long story short, the EditableImage’s :WritePixels() method is the bottleneck, at least for me.

I know, drawing the actual pixels is usually the primary bottleneck. I’m just asking if you found that 20 threads specifically (or some different value) seem to perform way better than any other thread count (with or without actually drawing pixels). Or if you have found any other arbitrary number that seems to apparently provide the highest performance.

Personally i’ve noticed that a while back (somewhere last year) roblox changed something about parallel luau so that it can no longer really properly utilize any cpu. I’ve tested with a cpu as old as an i7 4790 and still found that parallel luau can no longer properly max out anything.
Before this magic change Parallel Luau was very much capable of maxing out even more modern chips so im not exactly sure what changed about it.

This lead me to test the same magic 20 thread count on a different range of cpus (both intel and amd) and somehow all of them magically performed the best at that same 20 threads. This was a few months back so maybe something changed until then but super quick testing that i can do right now still provides similar results (though different thread counts).

Still whatever they did, those changes are leaving varying amount of resources on the table for no apparent specific reason.

I used 20 because I have 20 logical processors in my CPU (intel i9 10900F). It can be said the more the better, but there is a limit to when roblox decides to break/ when the performance is being bottlenecked.