100 lines
2.8 KiB
C
100 lines
2.8 KiB
C
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
#pragma once
|
|
|
|
// "Fast, minimum storage ray-triangle intersection" Moller-Trumbore, 1997
|
|
bool RayTriangleIntersectionMollerTrumbore(float3 RayOrigin, float3 RayDirection, float3 Vertex0, float3 Vertex1, float3 Vertex2, out float IntersectionT, out float2 Barycentrics)
|
|
{
|
|
const float Epsilon = 1e-9;
|
|
|
|
const float3 E1 = Vertex1 - Vertex0;
|
|
const float3 E2 = Vertex2 - Vertex0;
|
|
const float3 P = cross(RayDirection, E2);
|
|
const float Det = dot(E1, P);
|
|
#if BACKFACE_CULLING
|
|
if (Det < Epsilon) return false;
|
|
#else
|
|
if (Det > -Epsilon && Det < Epsilon) return false;
|
|
#endif
|
|
const float InvDet = rcp(Det);
|
|
|
|
const float3 T = RayOrigin - Vertex0;
|
|
float U = dot(T, P) * InvDet;
|
|
if (U < 0 || U > 1) return false;
|
|
|
|
float3 Q = cross(T, E1);
|
|
float V = dot(RayDirection, Q) * InvDet;
|
|
if (V < 0 || U + V > 1) return false;
|
|
|
|
const float t = dot(E2, Q) * InvDet;
|
|
if (t <= 0) return false;
|
|
|
|
// In the original paper UV is from Vertex0 but we want UV to be from Vertex2 to match DXR.
|
|
Barycentrics = float2(1 - U - V, U);
|
|
IntersectionT = t;
|
|
|
|
return true;
|
|
}
|
|
|
|
// "Watertight Ray/Triangle Intersection" Woop, Benthin and Wald 2013
|
|
uint MaxDimension(float3 V)
|
|
{
|
|
return V.y > V.x ? (V.z > V.y ? 2 : 1) : (V.z > V.x ? 2 : 0);
|
|
}
|
|
|
|
bool RayTriangleIntersectionWatertight(float3 RayOrigin, float3 RayDirection, float3 Vertex0, float3 Vertex1, float3 Vertex2, out float IntersectionT, out float2 Barycentrics)
|
|
{
|
|
int kz = MaxDimension(abs(RayDirection));
|
|
int kx = kz + 1; if (kx == 3) kx = 0;
|
|
int ky = kx + 1; if (ky == 3) ky = 0;
|
|
|
|
if (RayDirection[kz] < 0.0f)
|
|
{
|
|
int temp = kx;
|
|
kx = ky;
|
|
ky = temp;
|
|
}
|
|
|
|
const float3 ShearConstant = float3(RayDirection[kx], RayDirection[ky], 1.0f) * rcp(RayDirection[kz]);
|
|
|
|
const float3 A = Vertex0 - RayOrigin;
|
|
const float3 B = Vertex1 - RayOrigin;
|
|
const float3 C = Vertex2 - RayOrigin;
|
|
|
|
const float Ax = A[kx] - ShearConstant.x * A[kz];
|
|
const float Ay = A[ky] - ShearConstant.y * A[kz];
|
|
const float Bx = B[kx] - ShearConstant.x * B[kz];
|
|
const float By = B[ky] - ShearConstant.y * B[kz];
|
|
const float Cx = C[kx] - ShearConstant.x * C[kz];
|
|
const float Cy = C[ky] - ShearConstant.y * C[kz];
|
|
|
|
float3 UVW;
|
|
UVW.x = Cx * By - Cy * Bx;
|
|
UVW.y = Ax * Cy - Ay * Cx;
|
|
UVW.z = Bx * Ay - By * Ax;
|
|
|
|
if (any(UVW == 0.0f))
|
|
{
|
|
// double precision
|
|
}
|
|
|
|
#if BACKFACE_CULLING
|
|
if (any(UVW < 0.0f)) return false;
|
|
#else
|
|
if (any(UVW < 0.0f) && any(UVW > 0.0f)) return false;
|
|
#endif
|
|
|
|
const float Det = dot(UVW, 1.0f);
|
|
if (Det == 0.0f) return false;
|
|
|
|
const float3 ScaledZ = ShearConstant.z * float3(A[kz], B[kz], C[kz]);
|
|
const float T = dot(UVW, ScaledZ);
|
|
|
|
if (Det < 0 && T >= 0) return false;
|
|
if (Det > 0 && T <= 0) return false;
|
|
|
|
const float InvDet = rcp(Det);
|
|
Barycentrics = UVW.xy * InvDet;
|
|
IntersectionT = T * InvDet;
|
|
|
|
return true;
|
|
} |