CanvasDraw - A powerful pixel-based graphics library (Draw pixels, lines, triangles, read/modify image data, and much more!)

Better to do with CFrames, almost the same way, but:
Corner = Part.CFrame * (Part.Size.X / 2, Part.Size.Y / 2, Part.Size.Z / 2)
But with all 8 possible ± This way it will account for part rotation.

1 Like

Patch v4.0.2.b

  • Fixed canvas clearing and filling methods using the wrong order of colour channels from the canvas colour.

CanvasDraw can also now be redistributed or shared for free without cost as long as credit is kept.

1 Like

uhm, it’s Corner = Part.CFrame * CFrame.new(Part.Size.X / 2, Part.Size.Y / 2, Part.Size.Z / 2)

2 Likes

Oh, yes, I have forgot to put datatype before brackets. Btw, Vector3 will also work. Thanks for pointing that out!

2 Likes

I made an object renderer with triangles, but only for one object, how do I render more objects at the same time?

local Map = workspace:WaitForChild("Map"):GetDescendants()

local Camera = workspace.CurrentCamera

local CanvasModule = require(script.Parent.CanvasDraw)

local Canvas = CanvasModule.new(script.Parent.Parent.Frame, Vector2.new(240,240))

local a = 0
local b = -8

for _, Object in pairs(Map) do
	if Object:IsA("BasePart") then
		b += 8

		for i = 1, 8 do
			a += 1

			local folder = script.Parent.Parent.Frames
			local frame = Instance.new("Frame")
			frame.Parent = script.Parent.Parent.Frames
			frame.AnchorPoint = Vector2.new(0.5, 0.5)
			frame.BackgroundColor3 = Color3.new(0,1,0)
			frame.Name = "Frame".. a
			
			coroutine.wrap(function()
				while task.wait(0.01) do
					local Corners = {
						[1] = Object.CFrame * CFrame.new(Object.Size.X / 2, Object.Size.Y / 2, Object.Size.Z / 2),
						[2] = Object.CFrame * CFrame.new(Object.Size.X / 2, Object.Size.Y / 2, Object.Size.Z / -2),
						[3] = Object.CFrame * CFrame.new(Object.Size.X / 2, Object.Size.Y / -2, Object.Size.Z / 2),
						[4] = Object.CFrame * CFrame.new(Object.Size.X / 2, Object.Size.Y / -2, Object.Size.Z / -2),
						[5] = Object.CFrame * CFrame.new(Object.Size.X / -2, Object.Size.Y/ 2, Object.Size.Z / 2),
						[6] = Object.CFrame * CFrame.new(Object.Size.X / -2, Object.Size.Y / -2, Object.Size.Z / 2),
						[7] = Object.CFrame * CFrame.new(Object.Size.X / -2, Object.Size.Y / -2, Object.Size.Z / -2),
						[8] = Object.CFrame * CFrame.new(Object.Size.X / -2, Object.Size.Y / 2, Object.Size.Z / -2)
					}

					local ViewportSize = Camera.ViewportSize
					local AspectRatio = ViewportSize.X/ViewportSize.Y

					local VerticalFoV = math.rad(Camera.FieldOfView)

					local ScreenSizeY = 2*math.tan(VerticalFoV/2)
					local ScreenSizeX = AspectRatio*ScreenSizeY

					local RelativePosition1 = Camera.CFrame:Inverse() * Corners[i]

					local ScreenPositionX1 = RelativePosition1.X/-RelativePosition1.Z
					local ScreenPositionY1 = RelativePosition1.Y/-RelativePosition1.Z

					frame.Position = UDim2.fromScale(
						1/2 + ScreenPositionX1/ScreenSizeX,
						1/2 - ScreenPositionY1/ScreenSizeY
					)

					local function frame(name)
						return Vector2.new(folder:WaitForChild(name).Position.X.Scale, folder:WaitForChild(name).Position.Y.Scale) * 240
					end
					Canvas:DrawTriangle(frame("Frame" .. 1 + b), frame("Frame" .. 2 + b), frame("Frame" .. 3 + b), Color3.new(0, 0, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 2 + b), frame("Frame" .. 3 + b), frame("Frame" .. 4 + b), Color3.new(0, 0, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 1 + b), frame("Frame" .. 2 + b), frame("Frame" .. 5 + b), Color3.new(1, 1, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 2 + b), frame("Frame" .. 5 + b), frame("Frame" .. 8 + b), Color3.new(1, 1, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 2 + b), frame("Frame" .. 4 + b), frame("Frame" .. 7 + b), Color3.new(0, 1, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 2 + b), frame("Frame" .. 7 + b), frame("Frame" .. 8 + b), Color3.new(0, 1, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 1 + b), frame("Frame" .. 2 + b), frame("Frame" .. 5 + b) , Color3.new(1, 0, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 3 + b), frame("Frame" .. 5 + b), frame("Frame" .. 6 + b), Color3.new(1, 0, 0), false)
					Canvas:DrawTriangle(frame("Frame" .. 5 + b), frame("Frame" .. 6 + b), frame("Frame" .. 8 + b) , Color3.new(0, 0, 1), false)
					Canvas:DrawTriangle(frame("Frame" .. 6 + b), frame("Frame" .. 8 + b), frame("Frame" .. 7 + b) , Color3.new(0, 0, 1), false)
					task.wait()
					Canvas:Clear()
				end
			end) ()
			
		end
		

	end
