RbxShader: A robust shader engine, for everyone

Amazing! To think this Super Optimised Pixel Raytracer with Textures! would become free material! I did try out the stuff it’s a little confusing and didn’t get it to work but I will wait for the instructions! It’s cool to see this kind of thing be used in Roblox. I can’t wait for more stuff like this since I myself am not capable I’ll leave it to you guys! I can see more stuff like this in the future when coders know implement this kind of stuff more, unlike other software (unity? I am not making fun of them) where they come with shaders like this or so I heard (VHS style games). Not sure if any of that made sense, but can’t wait for more!

3 Likes

Hi! Thank you for your appreciation and sorry for the late reply! I was busy making the tutorial for the module and is now available. I hope this fixed your problem!

Finally someone doing this :sob:
Godspeed man, i hope the performance issues gets well over time.

1 Like

Thanks for crediting me for CanvasDraw! Just a couple of hints to help improve performance however!

local function PerFrame ( iTimeDelta : number )

		local iTime = iTime()
		if Step > InterlaceFactor then Step = 1 end

		for y = Step, Canvas.Resolution.Y, InterlaceFactor do
			for x = 1, Canvas.Resolution.X do
				ImageBuffer:SetRGBA(x, y, Shader.mainImage(
					Vector3.new(ImageBuffer:GetRGB(x, y)),
					Vector2.new(x + CanvasOffset.X, y + CanvasOffset.Y),
					iTime,
					iTimeDelta,
					iResolution
				))
			end
		end

		Canvas:DrawImage(ImageBuffer)
		Step += 1
	end

Firstly, your method of using a blank ImageData object as a buffer isn’t needed. A canvas is it’s own buffer!

You are technically setting pixels twice (one in the image data, one in the canvas when drawing said image)

You can disable AutoRendering (CanvasDraw.AutoRender = false)

and then use Canvas:SetRBG() instead of ImageData:SetRGB(),

and then instead of Canvas:DrawImage(), use Canvas:Render()!

This will maximize per pixel efficiency!


Secondly, you should use more actors than threads in your CPU or whatever CPU core amount you’re targetting. In your example, you have it set to 4. Setting this to like double with help spread out the workflow better and slightly increase FPS.

6 Likes

Hi! Thank you for reaching out to me! Sorry for the late reply, I have trying to implement what you’ve said but I can’t seem to do so because the array I’m producing keeps being larger than Size.X*Size.Y*4, I know it’s an indexing problem but I can’t seem to figure out why can you help me point out the problem here?

NVM, I was being stupid and made the for-loops run adjusted to conform to it’s position on the “global canvas”, but I forgot the canvas are subcanvases (smaller canvases that make up the whole scene) so it should really just be local positions. :triumph:

Anyways, thank you so much for pointing it out. because of this, I managed to squeeze out an extra 2-4 frames (when interlacing is set to 1, and canvas size is 180 by 120)! Also, I am aware that having more actors can help spread out the workflow, I only set mine to 4 because it doesn’t really do that much of a difference on my device; but thank you for mentioning it!

3 Likes

The new release, v1.3.0 is out. It features a new configuration parameter called DualAxisInterlacing which makes the renderer interlace for both axises of the screen when set to true.

A canvas size of 180 by 120 and having your configuration set to:

{
	InterlaceFactor = 2 ,
	DualAxisInterlacing = true ,
	ScreenDivision = 16
}

can now give you an average of 25 frames on most shaders (on dual-core processors atleast).

Does this work on older drivers? (P1000 Notebook)

I’m not sure, but you could go ahead and try!

Yeaaaahhh it bluescreeened… In my offense i have a VERY VERY old laptop like its older than my brother.

1 Like

I have 0 experience in graphics area, so what is this, what is a shader engine, is this for like playing videos, im confused.

For playing shader programs, you can view examples of such by going to Shadertoy. if you wish to know more, you can do more research about shaders or graphics programming in general.

1 Like

v1.4.1 has been release.

And we’ve got few things to cover. Buffers are now supported. Additionally, for everyone that is currently using it, there will be a bit of an API change. Any questions and feedback regarding these changes and additions are welcome.

I. API Changes

First and foremost, you now have the ability to put the shaders to any GuiBase of your choice via the Screen parameter, as originally, they were only restricted to ScreenGui’s.

RbxShader.new() now holds a new 6th parameter called ShaderID, this allows for multiple shaders to be ran for a single host script as previously, whatever was the host/parent of the script would automatically be the parent of the shader workers threads, which would be problematic for people running multiple shader programs (though I doubt anyone actually would do this) for the same host.

Consequently, this means that RbxShader.run() and RbxShader.stop() now takes in a ShaderID instead of the host of the program.

Added new functionalities, such as RbxShader.pause() and RbxShader.resume() which as you’ve guessed, pauses and resumes a shader program. The difference between these functions and .run() and .stop() is that it preserves the iTime of the program, which most shaders often rely on for moving scenes, etc.

A new function, called RbxShader.set() has also been created. Which sets a shader program’s canvas size, interlacing factor, and subdivisions (equivalent to the amount of worker threads) to whatever you want. It also preserves iTime, as it uses .pause().

