module Graphics.LambdaCube.Frustum where
import Data.List (foldl')
import Graphics.LambdaCube.Types
data Plane
= Plane
{ plNormal :: Vec3
, plDist :: FloatType
}
newtype Frustum
= Frustum
{ frPlanes :: [Plane]
}
pointInFrustum :: Vec3 -> Frustum -> Bool
pointInFrustum p fr = foldl' (\b (Plane n d) -> b && d + n &. p >= 0) True $ frPlanes fr
sphereInFrustum :: Vec3 -> FloatType -> Frustum -> Bool
sphereInFrustum p r fr = all (\(Plane n d) -> d + n &. p >= (r)) (frPlanes fr)
boxInFrustum ::Vec3 -> Vec3 -> Frustum -> Bool
boxInFrustum pp pn fr = foldl' (\b (Plane n d) -> b && d + n &. (g pp pn n) >= 0) True $ frPlanes fr
where
g (Vec3 px py pz) (Vec3 nx ny nz) n = Vec3 (fx px nx) (fy py ny) (fz pz nz)
where
[fx,fy,fz] = map (\a -> if a > 0 then max else min) $ destructVec3 [n]
frustum :: FloatType -> FloatType -> FloatType -> FloatType -> Vec3 -> Vec3 -> Vec3 -> Frustum
frustum angle ratio nearD farD p l u = Frustum [pl ntr ntl ftl, pl nbl nbr fbr, pl ntl nbl fbl,
pl nbr ntr fbr, pl ntl ntr nbr, pl ftr ftl fbl]
where
pl a b c = Plane n d
where
n = normalize $ (c &- b) &^ (a &- b)
d = (n &. b)
ang2rad = pi / 180
tang = tan $ angle * ang2rad * 0.5
nh = nearD * tang
nw = nh * ratio
fh = farD * tang
fw = fh * ratio
z = normalize $ p &- l
x = normalize $ u &^ z
y = z &^ x
nc = p &- nearD *& z
fc = p &- farD *& z
ntl = nc &+ nh *& y &- nw *& x
ntr = nc &+ nh *& y &+ nw *& x
nbl = nc &- nh *& y &- nw *& x
nbr = nc &- nh *& y &+ nw *& x
ftl = fc &+ fh *& y &- fw *& x
ftr = fc &+ fh *& y &+ fw *& x
fbl = fc &- fh *& y &- fw *& x
fbr = fc &- fh *& y &+ fw *& x
frustumFromMatrix :: Mat4 -> Frustum
frustumFromMatrix m = Frustum [pl plLeftN plLeftD, pl plRightN plRightD, pl plTopN plTopD, pl plBottomN plBottomD, pl plNearN plNearD, pl plFarN plFarD]
where
Mat4 (Vec4 m00 m01 m02 m03) (Vec4 m10 m11 m12 m13) (Vec4 m20 m21 m22 m23) (Vec4 m30 m31 m32 m33) = transpose m
pl n d = Plane (normalize n) (d / norm n)
plLeftN = Vec3 (m30+m00) (m31+m01) (m32+m02)
plLeftD = (m33+m03)
plRightN = Vec3 (m30m00) (m31m01) (m32m02)
plRightD = (m33m03)
plTopN = Vec3 (m30m10) (m31m11) (m32m12)
plTopD = (m33m13)
plBottomN = Vec3 (m30+m10) (m31+m11) (m32+m12)
plBottomD = (m33+m13)
plNearN = Vec3 (m30+m20) (m31+m21) (m32+m22)
plNearD = (m33+m23)
plFarN = Vec3 (m30m20) (m31m21) (m32m22)
plFarD = (m33m23)