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

if you aren’t using much colours, then you can try to increase the resolution limit in the module itself, and see how it goes, but i highly recommend sticking to the limit anyways as going any higher also seems to cause lag as well depending on what you are doing, and isn’t practical for games.

Why does your resolution need to be that high anyways?

1 Like

Small Update v4.1.0.b

Added two new CanvasDraw functions that are intended for storing compressed ImageData efficiently for datastore use:


  • CanvasDraw.CompressImageData(ImageData) : CompressedImageData

    • Returns a compressed image in the form of a very small table which takes advantage
      of a string compression algorithm for the pixel data which reduces file size by a lot.
  • CanvasDraw.DecompressImageData(CompressedImageData) : ImageData

    • Decompresses the CompressedImageData table and converts it back to
      the original ImageData class.
3 Likes

as you can see only 1 side is shown correctly, the rest are not displayed correctly, how would I fix it?


script:

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(200,200))
local Engine = require(game.ReplicatedStorage.Classes.Engine)
local a = 0

for _, Object in pairs(Map) do
	if Object:IsA("BasePart") then
		for i = 1, 8 do
			a += 1
			local folder = script.Parent.Parent.Frames
			local frame = Instance.new("Frame")
			frame.Parent = folder
			frame.Name = "Frame".. a			
			

			
			coroutine.wrap(function()
				while true do
					local vertices = {} 
					local pos = Object.Position
					local size = Object.Size
					
					for j = 1, 8 do
						local offsetX = (j % 2 == 0) and 0.5 or -0.5
						local offsetY = ((j > 4) and -0.5 or 0.5)
						local offsetZ = ((j > 2 and j < 7) and 0.5 or -0.5)
						vertices[j] = pos + Vector3.new(size.X * offsetX, size.Y * offsetY, size.Z * offsetZ)
					end

					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() * vertices[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) * 200
					end

					local function drawTriangle(num1, num2, num3, Color)
						Canvas:DrawTriangle(frame("Frame" .. num1), frame("Frame" .. num2), frame("Frame" .. num3), Color, true)
					end

					local visibleSides = {}
					
					for j = 1, 6 do
						local normal = (vertices[j + 1] - vertices[j]).Unit:Cross(vertices[j + 2] - vertices[j]).Unit
						local toCamera = Camera.CFrame.Position - vertices[j]
						if normal:Dot(toCamera) > 0 then
							table.insert(visibleSides, j)
						end
					end
					
					local triangleDrawFunctions = {
						[1] = function() 
							drawTriangle(2,4,6, Color3.new(1, 1, 0))
							drawTriangle(2,6,8, Color3.new(1, 1, 0))
						end,
						[2] = function() 
							drawTriangle(2,7,8, Color3.new(0, 1, 0))
							drawTriangle(2,7,1, Color3.new(0, 1, 0))
						end,
						[3] = function() 
							drawTriangle(1,3,7, Color3.new(0, 0, 1))
							drawTriangle(3,7,5, Color3.new(0, 0, 1))
						end,
						[4] = function() 
							drawTriangle(3,4,5, Color3.new(0,1,1))
							drawTriangle(4,5,6, Color3.new(0,1,1))
						end,
						[5] = function() 
							drawTriangle(1,2,3, Color3.new(1, 0, 0))
							drawTriangle(2,3,4, Color3.new(1, 0, 0))
						end,
						[6] = function()
							drawTriangle(5,6,7, Color3.new(1, 0, 1))
							drawTriangle(6,7,8, Color3.new(1, 0, 1))
						end 
					}


					for _, side in visibleSides do
						if triangleDrawFunctions[side] then
							triangleDrawFunctions[side]()
						end
					end


					task.wait()

					Canvas:Clear()

				end
			end) ()
		end
	end
end

it doesn’t look like an issue with CanvasDraw at all. It just appears to me that your calculations for the normals don’t seem to be working quite right.

I can’t quite understand what’s going on here since there’s quite a few interesting math and code techniques here, but it’s probably something in that field.

Yeah, you’re right, it is my math calculations problem, if you dont understand the:

for j = 1, 8 do
						local offsetX = (j % 2 == 0) and 0.5 or -0.5
						local offsetY = ((j > 4) and -0.5 or 0.5)
						local offsetZ = ((j > 2 and j < 7) and 0.5 or -0.5)
						vertices[j] = pos + Vector3.new(size.X * offsetX, size.Y * offsetY, size.Z * offsetZ)
					end

