A triangle raycast callback used by the Bullet collision code. It tests a ray from m_from to m_to against a single triangle, performs plane intersection and inside-triangle checks, applies backface filtering and calls ReportHit when an intersection is found.
/* * C# / XNA port of Bullet (c) 2011 Mark Neale <[email protected]> * * Bullet Continuous Collision Detection and Physics Library * Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/ * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ // Adapted from BulletXNA 73b2e1b9: namespace isolation, no XNA rendering, one type per file. #nullable disable #pragma warning disable CS1591, CS0168, CS0219, CS0414, CS0660, CS0661, CS0659, CS0693, CS8981, CS0108, CS0114 using System; using HumanoidRetargeter.Core.Formats.Mmd.Bullet.LinearMath; namespace HumanoidRetargeter.Core.Formats.Mmd.Bullet.BulletCollision; internal abstract class TriangleRaycastCallback : ITriangleCallback { public TriangleRaycastCallback() { } // for pool public TriangleRaycastCallback(ref IndexedVector3 from, ref IndexedVector3 to, EFlags flags) { m_from = from; m_to = to; m_flags = flags; m_hitFraction = 1f; } public virtual void Initialize(ref IndexedVector3 from, ref IndexedVector3 to, EFlags flags) { m_from = from; m_to = to; m_flags = flags; m_hitFraction = 1f; } public virtual bool graphics() { return false; } public virtual void ProcessTriangle(IndexedVector3[] triangle, int partId, int triangleIndex) { IndexedVector3 v10 = triangle[1] - triangle[0]; IndexedVector3 v20 = triangle[2] - triangle[0]; IndexedVector3 triangleNormal = v10.Cross(ref v20); float dist = IndexedVector3.Dot(ref triangle[0], ref triangleNormal); float dist_a = IndexedVector3.Dot(ref triangleNormal, ref m_from); dist_a -= dist; float dist_b = IndexedVector3.Dot(ref triangleNormal, ref m_to); dist_b -= dist; if (dist_a * dist_b >= 0f) { return; // same sign } //@BP Mod - Backface filtering if (((m_flags & EFlags.kF_FilterBackfaces) != 0) && (dist_a > 0f)) { // Backface, skip check return; } float proj_length = dist_a - dist_b; float distance = (dist_a) / (proj_length); // Now we have the intersection point on the plane, we'll see if it's inside the triangle // Add an epsilon as a tolerance for the raycast, // in case the ray hits exacly on the edge of the triangle. // It must be scaled for the triangle size. if (distance < m_hitFraction) { float edge_tolerance = triangleNormal.LengthSquared(); edge_tolerance *= -0.0001f; IndexedVector3 point; point = MathUtil.Interpolate3(ref m_from, ref m_to, distance); { IndexedVector3 v0p = triangle[0] - point; IndexedVector3 v1p = triangle[1] - point; IndexedVector3 cp0 = v0p.Cross(ref v1p); if (IndexedVector3.Dot(ref cp0, ref triangleNormal) >= edge_tolerance) { IndexedVector3 v2p = triangle[2] - point; IndexedVector3 cp1 = v1p.Cross(ref v2p); //= IndexedVector3.Cross(v1p,v2p); if (IndexedVector3.Dot(ref cp1, ref triangleNormal) >= edge_tolerance) { IndexedVector3 cp2 = v2p.Cross(ref v0p); if (IndexedVector3.Dot(ref cp2, ref triangleNormal) >= edge_tolerance) { //@BP Mod // Triangle normal isn't normalized triangleNormal.Normalize(); //@BP Mod - Allow for unflipped normal when raycasting against backfaces if (((m_flags & EFlags.kF_KeepUnflippedNormal) == 0) && (dist_a <= 0.0f)) { IndexedVector3 negNormal = -triangleNormal; m_hitFraction = ReportHit(ref negNormal, distance, partId, triangleIndex); } else { m_hitFraction = ReportHit(ref triangleNormal, distance, partId, triangleIndex); } } } } } } } public abstract float ReportHit(ref IndexedVector3 hitNormalLocal, float hitFraction, int partId, int triangleIndex); public virtual void Cleanup() { } public IndexedVector3 m_from; public IndexedVector3 m_to; public EFlags m_flags; public float m_hitFraction; }