Need some help with my 3D renderer. Triangle overlap. Triangle not render if point not onscreen. Transparent triangles partially overlap

I have decided to try to make 3D renderer on roblox. It goes somewhat well - I made ZBuffer, triangle rendering, but I have got this problems:

  1. If 1 point of triangle is invisible - entire triangle will be invisible.
    image
    image

  2. If object is transparent, some triangle pixels will overlap.
    image

  3. Sometimes. pixels from 1 object will be rendered ontop of another one, incorrectly. Transparency is not a thing here.
    image
    image

Can anyone tell me, how I can fix this issues? I will accept ideas too.

CODE PART:
Renderer

local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local RunService = game:GetService("RunService")

local Camera = workspace.CurrentCamera
local Scene = workspace.Scene

local Modules = {
	Canvas = require(script.Canvas),
	Objects = require(script.ObjectsData),
	ZBuffer = require(script.ZBuffer),
}

local ScreenSize = Vector2.new(130, 100)
local Canvas = Modules.Canvas(ScreenSize)
Canvas.Gui.Parent = PlayerGui

local ZBuffer

local ScreenDistance = 0.001
local ObserveRange = 70*2
local Scale = ScreenSize.X / (2 * ScreenDistance * math.tan(ObserveRange / 2))
local function Vector3OnScreen(Position)
	local Relative = Camera.CFrame:Inverse() * Position
	Relative = Vector3.new(Relative.X, Relative.Y, -Relative.Z)
	--print(Relative)
	--[[if Relative.Z < ScreenDistance then
		return nil
	end]]
	local Delta = ScreenDistance / Relative.Z * Scale
	--print(Delta)
	local Projection = Vector2.new(Relative.X, Relative.Y) * Delta
	local Screen = Projection + Vector2.new(ScreenSize.X / 2, -ScreenSize.Y / 2)
	local ScreenCoords = Vector2.new(math.floor(Screen.X+0.5), math.floor(-Screen.Y+0.5))
	--if ScreenCoords.X >= 0 and ScreenCoords.X < ScreenSize.X and ScreenCoords.Y >= 0 and ScreenCoords.Y < ScreenSize.Y then
		return ScreenCoords, Relative.Z
	--end
	--return nil
end

local function DrawLine(Start, End)
	local x1 = math.floor(Start.X)
	local x2 = math.floor(End.X)
	if (x1 > x2) then
		x1, x2 = x2, x1
		Start, End = End, Start
	end
	local d = (End.Y - Start.Y) / (x2 - x1)
	local y = Start.Y
	for i = x1, x2, 1 do
		local pixelY = math.floor(y)
		Canvas:SetPixelSilent(Vector2.new(i, pixelY), 255, 0, 0)
		y += d
	end
end

