// Copyright (c) Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Math/Vector3.h" #include "Engine/Core/Math/Transform.h" #include "Engine/Core/Math/Ray.h" #include "Engine/Core/Math/CollisionsHelper.h" #include "Engine/Core/Math/Half.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Graphics/PixelFormat.h" /// /// Helper container used for detailed triangle mesh intersections tests. /// class FLAXENGINE_API CollisionProxy { public: struct CollisionTriangle { Float3 V0, V1, V2; }; /// /// The triangles. /// Array Triangles; public: FORCE_INLINE bool HasData() const { return Triangles.HasItems(); } template void Init(uint32 vertices, uint32 triangles, const Float3* positions, const IndexType* indices, uint32 positionsStride = sizeof(Float3), PixelFormat positionsFormat = PixelFormat::R32G32B32_Float) { Triangles.Clear(); Triangles.EnsureCapacity(triangles, false); const IndexType* it = indices; #define LOOP_BEGIN() \ for (uint32 i = 0; i < triangles; i++) \ { \ const IndexType i0 = *(it++); \ const IndexType i1 = *(it++); \ const IndexType i2 = *(it++); \ if (i0 < vertices && i1 < vertices && i2 < vertices) \ { #define LOOP_END() } } if (positionsFormat == PixelFormat::R32G32B32_Float) { LOOP_BEGIN() #define GET_POS(idx) *(const Float3*)((const byte*)positions + positionsStride * idx) Triangles.Add({ GET_POS(i0), GET_POS(i1), GET_POS(i2) }); #undef GET_POS LOOP_END() } else if (positionsFormat == PixelFormat::R16G16B16A16_Float) { LOOP_BEGIN() #define GET_POS(idx) ((const Half4*)((const byte*)positions + positionsStride * idx))->ToFloat3() Triangles.Add({ GET_POS(i0), GET_POS(i1), GET_POS(i2) }); #undef GET_POS LOOP_END() } #undef LOOP_BEGIN #undef LOOP_END } void Clear() { Triangles.Clear(); } bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const { distance = MAX_Real; for (int32 i = 0; i < Triangles.Count(); i++) { CollisionTriangle triangle = Triangles[i]; Float3::Transform(triangle.V0, world, triangle.V0); Float3::Transform(triangle.V1, world, triangle.V1); Float3::Transform(triangle.V2, world, triangle.V2); // TODO: use 32-bit precision for intersection Real d; if (CollisionsHelper::RayIntersectsTriangle(ray, triangle.V0, triangle.V1, triangle.V2, d) && d < distance) { normal = Vector3::Normalize((triangle.V1 - triangle.V0) ^ (triangle.V2 - triangle.V0)); distance = d; } } return distance < MAX_Real; } bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const { distance = MAX_Real; for (int32 i = 0; i < Triangles.Count(); i++) { CollisionTriangle triangle = Triangles[i]; Vector3 v0, v1, v2; transform.LocalToWorld(triangle.V0, v0); transform.LocalToWorld(triangle.V1, v1); transform.LocalToWorld(triangle.V2, v2); // TODO: use 32-bit precision for intersection Real d; if (CollisionsHelper::RayIntersectsTriangle(ray, v0, v1, v2, d) && d < distance) { normal = Vector3::Normalize((v1 - v0) ^ (v2 - v0)); distance = d; } } return distance < MAX_Real; } };