This isn’t the right module for that then, you’d have to make an image sequence, basically take a whole bunch of images from the recaps and stitch them together via code.
This module is only helpful for the drawing part for your case. All you have to do is find a way to capture pixel data from your screen (and down scale the resolution) and for every frame, find a way to send every pixel data from your screen as color3 values and then draw every pixel to the canvas.
You may need third party tools to achieve this
i have such a Encoder already just i need a good decoder inside roblox
i will have to cache around 50 frames and in background constantly preloading
How can I make a raytracing rendering engine with this? im trying to make realtime reflections…
is it possible to use this to make minimap? something like rorender
This module is criminally underrated, when looking at the title I thought this was one of those basic drawing tools like in drawing games, boy was I wrong, first few hours of figuring out how it works and already got videos of around 20 seconds working (95x190 res with 10 fps) might look into making watchable live streams next (That aren’t laggy) and a tutorial if anyone is interested
Sort of. But you would just have to project the whole world into the canvas but your probably better off using ViewportFrames for this case
You’d have to do your own math, I have a topic on that contains a link to some raytracing stuff the you could prob start from there
its already done lmao, All i need is to blur the pixels, something thats been a challenge
Heck even more of a challenge compared to adding shadows. I plan on doing Box kernel Blur, but im not sure if thats a good option.
Btw, I used GradientCanvas for this reflections project, thanks to that, there are less guis in use.
Hi there! I gotta ask… may I take use this module, scan the Image functions so that i can write a similar system into my own upcoming module, but this time with some optimizations?
I’ve learnt a bunch of things that might help with the optimization part, Especially reducing the frame/instance count and etc.
Yeah sure. But please do credit me somewhere in your module (a comment will be fine) for the image functions as I put a tone of effort into them and making them run well
Optimisation Update - v2.5.0
This update brings some very needed optimisations and new algorithms which will perform much better than before giving your pixel, line, or even polygon based games real-time results at high resolutions!
General Optimisations
- Most of the drawing and pixel-based functions have been optimised or even rewritten completely. CanvasDraw now runs so well that I am running out of things to optimise.
Here’s a list of functions that have be optimised/rewritten:- DrawTriangle()
- DrawLine()
- DrawRectangle()
- DrawCircle()
- DrawImage()
Lines
-
The
DrawLine()
function has been completely rewritten and now uses Bresenham’s Line Algorithm to draw lines (instead of my poor attempt at an algorithm) -
There is also a new
DrawLineXY()
function which behaves similarly toDrawLine()
, but takes a seperate X and Y coordinates to declare the line points.
This function also runs much better thanDrawLine()
as it avoids general checks, rounding, table manipulation and vector constructing. This is a much more general, fast and raw method to drawing lines.
Triangles
-
The
DrawTriangle()
function has been completely rewritten and now uses a standard triangle algorithm which is extremely fast and efficient, compared to my old one which was a poor scan-line triangle algorithm. -
There is also a new
DrawTriangleXY()
function which behaves similarly toDrawTriangle()
, but takes seperate X and Y coordinates to declare the triangle points.
This function also runs much better than the normalDrawTriangle()
as it avoids general checks, rounding, table manipulation and vector constructing. This is a much more general, fast and raw method to drawing triangles. -
This new triangle algorithm is so fast that I managed to get 60 FPS on my custom 3D Object Rasteriser rendering a cube at 200x200 with the
DrawTriangleXY()
function!
If you would like to see all the new features, then I recommend checking the API for this module
Small Optimisation Update - v2.5.1
This is a small update which heavily improves the performance of GetPixel()
and GetPixelXY()
functions.
The CanvasPixels
property has also been removed as it is not that useful and has been replaced by the other pixel fetch methods
Hi there, um the image import just sometimes fails to import images, i noticed that when you try to import multiple frames, it will error on frames that are dark.
Okay so, i tried importing an animation that has multiple fade in and fade out effects. Then i tried to import, only to go through some errors. I realized that the module will struggle agaisnt frames that have a dark lighting or are completely black.
Oh really? Thats odd. Do you mind giving the png images that causes the error? I will fix the issues asap
lemme find a way to send you the folder, it has 300 pngs to upload, this one is prone tto the same error.
alright this link will lead you to a website called WeTransfer, it will allow u to download all of the png files:
I have made a temporary fix. There for some reason appears to be something wrong with the actual pixel data in the PNG file.
You should be able to import the images now though without any issues. If something does happen with other PNG images, please let me know.
Also, I have actually released a small secret update to the CanvasDraw module which heavily optimises the DrawImage()
and DrawImageXY()
function. Now your videos should be able to run much better at higher resolutions.
TIP: For maximum performance, use DrawImageXY for each frame in your video/GIF
Enjoy!
A nice crispy 30 FPS at 256x157
Could actually get a much higher framerate if i had something better than Boatbomber’s GreedyCanvas module to draw the pixels
Hi, I have a question about your 3D render engine. I’ve watched the youtube video that you have linked and I got to the end of the tutorial. The cube does show up on the CanvasDraw screen but the cube is squashed. I’m not sure if you actually based your 3D render engine code on the code of the video that you linked but if you did then maybe you know what I did wrong. Here’s my code and explorer:
--!strict
local ScreenWidth : number = 256
local ScreenHeight : number = 240 --// In tutorial 240
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
local Screen = script.Parent
local CanvasFrame = Screen.CanvasFrame
local CanvasDraw = require(Screen.CanvasDraw)
local VectorModule = require(Screen.VectorModule)
local RunService = game:GetService("RunService")
type vec3d = {["X"] : number, ["Y"] : number, ["Z"] : number, ["Magnitude"] : number}
type pArray = {[number] : vec3d}
type triangle = {["p"] : pArray}
type triangleArray = {[number?] : triangle}
type mesh = {["tris"] : triangleArray}
type matRow = {[number] : number}
type mat4x4 = {[number] : matRow}
--// Construct
local function Construct_vec3d(...) : vec3d
if #{...} == 0 then return VectorModule.zero end
return VectorModule.new(unpack{...})
end
local function Construct_triangle(...) : triangle
local Params = {...}
if #Params == 0 then return {p = {Construct_vec3d(), Construct_vec3d(), Construct_vec3d()}} end
return {p = {Params[1] or Construct_vec3d(), Params[2] or Construct_vec3d(), Params[3] or Construct_vec3d()}}
end
local function Construct_mesh(...) : mesh
local Params = {...}
if #Params == 0 then return {tris = {}} end
return {tris = Params}
end
local function Construct_mat4x4(x : number?) : mat4x4
--// x is a default
local d = 0
if type(x) == "number" then d = x end
local NewMatrix = {
{d, d, d, d};
{d, d, d, d};
{d, d, d, d};
{d, d, d, d};
}
return NewMatrix
end
--// Methods
local function MultiplyMatrixVector(i : vec3d, m : mat4x4) : vec3d
local o : vec3d = Construct_vec3d()
o.X = i.X * m[1][1] + i.Y * m[2][1] + i.Z * m[3][1] + m[4][1]
o.Y = i.X * m[1][2] + i.Y * m[2][2] + i.Z * m[3][1] + m[4][2]
o.Z = i.X * m[1][3] + i.Y * m[2][3] + i.Z * m[3][3] + m[4][3]
local w : number = i.X * m[1][4] + i.Y * m[2][4] + i.Z * m[3][4] + m[4][4]
if w ~= 0 then
o.X /= w
o.Y /= w
o.Z /= w
end
return o
end
local function CopyTable(Target : any) : any
local Result : any = {}
for Key, Value in Target do
Result[Key] = Value
end
return Result
end
local meshCube = Construct_mesh()
local matProj : mat4x4 = Construct_mat4x4()
local function Initialize() : nil --// main
local Resolution = Vector2.new(ScreenWidth, ScreenHeight)
CanvasDraw.CreateCanvas(CanvasFrame, Resolution, Color3.fromRGB(0,0,0), false)
meshCube.tris = {
--// South
Construct_triangle(Construct_vec3d(0, 0, 0), Construct_vec3d(0, 1, 0), Construct_vec3d(1, 1, 0));
Construct_triangle(Construct_vec3d(0, 0, 0), Construct_vec3d(1, 1, 0), Construct_vec3d(1, 0, 0));
--// East
Construct_triangle(Construct_vec3d(1, 0, 0), Construct_vec3d(1, 1, 0), Construct_vec3d(1, 1, 1));
Construct_triangle(Construct_vec3d(1, 0, 0), Construct_vec3d(1, 1, 1), Construct_vec3d(1, 0, 1));
--// North
Construct_triangle(Construct_vec3d(1, 0, 1), Construct_vec3d(1, 1, 1), Construct_vec3d(0, 1, 1));
Construct_triangle(Construct_vec3d(1, 0, 1), Construct_vec3d(0, 1, 1), Construct_vec3d(0, 0, 1));
--// West
Construct_triangle(Construct_vec3d(0, 0, 1), Construct_vec3d(0, 1, 1), Construct_vec3d(0, 1, 0));
Construct_triangle(Construct_vec3d(0, 0, 1), Construct_vec3d(0, 1, 0), Construct_vec3d(0, 0, 0));
--// Top
Construct_triangle(Construct_vec3d(0, 1, 0), Construct_vec3d(0, 1, 1), Construct_vec3d(1, 1, 1));
Construct_triangle(Construct_vec3d(0, 1, 0), Construct_vec3d(1, 1, 1), Construct_vec3d(1, 1, 0));
--// Bottom
Construct_triangle(Construct_vec3d(1, 0, 1), Construct_vec3d(0, 0, 1), Construct_vec3d(0, 0, 0));
Construct_triangle(Construct_vec3d(1, 0, 1), Construct_vec3d(0, 0, 0), Construct_vec3d(1, 0, 0));
}
return
end
--// OnUserCreate
Initialize()
local fNear = 0.1
local fFar = 1000
local fFov = 90
local fAspectRartio = ScreenHeight / ScreenWidth
local fFovRad = 1 / math.tan(math.rad(fFov * 0.5))
local fTheta = 0
matProj[1][1] = fAspectRartio * fFovRad
matProj[2][2] = fFovRad
matProj[3][3] = fFar / (fFar - fNear)
matProj[4][3] = (-fFar * fNear) / (fFar - fNear)
matProj[3][4] = 1
matProj[4][4] = 0
RunService.RenderStepped:Connect(function() --// OnUserUpdate
CanvasDraw.ClearCanvas()
local matRotZ : mat4x4, matRotX : mat4x4 = Construct_mat4x4(), Construct_mat4x4()
fTheta += 0.01
--// Rotation Z
matRotZ[1][1] = math.cos(fTheta)
matRotZ[1][2] = math.sin(fTheta)
matRotZ[2][1] = -math.sin(fTheta)
matRotZ[2][2] = math.cos(fTheta)
matRotZ[3][3] = 1
matRotZ[4][4] = 1
--// Rotation X
matRotX[1][1] = 1
matRotX[2][2] = math.cos(fTheta * 0.5)
matRotX[2][3] = math.sin(fTheta * 0.5)
matRotX[3][2] = -math.sin(fTheta * 0.5)
matRotX[3][3] = math.cos(fTheta * 0.5)
matRotX[4][4] = 1
--// Draw Triangles
for _, tri : triangle in meshCube.tris do
local triProjected : triangle = Construct_triangle()
local triRotatedZ : triangle = Construct_triangle()
local triRotatedZX : triangle = Construct_triangle()
triRotatedZ.p[1] = MultiplyMatrixVector(tri.p[1], matRotZ)
triRotatedZ.p[2] = MultiplyMatrixVector(tri.p[2], matRotZ)
triRotatedZ.p[3] = MultiplyMatrixVector(tri.p[3], matRotZ)
triRotatedZX.p[1] = MultiplyMatrixVector(triRotatedZ.p[1], matRotX)
triRotatedZX.p[2] = MultiplyMatrixVector(triRotatedZ.p[2], matRotX)
triRotatedZX.p[3] = MultiplyMatrixVector(triRotatedZ.p[3], matRotX)
local triTranslated : triangle = Construct_triangle(
Construct_vec3d(triRotatedZX.p[1].X, triRotatedZX.p[1].Y, triRotatedZX.p[1].Z),
Construct_vec3d(triRotatedZX.p[2].X, triRotatedZX.p[2].Y, triRotatedZX.p[2].Z),
Construct_vec3d(triRotatedZX.p[3].X, triRotatedZX.p[3].Y, triRotatedZX.p[3].Z)
)
triTranslated.p[1].Z = triRotatedZX.p[1].Z + 3
triTranslated.p[2].Z = triRotatedZX.p[2].Z + 3
triTranslated.p[3].Z = triRotatedZX.p[3].Z + 3
triProjected.p[1] = MultiplyMatrixVector(triTranslated.p[1], matProj)
triProjected.p[2] = MultiplyMatrixVector(triTranslated.p[2], matProj)
triProjected.p[3] = MultiplyMatrixVector(triTranslated.p[3], matProj)
--// Scale into view
triProjected.p[1].X += 1; triProjected.p[1].Y += 1
triProjected.p[2].X += 1; triProjected.p[2].Y += 1
triProjected.p[3].X += 1; triProjected.p[3].Y += 1
triProjected.p[1].X *= 0.5 * ScreenWidth; triProjected.p[1].Y *= 0.5 * ScreenHeight
triProjected.p[2].X *= 0.5 * ScreenWidth; triProjected.p[2].Y *= 0.5 * ScreenHeight
triProjected.p[3].X *= 0.5 * ScreenWidth; triProjected.p[3].Y *= 0.5 * ScreenHeight
CanvasDraw.DrawTriangle(Vector2.new(triProjected.p[1].X , triProjected.p[1].Y ), -- You have to shift everything by 1 on both axes because the canvas ...
-- actually starts on 1, 1 and not 0, 0 :(
Vector2.new(triProjected.p[2].X , triProjected.p[2].Y ),
Vector2.new(triProjected.p[3].X , triProjected.p[3].Y ),
Color3.fromRGB(255,255,255), false
)
end
end)
Beautiful video of a squashed cube:
Yeah the issue isn’t related to CanvasDraw itself. But judging by your code and the video, it seems mostly fine, all though I think there might be something wrong with your projection or matrix translations, because it only squashes when it rotates a certain amount.
Check your translations and maybe double check with the video (I had to rewatch the tutorial a good 4 times before I made my 3D rasteriser).
If you have any more questions, please do ask. I am more than happy to help!
I think I found the issue. One of the triangles (the first bottom triangle) actually has a Y position of 1 and that’s obviously wrong. I must have copied the values over incorrectly. Ok so after fixing it the cube has lost it’s height. This is so annoying to deal with.