140 lines
3.0 KiB
C++
140 lines
3.0 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Engine/Texture.h"
|
|
|
|
|
|
namespace Nanite
|
|
{
|
|
|
|
class FDisplacementMap
|
|
{
|
|
public:
|
|
ETextureSourceFormat SourceFormat;
|
|
|
|
int32 BytesPerPixel;
|
|
int32 SizeX;
|
|
int32 SizeY;
|
|
uint32 NumLevels;
|
|
|
|
float Magnitude;
|
|
float Center;
|
|
|
|
TextureAddress AddressX;
|
|
TextureAddress AddressY;
|
|
|
|
public:
|
|
NANITEUTILITIES_API FDisplacementMap();
|
|
NANITEUTILITIES_API FDisplacementMap( struct FImage&& TextureSourceImage, float InMagnitude, float InCenter, TextureAddress InAddressX, TextureAddress InAddressY );
|
|
|
|
// Bilinear filtered
|
|
NANITEUTILITIES_API float Sample( FVector2f UV ) const;
|
|
NANITEUTILITIES_API FVector2f Sample( FVector2f MinUV, FVector2f MaxUV ) const;
|
|
|
|
float Sample( int32 x, int32 y ) const;
|
|
FVector2f Sample( int32 x, int32 y, uint32 Level ) const;
|
|
|
|
float Load( int32 x, int32 y ) const;
|
|
FVector2f Load( int32 x, int32 y, uint32 Level ) const;
|
|
|
|
private:
|
|
TArray64< uint8 > SourceData;
|
|
TArray< FVector2f > MipData[12];
|
|
|
|
void Address( int32& x, int32& y ) const;
|
|
};
|
|
|
|
|
|
FORCEINLINE float FDisplacementMap::Sample( int32 x, int32 y ) const
|
|
{
|
|
Address(x,y);
|
|
|
|
float Displacement = Load(x,y);
|
|
Displacement -= Center;
|
|
Displacement *= Magnitude;
|
|
|
|
return Displacement;
|
|
}
|
|
|
|
FORCEINLINE FVector2f FDisplacementMap::Sample( int32 x, int32 y, uint32 Level ) const
|
|
{
|
|
Address(x,y);
|
|
|
|
x >>= Level;
|
|
y >>= Level;
|
|
|
|
FVector2f Displacement = Load( x, y, Level );
|
|
Displacement -= FVector2f( Center );
|
|
Displacement *= Magnitude;
|
|
|
|
return Displacement;
|
|
}
|
|
|
|
FORCEINLINE float FDisplacementMap::Load( int32 x, int32 y ) const
|
|
{
|
|
const uint8* PixelPtr = &SourceData[ int64( x + (int64)y * SizeX ) * BytesPerPixel ];
|
|
|
|
if( SourceFormat == TSF_BGRA8 )
|
|
{
|
|
return float( PixelPtr[2] ) / 255.0f;
|
|
}
|
|
else if( SourceFormat == TSF_RGBA16 )
|
|
{
|
|
checkSlow(BytesPerPixel == sizeof(uint16) * 4);
|
|
return float( *(uint16*)PixelPtr ) / 65535.0f;
|
|
}
|
|
else if( SourceFormat == TSF_RGBA16F || SourceFormat == TSF_R16F )
|
|
{
|
|
FFloat16 HalfValue = *(FFloat16*)PixelPtr;
|
|
return HalfValue;
|
|
}
|
|
else if( SourceFormat == TSF_G8 )
|
|
{
|
|
return float( PixelPtr[0] ) / 255.0f;
|
|
}
|
|
else if (SourceFormat == TSF_G16)
|
|
{
|
|
return float( *(uint16*)PixelPtr ) / 65535.0f;
|
|
}
|
|
else if( SourceFormat == TSF_RGBA32F || SourceFormat == TSF_R32F )
|
|
{
|
|
return *(float*)PixelPtr;
|
|
}
|
|
else
|
|
{
|
|
checkf( 0, TEXT("Displacement map format not supported") );
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
FORCEINLINE FVector2f FDisplacementMap::Load( int32 x, int32 y, uint32 Level ) const
|
|
{
|
|
checkSlow( Level > 0 );
|
|
|
|
uint32 MipSizeX = ( ( SizeX - 1 ) >> Level ) + 1;
|
|
uint32 MipSizeY = ( ( SizeY - 1 ) >> Level ) + 1;
|
|
|
|
return MipData[ Level - 1 ][ x + y * MipSizeX ];
|
|
}
|
|
|
|
FORCEINLINE void FDisplacementMap::Address( int32& x, int32& y ) const
|
|
{
|
|
if( AddressX == TA_Clamp )
|
|
x = FMath::Clamp( x, 0, SizeX - 1 );
|
|
else
|
|
{
|
|
x = x % SizeX;
|
|
x += x < 0 ? SizeX : 0;
|
|
}
|
|
|
|
if( AddressY == TA_Clamp )
|
|
y = FMath::Clamp( y, 0, SizeY - 1 );
|
|
else
|
|
{
|
|
y = y % SizeY;
|
|
y += y < 0 ? SizeY : 0;
|
|
}
|
|
}
|
|
|
|
} // namespace Nanite
|