local function DrawTriangle(Point1, Point2, Point3, R, G, B, A)
	if Point1.X < 0 or Point1.X > ScreenSize.X-1 or Point1.Y < 0 or Point1.Y > ScreenSize.Y-1 then
		return
	end
	if Point2.X < 0 or Point2.X > ScreenSize.X-1 or Point2.Y < 0 or Point2.Y > ScreenSize.Y-1 then
		return
	end
	if Point3.X < 0 or Point3.X > ScreenSize.X-1 or Point3.Y < 0 or Point3.Y > ScreenSize.Y-1 then
		return
	end
	if (Point1.X > Point2.X) then
		Point1, Point2 = Point2, Point1
	end
	if (Point2.X > Point3.X) then
		Point2, Point3 = Point3, Point2
		if (Point1.X > Point2.X) then
			Point1, Point2 = Point2, Point1
		end
	end
	--print(Point1.X, Point2.X, Point3.X)
	local steps12 = math.max(Point2.X-Point1.X, 1)
	local steps13 = math.max(Point3.X-Point1.X, 1)
	local steps32 = math.max(Point3.X-Point2.X, 1)
	local steps31 = math.max(Point3.X-Point1.X, 1)
	

	local upDelta = (Point2.Y - Point1.Y) / steps12
	local downDelta = (Point3.Y - Point1.Y) / steps13
	
	if upDelta < downDelta then
		upDelta, downDelta = downDelta, upDelta
	end
	local Top, Bottom = math.max(Point1.Y, Point2.Y, Point3.Y), math.min(Point1.Y, Point2.Y, Point3.Y)
	local up = Point1.Y
	local down = Point1.Y

	local y23 = Point2.Y-Point3.Y
	local y31 = Point3.Y-Point1.Y
	local y12 = Point1.Y-Point2.Y
	
	local Volume = Point1.X*y23+Point2.X*y31+Point3.X*y12

	for i = math.floor(Point1.X), math.floor(Point2.X), 1 do
		for g = math.floor(down), math.floor(up), 1 do
			local y14 = Point1.Y-g
			local y24 = Point2.Y-g
			local y34 = Point3.Y-g

			local Volume1 = i*y23+Point2.X*y34+Point3.X*-y24
			local Volume2 = Point1.X*-y34+i*y31+Point3.X*y14
			local Volume3 = Point1.X*y24+Point2.X*-y14+i*y12

			local Weight1, Weight2, Weight3 = Volume1/Volume, Volume2/Volume, Volume3/Volume
			local TotalZ = Point1.Z*Weight1+Point2.Z*Weight2+Point3.Z*Weight3

			ZBuffer:Add(Vector2.new(i, g), R, G, B, A, TotalZ)
		end
		up += upDelta
		down += downDelta
	end

	upDelta = (Point3.Y - Point2.Y) / steps32
	downDelta = (Point3.Y - Point1.Y) / steps31
	if upDelta < downDelta then
		upDelta, downDelta = downDelta, upDelta
	end

	up = Point3.Y
	down = Point3.Y
	
	for i = math.floor(Point3.X), math.floor(Point2.X), -1 do
		for g = math.floor(down), math.floor(up), -1 do
			local y14 = Point1.Y-g
			local y24 = Point2.Y-g
			local y34 = Point3.Y-g

			local Volume1 = i*y23+Point2.X*y34+Point3.X*-y24
			local Volume2 = Point1.X*-y34+i*y31+Point3.X*y14
			local Volume3 = Point1.X*y24+Point2.X*-y14+i*y12

			local Weight1, Weight2, Weight3 = Volume1/Volume, Volume2/Volume, Volume3/Volume
			local TotalZ = Point1.Z*Weight1+Point2.Z*Weight2+Point3.Z*Weight3
			--local R, G, B = Volume1/Volume*255, Volume2/Volume*255, Volume3/Volume*255

			ZBuffer:Add(Vector2.new(i, g), R, G, B, A, TotalZ)
			--print(i, g)
			--Canvas:SetPixel(Vector2.new(i, g), R, G, B)
		end
		up -= upDelta
		down -= downDelta
	end
end

