[bb] Ray Intersect Triangle Test by sswift [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:39

Previous topic - Next topic

BlitzBot

Title : Ray Intersect Triangle Test
Author : sswift
Posted : 1+ years ago

Description : This function is very useful and important for 3D programmers to have.  

It allows you to specify an infinite line in 3D (a ray) and a triangle, and determine if the line interesects the triangle.

As an added bonus, the intersection test this function performs also calculates the UV coordinates of the intersection point.   That means that if you have a texture tiled across the triangle once, you can determine which texel of the texture you hit.

The function does not return the U and V values by default.  You will have to modify it to do that if you need those values.

The original C source code to this function is located here:
<a href="http://www.acm.org/jgt/papers/MollerTrumbore97/code.html" target="_blank">http://www.acm.org/jgt/papers/MollerTrumbore97/code.html</a>

This code has a slightly diffrent inner structure... there's a second set of code for if you want the function to do a backface check and report no collision if the polygon is facing away from the point specified on the line.  You should be able to add that functionality yourself with access to both these code snippets if you need it.

You can also modify the function to return a value T with the U and V values.  This T value can be used with the U and V values to find the point in world space where the collision occured.  This itself is very useful.  Unfortunately I don't know the math involved in making that conversion at this time.

The code also has another use.  It demonstrates how to do cross and dot products on vectors.  These are two very important equations used in a lot of 3D math.  I won't go into a big explanation for what they do or how they work... because I honestly don't even remember myself.  But if you come across an equation ont he net that requires one, well, there's how to do it!


Code :
Code (blitzbasic) Select
; -------------------------------------------------------------------------------------------------------------------
; This function returns TRUE if a ray intersects a triangle.
;
; It also calculates the UV coordinates of said colision as part of the intersection test,
; but does not return them.
;
; V0xyz, V1xyz, and V2xyz are the locations of the three vertices of the triangle.
;
; V0 is location of UV(0,0).  V1 is the location of UV(1, 0).  V2 is the location of UV(0,1)
; These are important to know if you want to return the exact location in texture space of the collision, but
; you don't have to worry about them if you only want to find out if a collision occured.
;
; Pxyz is a point on the line.
;
; Dxyz is a vector providing the slope of the line.
; -------------------------------------------------------------------------------------------------------------------
Function Ray_Intersect_Triangle(Px#, Py#, Pz#, Dx#, Dy#, Dz#, V0x#, V0y#, V0z#, V1x#, V1y#, V1z#, V2x#, V2y#, V2z#)


; A couple definitions for vector operations:

;crossproduct(a,b,c) =
;ax = (by * cz) - (cy * bz)
;ay = (bz * cx) - (cz * bx)
;az = (bx * cy) - (cx * by)

;dotproduct(v,q) = (vx * qx) + (vy * qy) + (vz * qz)


; vector(e1,v1,v0)
E1x# = V1x# - V0x#
E1y# = V1y# - V0y#
E1z# = V1z# - V0z#


; vector(e2,v2,v0)
E2x# = V2x# - V0x#
E2y# = V2y# - V0y#
E2z# = V2z# - V0z#


; crossproduct(h,d,e2)
Hx# = (Dy# * E2z#) - (E2y# * Dz#)
Hy# = (Dz# * E2x#) - (E2z# * Dx#)
Hz# = (Dx# * E2y#) - (E2x# * Dy#)


; a = dotproduct(e1,h)
A# = (E1x# * Hx#) + (E1y# * Hy#) + (E1z# * Hz#)


; If the ray is parallel to the plane then it does not intersect it.
If (A# > -0.00001) And (A# < 0.00001)
Return False
EndIf


F# = 1.0 / A#


; vector(s,p,v0)
Sx# = Px# - V0x#
Sy# = Py# - V0y#
Sz# = Pz# - V0z#


;u = f * (dotProduct(s,h))
U# = F# * ((Sx# * Hx#) + (Sy# * Hy#) + (Sz# * Hz#))


; If the value of the U coordinate is outside the range of values inside the triangle,
; then the ray has intersected the plane outside the triangle.
If (U# < 0.0) Or (U# > 1.0)
Return False
EndIf


; crossProduct(q,s,e1)
Qx# = (Sy# * E1z#) - (E1y# * Sz#)
Qy# = (Sz# * E1x#) - (E1z# * Sx#)
Qz# = (Sx# * E1y#) - (E1x# * Sy#)


; v = f * dotProduct(d,q)
V# = F# * ((Dx# * Qx#) + (Dy# * Qy#) + (Dz# * Qz#))


; If the value of the V coordinate is outside the range of values inside the triangle,
; then the ray has intersected the plane outside the triangle.
;
; U + V cannot exceed 1.0 or the point is not in the triangle.
;
; If you imagine the triangle as half a square this makes sense.  U=1 V=1 would be  in the
; lower left hand corner which would be in the second triangle making up the square.
If (V# < 0.0) Or ((U# + V#) > 1.0)
Return(False)
EndIf


; The point was in the triangle.  Yay!
Return True


; Note that you could also return the U and V coordinates calculated from this function
; if you need those values!


End Function


Comments : none...