Lastly, we have RbxShader.clear(), which wipes off the shader program by the given ShaderID from the host. Useful if you only ever need to display the program for a short period or when it’s too far too be rendered becoming a waste of processing power.

II. Buffers

Buffers are a way to make multiple passes on a single frame. Useful for structuring and organizing your shader program.

You can now make buffers but only ranging from A to Z. This is by design, as having too many buffers is absurd. This means that proper function name for buffers could only be "bufferA, ..., bufferZ" else they will not be recognized as buffers (but having everything to be in lowercase is allowed).

III. Input Handling

Added a new sixth parameter for mainImage and buffers called iMouse, which acts as a Vector2 that represents the mouse’s position on the screen (with respect to the UI inset). This value only ever changes to wherever the mouse moves when the left mouse button is held down inside the display of the program.


Here is a short video showcasing some of the new features mentioned.

4 Likes

oh damn this thing is awesome!!
it might not be that performant but i cloned an existing shader and it works like a charm: original shader

2 Likes

How come I haven’t heard of this? Is this more performant than Hexo’s shader system and that other one? Considering that it says it has multithread and Hexo’s doesn’t and it also has interlacing (Hexo’s also has interlacing) which the shader system made by someone who’s name I don’t remember doesn’t have interlacing. The best of 2 worlds! Tho it EditableImages so no live servers.

same

just use canvasdraw so it can be used in live servers but so it also can use editableimages when your in studio
edit: wait your using the beta but wait shouldnt it work in live servers but actualy im wrong i thought the new beta canvasdraw automatically uses the old create a bunch of colored frames method or the uigradient method well i actualy havent used canvasdraw before also just so you know you can change the canvasdraw canvas color and blur you should make it an option to change the canvas color or blur

I also wish it ran on the GPU so I can run this at 144 FPS but ROBLOX doesn’t let you do that hope ROBLOX adds shader support (but coregui will draw over shaders so you can’t hide them for security reasons)
Also CPU shaders do kindof exist they’re not really shaders but it is rendering an example is Blender Cycles on CPU setting or Blender Compositor on CPU setting they are much more optimized it is probably possible to make this run most shaders at a smooth 60 fps at 180 by 120 with interlacing 2 or even 1920 by 1080 with no interlacing but ROBLOX’s lua is not that fast

edit: I also would like it if alpha was added so i can see through the canvas tho im pretty sure thats not in canvasdraw yet. (edit: it does but rbxshader makes the background opaque) also i did get this running also interlacing is not working
edit: i got interlacing to work

	- there is something very wrong with how I calculate
	  material reflectance

instead of

local Direction = g.reflect(RaycastResult.Position, RaycastResult.Normal)

do

local Direction = g.reflect(RaycastResult.Position-Raycast.Origin, RaycastResult.Normal)
1 Like

Hey there, thank you for checking out my resource!

I am not sure, about that. Benchmarks could be made, but I don’t want to be the one to do it as I don’t want to look too competitive. In fact, I also have seen Hexo’s shader system before I embarked on this project. I tried to use it but the way how you make a shader on that module felt really unintuitive to me + he didn’t have proper documentation on how to use it :cry:. ( But I do understand that the design choice was meant to leverage performance—especially for a single-threaded shader system )


I am infact using the beta—of CanvasDraw v4, which is a version that supports EditableImage. You could modify the source of the code at the RbxShader.Worker file so that it uses CanvasDraws’ Canvas object instead to render the shader, then you’ll be able to publish it for live production.


Same, if they’ll never make an explicit interface to interact with the graphics library or whatever, at the very least I wish they could make Luau something like Bend (a high-level massively parallel programming language), where “Anything that can run in parallel, will run in parallel”.


Could you elaborate how? I got ran my test place up and the interlacing is working perfectly fine for me; did you set shader configurations properly?


I really thought that I had already properly implement this, but it turns out I haven’t.
10 minutes later, I have found a solution. After some tinkering, I learned that returning colors that have a custom alpha like this:

-- # `v3_rgb` means that we're splitting a Vector3 into 3 numbers (RGB channels)
return g.v3_rgb(col), 0.5

—doesn’t work because what Luau actually does is it takes the first element from the tuple, then returns it alongside 0.5 ( weird I know ). To resolve this issue, I’ve added two new methods at the graphics library, albeit sorta hacky:

-- # these split their respective value into RGB values, which they return
--   along with the alpha value given so that the tuple doesn't get cut
g.v3_rgba( v : Vector3 , alpha : number )
g.c3_rgba( c : Color3 , alpha : number )

This change will be a part of v1.5.2, which I’ll be releasing this afternoon.

just a question but, has Roblox added a way to use Viewport frames as buffers?

What do you mean by this? Could you possibly elaborate?

not sure how to explain this but i mean like getting what you see in a Viewport frame as an editable image. or getting it as a rendering buffer like you can in shadertoy with buffer A buffer B and so on.

I don’t think this is possible.

1 Like

dang, roblox should really add that. Though i do remember seeing a comment where someone mentioned being able to use Viewport frames as buffers. Anyhow im going to try this shader engine, i hope it not too laggy on my pc :<

2 Likes