RunService.RenderStepped:Connect(function(Delta)
	ZBuffer = Modules.ZBuffer(ScreenSize)
	Canvas:Clear(0, 0, 0)
	for _, Object in pairs(Scene:GetChildren()) do
		local ObjectData = Modules.Objects.GetObjectData(Object)
		local ScreenPoints = {}
		for i = 1, #ObjectData.Vertex, 1 do
			local ScreenPos, Depth = Vector3OnScreen(ObjectData.Vertex[i])
			if ScreenPos then
				ScreenPoints[i] = Vector3.new(math.floor(ScreenPos.X), math.floor(ScreenPos.Y), Depth)
			end
		end
		for i = 1, #ObjectData.Faces/3, 1 do
			local p1, p2, p3 = ObjectData.Faces[i*3-2], ObjectData.Faces[i*3-1], ObjectData.Faces[i*3]
			if ScreenPoints[p1] and ScreenPoints[p2] and ScreenPoints[p3] then
				DrawTriangle(ScreenPoints[p1], ScreenPoints[p2], ScreenPoints[p3], Object.Color.R*255, Object.Color.G*255, Object.Color.B*255, Object.Transparency)
			end
			--[[if ScreenPoints[p1] and ScreenPoints[p2] then
				DrawLine(ScreenPoints[p1], ScreenPoints[p2])
			end
			if ScreenPoints[p1] and ScreenPoints[p3] then
				DrawLine(ScreenPoints[p1], ScreenPoints[p3])
			end
			if ScreenPoints[p2] and ScreenPoints[p3] then
				DrawLine(ScreenPoints[p2], ScreenPoints[p3])
			end]]
		end
	end
	ZBuffer:Sort()
	ZBuffer:Calculate()
	local PixelData = buffer.create(ScreenSize.X * ScreenSize.Y*3)
	local Buffer = ZBuffer.Buffer
	for x = 0, ScreenSize.X-1, 1 do
		for y = 0, ScreenSize.Y-1, 1 do
			local Cursor = (x+y*ScreenSize.X)*3
			buffer.writeu8(PixelData, Cursor, math.clamp(Buffer[x][y][1], 0, 255))
			buffer.writeu8(PixelData, Cursor+1, math.clamp(Buffer[x][y][2], 0, 255))
			buffer.writeu8(PixelData, Cursor+2, math.clamp(Buffer[x][y][3], 0, 255))
		end
	end
	Canvas:DrawPixels(Vector2.zero, ScreenSize, PixelData)
	Canvas:RedrawCanvas()
end)

ZBuffer

local Module = {}
local ModuleMeta = {}
ModuleMeta.__index = ModuleMeta

function Module.Create(Size)
	local self = {
		Size = Size,
		Buffer = {}
	}
	for x = 0, Size.X-1, 1 do
		self.Buffer[x] = {}
		for y = 0, Size.Y-1, 1 do
			self.Buffer[x][y] = {}
		end
	end
	return setmetatable(self, ModuleMeta)
end

function ModuleMeta:Add(Point, R, G, B, A, Z)
	table.insert(self.Buffer[Point.X][Point.Y], {R, G, B, A, Z})
end

local function Compare(a, b)
	return a[5] < b[5]
end

function ModuleMeta:Sort()
	for x = 0, self.Size.X-1, 1 do
		for y = 0, self.Size.Y-1, 1 do
			table.sort(self.Buffer[x][y], Compare)
			local This = self.Buffer[x][y]
			for i = #This, 2, -1 do
				local Diff = This[i][5] - This[i-1][5]
				if Diff < 0.0001 and Diff > -0.0001 then
					table.remove(This, i)
				end
			end
		end
	end
end

function ModuleMeta:Calculate()
	for x = 0, self.Size.X-1, 1 do
		for y = 0, self.Size.Y-1, 1 do
			local Pixel = self.Buffer[x][y]
			local StartIndex = #Pixel
			local StackedA = 1
			if StartIndex > 0 then
				for i = 1, #Pixel, 1 do
					StackedA *= Pixel[i][4]
					if StackedA <= 0.01 then
						StartIndex = i
						break
					end
				end
			end
			if StartIndex > 0 then
				local R, G, B = 0, 0, 0
				for i = StartIndex, 1, -1 do
					local ThisPixel = Pixel[i]
					--print(ThisPixel)
					local NA = 1 - ThisPixel[4]
					R = R * ThisPixel[4] + ThisPixel[1] * NA
					G = G * ThisPixel[4] + ThisPixel[2] * NA
					B = B * ThisPixel[4] + ThisPixel[3] * NA
				end
				--R, G, B = math.clamp(R, 0, 255), math.clamp(G, 0, 255), math.clamp(B, 0, 255)
				self.Buffer[x][y] = {R, G, B, 0, 65535}
			else
				self.Buffer[x][y] = {0, 0, 0, 0, 65535}
			end
		end
	end
end

return Module.Create

Canvas is simply Frames with UIGradients (Cuz roblox has decided to not unleash power of Editables to not ID verified persons)