It is just getting position of 8 vertices of a cube, so how I predict, the problem is in this part of code:


					local visibleSides = {}
					
					for j = 1, 6 do
						local normal = (vertices[j + 1] - vertices[j]).Unit:Cross(vertices[j + 2] - vertices[j]).Unit
						local toCamera = Camera.CFrame.Position - vertices[j]
						if normal:Dot(toCamera) > 0 then
							table.insert(visibleSides, j)
						end
					end
					
					local triangleDrawFunctions = {
						[1] = function() 
							drawTriangle(2,4,6, Color3.new(1, 1, 0))
							drawTriangle(2,6,8, Color3.new(1, 1, 0))
						end,
						[2] = function() 
							drawTriangle(2,7,8, Color3.new(0, 1, 0))
							drawTriangle(2,7,1, Color3.new(0, 1, 0))
						end,
						[3] = function() 
							drawTriangle(1,3,7, Color3.new(0, 0, 1))
							drawTriangle(3,7,5, Color3.new(0, 0, 1))
						end,
						[4] = function() 
							drawTriangle(3,4,5, Color3.new(0,1,1))
							drawTriangle(4,5,6, Color3.new(0,1,1))
						end,
						[5] = function() 
							drawTriangle(1,2,3, Color3.new(1, 0, 0))
							drawTriangle(2,3,4, Color3.new(1, 0, 0))
						end,
						[6] = function()
							drawTriangle(5,6,7, Color3.new(1, 0, 1))
							drawTriangle(6,7,8, Color3.new(1, 0, 1))
						end 
					}


					for _, side in visibleSides do
						if triangleDrawFunctions[side] then
							triangleDrawFunctions[side]()
						end
					end

Out of interest, have to looked into incorporating parallel lua in this project? I was looking it relatively recently and it looks like it could make this project render faster then it already does, especially with the new editable Images in Roblox.

1 Like

i have no idea how to use multithreading well. Feel free to contribute to the project!

1 Like

are you planning to add model support? So you can make models here too.

@Ethanthegrand14 I had an idea the other day, and I want to just put this out there in case someone who is good at porting code and/or has quite a bit of coding knowledge wants to attempt it…

Since Blender is Open-Source, what if someone ported a possibly dumbed down version of the Eevee render engine to be used with CanvasDraw? :grinning:

Eevee already runs pretty decently in the “Render Preview” mode, so it would be interesting to see a version of it ported to work with CanvasDraw. :sweat_smile:

Not entirely sure how well it would work, but it is worth a try if anyone wants to attempt to do it. :saluting_face:

2 Likes

I was wondering…
Sprite Sheet support?

1 Like

honestly a really good idea. Definitely something I can add next update!

2 Likes

no clue what’s going on here, but for some reason any image i make in paint.net comes out all screwed up!
i have to open it in Microsoft Paint and re-save it for it to be fixed…

256x256 png from paint.net

the same png, opened in Microsoft Paint and re-saved:

somethin is up with this :face_with_spiral_eyes: perhaps its compressing the png in ways CanvasDraw isn’t expecting??

okay, actually right before i was gonna send this post i had a hunch and apparently i might be right. if you set the Bit Depth to anything below 8 bit while saving a png in paint.net, that’s when it starts breaking. paint.net automatically does this sometimes when it can to save space, so if anyone else is having this issue try changing the bit depth or re-saving your image in Microsoft Paint

2 Likes

That’s probably one of the few issues i cant fix. MaximumADHD’s PNG module doesnt seem to support all formats and bit depths, and lower bit depths wont work. I should probably mention that somewhere in my plugin.

1 Like

CanvasDraw Tools Sprite Editor Update - v4.1.1.b

After the release of the very awesome and epic release of the built-in image editor, it’s about time time it has received an update.

Let’s start from the top!

Image Effects!

That’s right, you heard me, the sprite editor will now start supporting special image processing effects.

Currently, we have 2 new effects: Quantising/Dithering and Blurring

Quantising with dithering:

Quantising without dithering (posterising):

Blurring:

Canvas content resizing!

You can now resize the canvas including it’s contents which will be rescaled to fit your new desired resolution

Visual Improvement

In some scenarios, it can be hard to read the text or see buttons due to the transparent style of the UI. Borders have been added on all the menus and some buttons to fix this.

Bug Fixes

Importing PNG’s with transparency from your computer didn’t import correctly causing to load in images with no transparency at all. This has now been fixed!


I have also fixed the modules Canvas:CreateImageDataFromCanvas() method not working at all. You should now be able to use this without any issues!

11 Likes

literally baldi basics effect lol

1 Like

Due to the fact that this workflow requires us to manually draw the sprites on each frame, what if, Drawing an Image onto the canvas could come with additional properties like RectOffset and RectSize.

This would mean that the developer would have to write code for a Sprite Player, yes. but that could be a built-in, optional module.

2 Likes

Ill take note of this, I’ll figure something out for sure

1 Like

yup
image

5 Likes

holy crap man, I love it!

What’s the resolution there and the render times?


I have also made my own hacky raytracer in the past, thought i’d show off a render I did:

this took 2 minutes and 48 seconds at 340x200

40 samples per pixel for shadows and reflections

EDIT: Did another one:

4 Likes

Also tried that once:


image

6 Likes