You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Switched FDynamicBVH to use greedy insertion because branch and bound perf significantly degrades with heavily overlapped leaves. Added closest point queries using branch and bound. FBounds is now templated as TBounds. #rb graham.wihlidal #robomerge FNNC #preflight 6216dbf9104496cff8abfc36 [CL 19107993 by Brian Karis in ue5-main branch]
164 lines
5.1 KiB
C++
164 lines
5.1 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ImposterAtlas.h"
|
|
#include "Rasterizer.h"
|
|
#include "Cluster.h"
|
|
|
|
inline FVector3f OctahedronToUnitVector( const FVector2D& Oct )
|
|
{
|
|
FVector3f N( Oct.X, Oct.Y, 1.0f - FMath::Abs( Oct.X ) - FMath::Abs( Oct.Y ) );
|
|
float t = FMath::Max( -N.Z, 0.0f );
|
|
N.X += N.X >= 0.0f ? -t : t;
|
|
N.Y += N.Y >= 0.0f ? -t : t;
|
|
return N.GetUnsafeNormal();
|
|
}
|
|
|
|
namespace Nanite
|
|
{
|
|
|
|
FImposterAtlas::FImposterAtlas( TArray< uint16 >& InPixels, const FBounds3f& Bounds )
|
|
: Pixels( InPixels )
|
|
{
|
|
BoundsCenter = 0.5f * ( Bounds.Max + Bounds.Min );
|
|
BoundsExtent = 0.5f * ( Bounds.Max - Bounds.Min );
|
|
|
|
Pixels.AddZeroed( FMath::Square( AtlasSize * TileSize ) );
|
|
}
|
|
|
|
FMatrix44f FImposterAtlas::GetLocalToImposter( const FIntPoint& TilePos ) const
|
|
{
|
|
FVector2D Oct = ( FVector2D( TilePos ) + 0.5f ) / AtlasSize * 2.0f - 1.0f;
|
|
|
|
FVector3f ImposterZ = OctahedronToUnitVector( Oct );
|
|
|
|
#if 0
|
|
// [Frisvad 2012, "Building an Orthonormal Basis from a 3D Unit Vector Without Normalization"]
|
|
// Invalid for ImposterZ.z == -1
|
|
float A = 1.0f / ( 1.0f + ImposterZ.Z );
|
|
float B = -ImposterZ.X * ImposterZ.Y * A;
|
|
FVector3f ImposterX( 1.0f - FMath::Square( ImposterZ.X ) * A, B, -ImposterZ.X );
|
|
FVector3f ImposterY( B, 1.0f - FMath::Square( ImposterZ.Y ) * A, -ImposterZ.Y );
|
|
#else
|
|
FVector3f ImposterX( 0.0f, 0.0f, 1.0f );
|
|
ImposterX -= ImposterZ.Z * ImposterZ;
|
|
ImposterX.Normalize();
|
|
FVector3f ImposterY = ImposterZ ^ ImposterX;
|
|
#endif
|
|
|
|
FVector3f ImposterExtent(
|
|
BoundsExtent | ImposterX.GetAbs(),
|
|
BoundsExtent | ImposterY.GetAbs(),
|
|
BoundsExtent | ImposterZ.GetAbs() );
|
|
|
|
ImposterExtent = FVector3f::Max(ImposterExtent, FVector3f(0.001f)); // Prevent division by zero
|
|
|
|
FMatrix44f LocalToImposter = FMatrix44f(
|
|
ImposterX,
|
|
ImposterY,
|
|
ImposterZ,
|
|
FVector3f::ZeroVector ).GetTransposed();
|
|
|
|
return FTranslationMatrix44f( -BoundsCenter ) * LocalToImposter * FScaleMatrix44f( FVector3f::OneVector / ImposterExtent );
|
|
}
|
|
|
|
void FImposterAtlas::Rasterize( const FIntPoint& TilePos, const FCluster& Cluster, uint32 ClusterIndex )
|
|
{
|
|
constexpr uint32 ViewSize = TileSize;// * SuperSample;
|
|
|
|
FIntRect Scissor( 0, 0, ViewSize, ViewSize );
|
|
|
|
FMatrix44f LocalToImposter = GetLocalToImposter( TilePos );
|
|
|
|
TArray< FVector3f, TInlineAllocator<128> > Positions;
|
|
Positions.SetNum( Cluster.NumVerts, false );
|
|
|
|
for( uint32 VertIndex = 0; VertIndex < Cluster.NumVerts; VertIndex++ )
|
|
{
|
|
FVector3f Position = Cluster.GetPosition( VertIndex );
|
|
//checkSlow( FBox( BoundsCenter - BoundsExtent, BoundsCenter + BoundsExtent ).ExpandBy( KINDA_SMALL_NUMBER ).IsInside( Position ) );
|
|
|
|
Position = LocalToImposter.TransformPosition( Position );
|
|
//checkSlow( Position.GetAbsMax() < 1.0001f );
|
|
|
|
// TODO Bake into matrix
|
|
Positions[ VertIndex ].X = ( Position.X * 0.5f + 0.5f ) * ViewSize;
|
|
Positions[ VertIndex ].Y = ( Position.Y * 0.5f + 0.5f ) * ViewSize;
|
|
Positions[ VertIndex ].Z = ( Position.Z * 0.5f + 0.5f ) * 254.0f + 1.0f; // zero is reserved as masked
|
|
}
|
|
|
|
for( uint32 TriIndex = 0; TriIndex < Cluster.NumTris; TriIndex++ )
|
|
{
|
|
FVector3f Verts[3];
|
|
Verts[0] = Positions[ Cluster.Indexes[ TriIndex * 3 + 0 ] ];
|
|
Verts[1] = Positions[ Cluster.Indexes[ TriIndex * 3 + 1 ] ];
|
|
Verts[2] = Positions[ Cluster.Indexes[ TriIndex * 3 + 2 ] ];
|
|
|
|
RasterizeTri( Verts, Scissor, 0,
|
|
[&]( int32 x, int32 y, float z )
|
|
{
|
|
uint32 Depth = FMath::RoundToInt( FMath::Clamp( z, 1.0f, 255.0f ) );
|
|
uint16 PixelValue = ( Depth << 8 ) | ( ClusterIndex << 7 ) | TriIndex;
|
|
//uint32 PixelIndex = x + y * ViewSize;
|
|
uint32 PixelIndex = x + ( y + ( TilePos.X + TilePos.Y * AtlasSize ) * TileSize ) * TileSize;
|
|
Pixels[ PixelIndex ] = FMath::Max( Pixels[ PixelIndex ], PixelValue );
|
|
} );
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void FImposterAtlas::DownSample( const FIntPoint& TilePos, TArray< uint16 >& Atlas ) const
|
|
{
|
|
constexpr uint32 ViewSize = TileSize * SuperSample;
|
|
|
|
for( int32 y = 0; y < TileSize; y++ )
|
|
{
|
|
for( int32 x = 0; x < TileSize; x++ )
|
|
{
|
|
TArray< uint8, TFixedAllocator< SuperSample * SuperSample > > UniqueTris;
|
|
uint8 Counts[ SuperSample * SuperSample ] = {};
|
|
|
|
uint32 SumDepth = 0;
|
|
uint32 SumCount = 0;
|
|
for( int32 sy = 0; sy < SuperSample; sy++ )
|
|
{
|
|
for( int32 sx = 0; sx < SuperSample; sx++ )
|
|
{
|
|
uint32 PixelIndex = ( sx + x * SuperSample ) + ( sy + y * SuperSample ) * ViewSize;
|
|
uint32 PixelValue = Pixels[ PixelIndex ];
|
|
uint32 TriIndex = PixelValue & 0xff;
|
|
uint32 Depth = PixelValue >> 8;
|
|
|
|
if( Depth )
|
|
{
|
|
Counts[ UniqueTris.AddUnique( TriIndex ) ]++;
|
|
SumDepth += Depth;
|
|
SumCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint16 PixelValue = 0;
|
|
if( SumCount >= SuperSample * SuperSample / 2 )
|
|
{
|
|
uint32 Depth = FMath::Clamp( ( SumDepth + (SumCount >> 1) ) / SumCount, 1u, 255u );
|
|
uint32 TriIndex = 0;
|
|
uint32 MaxCount = 0;
|
|
|
|
for( int i = 0; i < UniqueTris.Num(); i++ )
|
|
{
|
|
if( Counts[i] > MaxCount )
|
|
TriIndex = UniqueTris[i];
|
|
}
|
|
|
|
PixelValue = ( Depth << 8 ) | TriIndex;
|
|
}
|
|
|
|
uint32 AtlasIndex = x + ( y + ( TilePos.X + TilePos.Y * AtlasSize ) * TileSize ) * TileSize;
|
|
Atlas[ AtlasIndex ] = PixelValue;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} // namespace Nanite
|