// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MeshUtilities.h" #if USE_EMBREE #if USE_EMBREE_MAJOR_VERSION >= 4 #include #include #else #include #include #endif #else #define RTC_INVALID_GEOMETRY_ID ((unsigned int)-1) typedef void* RTCDevice; typedef void* RTCScene; typedef void* RTCGeometry; #endif class FSourceMeshDataForDerivedDataTask; struct FEmbreeTriangleDesc { int16 ElementIndex; bool IsTwoSided() const { // MaterialIndex on the build triangles was set to 1 if two-sided, or 0 if one-sided return ElementIndex == 1; } }; struct FEmbreeGeometryAsset { TArray IndexArray; TArray VertexArray; TArray TriangleDescs; // The material ID of each triangle. uint32 NumVertices; uint32 NumTriangles; uint32 SectionNumTwoSidedTriangles; uint32 SectionNumTriangles; RTCScene Scene = nullptr; }; struct FEmbreeGeometry { const FEmbreeGeometryAsset* Asset; uint32 GeometryId = RTC_INVALID_GEOMETRY_ID; }; class FEmbreeScene { public: const FEmbreeGeometryAsset* AddGeometryAsset( const FSourceMeshDataForDerivedDataTask* SourceMeshData, const FStaticMeshLODResources* LODModel, TConstArrayView SectionData, bool bIncludeTranslucentTriangles, bool bInstantiable); const FEmbreeGeometry* AddGeometry(const FEmbreeGeometryAsset* GeometryAsset); const FEmbreeGeometry* AddGeometryInstance(const FEmbreeGeometryAsset* GeometryAsset, const FMatrix44f& Transform); void Commit(); FString MeshName; bool bGenerateAsIfTwoSided = false; RTCDevice Device = nullptr; RTCScene Scene = nullptr; TIndirectArray GeometryAssets; TIndirectArray Geometries; int32 NumTrianglesTotal = 0; bool bMostlyTwoSided = false; }; #if USE_EMBREE struct FEmbreeRay : public RTCRayHit { FEmbreeRay() : ElementIndex(-1) { hit.u = hit.v = 0; ray.time = 0; ray.mask = 0xFFFFFFFF; hit.geomID = RTC_INVALID_GEOMETRY_ID; hit.instID[0] = RTC_INVALID_GEOMETRY_ID; hit.primID = RTC_INVALID_GEOMETRY_ID; } FVector3f GetHitNormal() const { return FVector3f(-hit.Ng_x, -hit.Ng_y, -hit.Ng_z).GetSafeNormal(); } bool IsHitTwoSided() const { // MaterialIndex on the build triangles was set to 1 if two-sided, or 0 if one-sided return ElementIndex == 1; } // Additional Outputs. int32 ElementIndex; // Material Index }; #if USE_EMBREE_MAJOR_VERSION >= 4 struct FEmbreeRayQueryContext : public RTCRayQueryContext { FEmbreeRayQueryContext() : ElementIndex(-1) {} #else struct FEmbreeIntersectionContext : public RTCIntersectContext { FEmbreeIntersectionContext() : ElementIndex(-1) {} #endif bool IsHitTwoSided() const { // MaterialIndex on the build triangles was set to 1 if two-sided, or 0 if one-sided return ElementIndex == 1; } // Hit against this primitive will be ignored int32 SkipPrimId = RTC_INVALID_GEOMETRY_ID; // Additional Outputs. int32 ElementIndex; // Material Index }; #endif namespace MeshRepresentation { /** * Generates unit length, stratified and uniformly distributed direction samples in a hemisphere. */ void GenerateStratifiedUniformHemisphereSamples(int32 NumSamples, FRandomStream& RandomStream, TArray& Samples); /** * [Frisvad 2012, "Building an Orthonormal Basis from a 3D Unit Vector Without Normalization"] */ FMatrix44f GetTangentBasisFrisvad(FVector3f TangentZ); void SetupEmbreeScene(FString MeshName, bool bGenerateAsIfTwoSided, FEmbreeScene& OutEmbreeScene); void DeleteEmbreeScene(FEmbreeScene& EmbreeScene); int64_t MemoryEstimateForEmbreeScene(uint64_t IndexCount); bool AddMeshDataToEmbreeScene(FEmbreeScene& EmbreeScene, const FMeshDataForDerivedDataTask& MeshData, bool bIncludeTranslucentTriangles); };