end
2 Likes

Been using this module for a few projects, its amazing and I can’t wait for 4.0 to work in-game too! But, Is there maybe a way to place these editable images next to each other to create a bigger canvas and then use the module’s normal functions and features on that bigger canvas? :thinking:

1 Like

Yeah that’s definitely possible. Im not sure how I’d personally go about it, but anyone can contribute to the project!

What about a RTX render?
Why would I use canvasdraw for that?

An RTX render is definitely doable. But if you plan to do a high resolution slow non real time render, you’re better off using raw editable image with ur own methods.

CanavsDraw is basically an extremely fast graphics library for roblox that runs under EditableImage.

You can make things from 2D games, to fully fledged 3D textured renderers. The limits are pretty well endless.

because I think rtx graphics are better and easier (but less performant) than normal graphics :person_shrugging:

You’re asking a lot for a custom roblox renderer lol. It would be great to have shader scripts in The roblox tho :thinking:

yeah, I made a post for that already.

2 Likes

Is there a separate model for CanvasDraw 4.0? I wanna use it with EditableImage but I can’t seem to find the module.
I still have the old model though I wonder if it’s been updated to 4.0.

1 Like

Check the main post. There are 2 links to canvasdraw 3.0 and 4.0. Also the current normal model is always up to date

3 Likes

Very cool module. Is there an efficient way to make it so that if a canvas is on a SurfaceGui, you have a SurfaceLight that is coloured based on the pixels on the canvas and same for the brightness. Somehow affect by the canvas. Basically ambient lighting based on the content of the canvas.

Yeah, I think.
You just use .new() on a Frame on a SurfaceGui.
I haven’t test it yet, but I’m sure it works.

The easiest way would be the average out all the canvas pixel colours into a single colour and then colour the light with that colour

Hi! I had a question:
I totally understand why it’s required to limit one axis of CanvasDraw 3.4.1, but why is it required to limit the other axis to 256?

With a new limit, I could place a canvas that is (500, 256).
If I understand correctly, the only limitation of 3.4.1 is the fact that gradients can only store a certain amount of information per string, but there shouldn’t be anything limiting you from creating more gradients on the other axis.

Correct me if I’m misunderstanding, but I think it would be really nice if the module came with functionality for having an unlocked width component.

Thanks!

The resolution is limited because when roblox renders too many UI frames, it completely breaks your GUIs causing many problems.

I have selected a limit of 256x256 cause it seems to be the highest you can go without running into rendering problems when using lots of colours or textures.

CanvasDraw 4.0 avoids this issue as it only uses one UI instance, which is the EditableImage, but currently only works in roblox studio with the beta enabled.

1 Like

Ah, I see. Another case of Roblox rendering being a little rough when put under pressure.

I will 100% be using the EditableImage version when EditableImage is released to the general public. However, unfortunately I need to use this for a game that will be public very soon.

The canvas needs to be 512x288. Any suggestions for how I could achieve this?

1 Like