I’m trying to make textures work in my recent raycaster. i have access to each pixel’s ray hit position as well as each vertex position of the triangle with their UV coordinates. i honestly have no idea how to fix it
Could you provide more info, like some code please
--!optimize 2
--!native
local event = script.Event
local gui = game.Players.LocalPlayer.PlayerGui.ScreenGui
local VERTS = {
Vector3.new(0,0,0),
Vector3.new(10,0,10),
Vector3.new(0,0,10),
Vector3.new(10,0,0),
}
local UVs = {
Vector2.new(0,0),
Vector2.new(1,1),
Vector2.new(0,1),
Vector2.new(1,0),
}
local img = {
{Color3.new(1, 1, 1),Color3.new(1, 1, 0),Color3.new(0.333333, 1, 1),Color3.new(0.333333, 0.333333, 0)},
{Color3.new(0.333333, 1, 0),Color3.new(0.333333, 0.666667, 1),Color3.new(1, 0, 0),Color3.new(0, 0, 0.498039)},
{Color3.new(1, 0.333333, 1),Color3.new(0.333333, 0.333333, 1),Color3.new(0.333333, 1, 1),Color3.new(0.333333, 0, 0.498039)},
{Color3.new(0, 1, 0),Color3.new(1, 1, 0),Color3.new(0.333333, 1, 1),Color3.new(0.333333, 0.333333, 0)},
}
local ycount = #img-1
local xcount = #img[1]-1
local light = Vector3.new(24, 24.5, -16)
local tris = {
{1,3,2},
{1,2,4},
}
local sz = Vector2.new(80,50)
function lerpTime(a,b,c)
return (c - a) * (b - a) or 0
end
function lerp(a,b,t)
return a + (b-a)*t
end
local function RayTri(origin, direction, Tri)
local vertice1, vertice2, vertice3 = VERTS[Tri[1]], VERTS[Tri[2]], VERTS[Tri[3]]
local uv1, uv2, uv3 = UVs[Tri[1]], UVs[Tri[2]], UVs[Tri[3]]
--local triobg = {
-- VERTS[Tri[1]],
-- VERTS[Tri[2]],
-- VERTS[Tri[3]],
--}
--local hi = {}
local edgeAB = vertice2 - vertice1
local edgeAC = vertice3 - vertice1
local ao = origin - vertice1
local dao = ao:Cross(direction)
local normal = edgeAB:Cross(edgeAC)
local det = -direction:Dot(normal)
local invDet = 1 / det
local dst = ao:Dot(normal) * invDet
local u = edgeAC:Dot(dao) * invDet
local v = -edgeAB:Dot(dao) * invDet
local w = 1 - u - v
--hi.didHit = det >= 1e-6 and dst >= 0 and u >= 0 and v >= 0 and w >= 0
--hi.point = origin+direction*dst
--hi.normal = (vertice1.Unit * w + vertice2 * u + vertice3 * v)
--hi.dst = dst
--local li = (normal:Dot(light)+1)/2
--local indexed = Tri[4]
--hi.r = indexed.R * li
--hi.g = indexed.G * li
--hi.b = indexed.B * li
--return hi
local li = (normal:Dot(light)+1)/2
--local indexed = Tri[4]
local pos = origin+direction*dst
--local r = indexed.R * li
--local g = indexed.G * li
--local b = indexed.B * li
--return det >= 1e-6 and dst >= 0 and u >= 0 and v >= 0 and w >= 0, r, g, b, dst
local sc = workspace.CurrentCamera.ViewportSize
local minY,maxY = 0,0
local minX,maxX = 0,0
local c = Vector2.zero
c = workspace.CurrentCamera:WorldToViewportPoint(pos)
local v1 = workspace.CurrentCamera:WorldToViewportPoint(vertice1)
local v2 = workspace.CurrentCamera:WorldToViewportPoint(vertice2)
local v3 = workspace.CurrentCamera:WorldToViewportPoint(vertice3)
local hit = det >= 1e-6 and dst >= 0 and u >= 0 and v >= 0 and w >= 0
minY,maxY = math.min(v1.Y,v2.Y,v3.Y),math.max(v1.Y,v2.Y,v3.Y)
minX,maxX = math.min(v1.X,v2.X,v3.X),math.max(v1.X,v2.X,v3.X)
local miuvX,mauvX = math.min(uv1.X,uv2.X,uv3.X), math.max(uv1.X,uv2.X,uv3.X)
local miuvY,mauvY = math.min(uv1.Y,uv2.Y,uv3.Y), math.max(uv1.Y,uv2.Y,uv3.Y)
local cordX = hit and lerp(miuvX,mauvX,(c.X-minX)/(maxX-minX))*4+1 or 0
local cordY = hit and lerp(miuvY,mauvY,(c.Y-minY)/(maxY-minY))*4+1 or 0
return hit, (cordX-1)/4, (cordY-1)/4, 0 * li, dst, pos
end
local function rayCollision(ray)
local mindidHit = false
local mindst = 9999999999999
local minr
local ming
local minb
local minpos
local origin, direction = ray.Origin, ray.Direction
for _, v in tris do
local hit, r,g,b, dst, pos = RayTri(origin, direction, v)
if hit and mindst > dst then
mindidHit = hit
minr, ming, minb = r, g, b
minpos = pos
end
end
return mindidHit, minr, ming, minb, minpos
end
local camera = workspace.CurrentCamera
local func = camera.ViewportPointToRay
local function vptr(...)
return func(camera, ...)
end
local cache = {}
return function(script : Script)
local actor = script.Parent :: Actor
local si, ei = 0, 0
actor:BindToMessage("cache", function(newCache, newsi, newei)
cache = newCache
si = newsi
ei = newei
end)
local function render(clock)
for i = si,ei,1 do
local pixelIndex = (i - si) * 4
local x = buffer.readu16(cache, pixelIndex)
local y = buffer.readu16(cache, pixelIndex + (2))
local hit, r,g,b, pos = rayCollision(vptr(x,y,0))
if hit then
event:Fire(pixelIndex/4 + si,r,g,b, clock)
else
event:Fire(pixelIndex/4 +si, nil, nil, nil, clock)
end
end
end
actor:BindToMessage("render", render)
actor:BindToMessageParallel("render_parallel", render)
end
this code runs in the actors that calculate the pixel color. the actual calculation happens in the RayTri function
Interesting you’re trying to make a raycaster in lua…
I have no answer besides looking up how to make your own rendering program (C and C++ have great tutorials on it). I will recommend though to simplify it more, though. If you’re trying to render a triangle with a gradient, but you can’t even render a filled-in gradient, have 3 lines instead that make up the outline of the triangle. It’s easier, since you can just make each line have a gradient to eachother. Then from there, you can try to mathematically fill in the area for the triangle.
If you need inspiration, SDL and OpenGL are rendering libraries. Since they deal with everything about rendering, they have an incredible amount of stuff, so it’d probably be hard to find how to render a triangle, but poking around in there can help you learn about more stuff