Reputation: 643
Given two vectors A and B which form the line segment L = A-B. Furthermore given a view frustum F which is defined by its left, right, bottom, top, near and far planes.
How do I clip L against F?
That is, test for an intersection and where on L that intersection occurs? (Keep in mind that a line segment can have more than one intersection with the frustum if it intersects two sides at a corner.)
If possible, provide a code example please (C++ or Python preferred).
Upvotes: 5
Views: 4845
Reputation: 48058
First extract the planes from your view matrix.
Then use your points to define a vector and min/max as (0, 1), then iterate over the planes and intersect them with the segment, updating the min/max, bailing out early if the min > max
.
Here's an example of a pure Python function, no external deps.
def clip_segment_v3_plane_n(p1, p2, planes):
"""
- p1, p2: pair of 3d vectors defining a line segment.
- planes: a sequence of (4 floats): `(x, y, z, d)`.
Returns 2 vector triplets (the clipped segment)
or (None, None) then segment is entirely outside.
"""
dp = sub_v3v3(p2, p1)
p1_fac = 0.0
p2_fac = 1.0
for p in planes:
div = dot_v3v3(p, dp)
if div != 0.0:
t = -plane_point_side_v3(p, p1)
if div > 0.0: # clip p1 lower bounds
if t >= div:
return None, None
if t > 0.0:
fac = (t / div)
if fac > p1_fac:
p1_fac = fac
if p1_fac > p2_fac:
return None, None
elif div < 0.0: # clip p2 upper bounds
if t > 0.0:
return None, None
if t > div:
fac = (t / div)
if fac < p2_fac:
p2_fac = fac
if p1_fac > p2_fac:
return None, None
p1_clip = add_v3v3(p1, mul_v3_fl(dp, p1_fac))
p2_clip = add_v3v3(p1, mul_v3_fl(dp, p2_fac))
return p1_clip, p2_clip
# inline math library
def add_v3v3(v0, v1):
return (
v0[0] + v1[0],
v0[1] + v1[1],
v0[2] + v1[2],
)
def sub_v3v3(v0, v1):
return (
v0[0] - v1[0],
v0[1] - v1[1],
v0[2] - v1[2],
)
def dot_v3v3(v0, v1):
return (
(v0[0] * v1[0]) +
(v0[1] * v1[1]) +
(v0[2] * v1[2])
)
def mul_v3_fl(v0, f):
return (
v0[0] * f,
v0[1] * f,
v0[2] * f,
)
def plane_point_side_v3(p, v):
return dot_v3v3(p, v) + p[3]
Upvotes: 1
Reputation: 2378
Adding to what Corporal Touchy said above, you'll need to know how to intersect a line segment with a plane. In the description on that page, u represents the parameter in the parametric definition of your line. First, calculate u using one of the 2 methods described. If the value of u falls in the range of 0.0 to 1.0, then the plane clips the line somewhere on your segment. Plugging u back into your line equation gives you the point where that intersection occurs.
Another approach is to find the directed distance of each point to a plane. If the distance of one point is positive and the other is negative, then they lie on opposite sides of the plane. You then know which point is outside your frustum (based on which way your plane normal points). Using this approach, finding the intersection point can be done faster by doing a linear interpolation based on the ratio of the directed distances. E.g. if the distance of one point is +12 and the other is -12, you know the plane cuts the segment in half, and your u parameter is 0.5.
Hope this helps.
Upvotes: 0
Reputation: 6972
I don't want to get into writing code for this now but if I understand "frustum" correctly the following should work.
But I may have completely misunderstood. In that case please elaborate :)
Upvotes: 4