Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Last active November 16, 2015 08:15
Show Gist options
  • Save dermotbalson/69b25e4e00a105ca46f9 to your computer and use it in GitHub Desktop.
Save dermotbalson/69b25e4e00a105ca46f9 to your computer and use it in GitHub Desktop.
Frustum test
function setup()
FOV=45
perspective(FOV)
PM1=1/projectionMatrix()[1]
ortho()
pos=vec2(100,100) --circle position
camPos=vec2(WIDTH/2,0) --fixed camera
camDir=vec2(0.25,1):normalize() --camera direction
far=700
fructum=mesh()
local w=far*PM1*vec2(-camDir.y,camDir.x)
fructum.vertices={camPos,camPos+far*camDir-w,camPos+far*camDir+w}
fructum:setColors(color(136, 168, 199, 255))
--radius=50 --collision circle radius
print("Fructum is in blue, pointing up")
print("True tangent is in pink")
print("Fake tangent is in green")
print("Use your finger to drag the circle around")
print("The circle goes bright yellow when it enters the frustum")
parameter.integer("radius",10,100,50)
end
function draw()
background(150)
fructum:draw()
pushStyle()
stroke(99, 124, 183, 255)
strokeWidth(2)
line(camPos.x,camPos.y,camPos.x+far*camDir.x,camPos.y+far*camDir.y)
popStyle()
DrawCircle()
end
function DrawCircle()
local tangent=GetTangent(pos,radius,camPos,camDir)
--calculate fake tangent
local fake=pos+camDir*radius*2.6
pushStyle()
if IsVisible(pos,camPos,camDir,radius,far) then fill(255,255,0) else fill(255,255,0,100) end
ellipse(pos.x,pos.y,radius*2)
stroke(195, 72, 169, 255) strokeWidth(2)
line(camPos.x,camPos.y,tangent.x,tangent.y)
stroke(52, 162, 48, 255)
line(camPos.x,camPos.y,fake.x,fake.y)
--ellipse(tangent.x,tangent.y,10)
popStyle()
end
function GetTangent(centre,radius,camPos,camDir)
--calculate offset from centre
local s=(centre.x-camPos.x)/(-centre.y+camPos.y)
local a=(radius/math.sqrt(1+s*s))*vec2(1,s)
--now figure out which side of the circle is closest to the camera direction
--this formula tells which side of a line, a point is on
local d=camPos+camDir*1000
local e=(centre.x-camPos.x)*(d.y-camPos.y)-(centre.y-camPos.y)*(d.x-camPos.x)
if e>0 then return centre-a else return centre+a end --adjust the centre by the offset
end
function touched(t)
pos=vec2(t.x,t.y)
end
function IsVisible(pos,camPos,camDir,radius,far)
local px,py,pcx,pcy,pdx,pdy,fx,fy=pos.x,pos.y,camPos.x,camPos.y,camDir.x,camDir.y
--get tangent point
local u=radius*2.6
local tx,ty=px+pdx*u,py+pdy*u --tangent point
--which side of LOS is our circle centre
local dx,dy=pcx+pdx*1000,pcy+pdy*1000
local IsOnLeft=(px-pcx)*(dy-pcy)-(py-pcy)*(dx-pcx)<0
local wx,wy=-far*PM1*pdy,far*PM1*pdx
if IsOnLeft then
fx,fy=pcx+pdx*far+wx,pcy+pdy*far+wy --far left of frustum
return (tx-pcx)*(fy-pcy)-(ty-pcy)*(fx-pcx)>0
else
fx,fy=pcx+pdx*far-wx,pcy+pdy*far-wy --far right of frustum
return (tx-pcx)*(fy-pcy)-(ty-pcy)*(fx-pcx)<0
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment