Files
UnrealEngineUWP/Engine/Source/Developer/NaniteUtilities/Private/DisplacementMap.cpp
julien stjean df881094e8 Fixed in a issue where the build a nanite displaced mesh might not use the displacement texture and then upload the wrong build data to the ddc.
Changed the nanite displaced meshes ddc key to get rid of the bad data sotred in the ddc.

#rb none
[FYI] Brian.Karis, Graham.Wihlidal
#preflight 641b881cec01de1664596786

[CL 24758139 by julien stjean in ue5-main branch]
2023-03-23 00:01:12 -04:00

160 lines
4.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DisplacementMap.h"
#include "ImageCore.h"
#include "ImageCoreUtils.h"
namespace Nanite
{
FDisplacementMap::FDisplacementMap()
: SourceFormat( TSF_G8 )
, BytesPerPixel(1)
, SizeX(1)
, SizeY(1)
, NumLevels(1)
, Magnitude( 0.0f )
, Center( 0.0f )
, AddressX( TA_Wrap )
, AddressY( TA_Wrap )
{
SourceData.Add(0);
}
FDisplacementMap::FDisplacementMap( FImage&& TextureSourceImage, float InMagnitude, float InCenter, TextureAddress InAddressX, TextureAddress InAddressY )
: NumLevels(1)
, Magnitude( InMagnitude )
, Center( InCenter )
, AddressX( InAddressX )
, AddressY( InAddressY )
{
SourceData = MoveTemp(TextureSourceImage.RawData);
check(!SourceData.IsEmpty());
SourceFormat = FImageCoreUtils::ConvertToTextureSourceFormat(TextureSourceImage.Format);
BytesPerPixel = ERawImageFormat::GetBytesPerPixel(TextureSourceImage.Format);
SizeX = TextureSourceImage.GetWidth();
SizeY = TextureSourceImage.GetHeight();
uint32 PrevSizeX = SizeX;
uint32 PrevSizeY = SizeY;
for( uint32 Level = 1; ; Level++ )
{
uint32 MipSizeX = ( ( SizeX - 1 ) >> Level ) + 1;
uint32 MipSizeY = ( ( SizeY - 1 ) >> Level ) + 1;
if( MipSizeX == 1 && MipSizeY == 1 )
break;
MipData[ Level - 1 ].AddUninitialized( MipSizeX * MipSizeY );
for( uint32 y = 0; y < MipSizeY; y++ )
{
for( uint32 x = 0; x < MipSizeX; x++ )
{
uint32 x0 = x*2;
uint32 y0 = y*2;
uint32 x1 = FMath::Min( x0 + 1, PrevSizeX - 1 );
uint32 y1 = FMath::Min( y0 + 1, PrevSizeY - 1 );
if( Level == 1 )
{
float d0 = Load( x0, y0 );
float d1 = Load( x1, y0 );
float d2 = Load( x0, y1 );
float d3 = Load( x1, y1 );
MipData[ Level - 1 ][ x + y * MipSizeX ] = FVector2f(
FMath::Min( d0, FMath::Min3( d1, d2, d3 ) ),
FMath::Max( d0, FMath::Max3( d1, d2, d3 ) ) );
}
else
{
FVector2f d0 = Load( x0, y0, Level - 1 );
FVector2f d1 = Load( x1, y0, Level - 1 );
FVector2f d2 = Load( x0, y1, Level - 1 );
FVector2f d3 = Load( x1, y1, Level - 1 );
MipData[ Level - 1 ][ x + y * MipSizeX ] = FVector2f(
FMath::Min( d0.X, FMath::Min3( d1.X, d2.X, d3.X ) ),
FMath::Max( d0.Y, FMath::Max3( d1.Y, d2.Y, d3.Y ) ) );
}
}
}
PrevSizeX = MipSizeX;
PrevSizeY = MipSizeY;
NumLevels++;
}
}
// Bilinear filtered
float FDisplacementMap::Sample( FVector2f UV ) const
{
// Half texel
UV.X = UV.X * SizeX - 0.5f;
UV.Y = UV.Y * SizeY - 0.5f;
int32 x0 = FMath::FloorToInt32( UV.X );
int32 y0 = FMath::FloorToInt32( UV.Y );
int32 x1 = x0 + 1;
int32 y1 = y0 + 1;
float wx1 = UV.X - x0;
float wy1 = UV.Y - y0;
float wx0 = 1.0f - wx1;
float wy0 = 1.0f - wy1;
return
Sample( x0, y0 ) * wx0 * wy0 +
Sample( x1, y0 ) * wx1 * wy0 +
Sample( x0, y1 ) * wx0 * wy1 +
Sample( x1, y1 ) * wx1 * wy1;
}
// Returns min/max over bilinear footprint
FVector2f FDisplacementMap::Sample( FVector2f MinUV, FVector2f MaxUV ) const
{
// Half texel
MinUV = MinUV * FVector2f( SizeX, SizeY ) - FVector2f( 0.5f );
MaxUV = MaxUV * FVector2f( SizeX, SizeY ) - FVector2f( 0.5f );
int32 x0 = FMath::FloorToInt32( MinUV.X );
int32 y0 = FMath::FloorToInt32( MinUV.Y );
int32 x1 = FMath::FloorToInt32( MaxUV.X ) + 1;
int32 y1 = FMath::FloorToInt32( MaxUV.Y ) + 1;
uint32 Level = FMath::FloorLog2( FMath::Max( x1 - x0, y1 - y0 ) );
if( (x1 >> Level) - (x0 >> Level) > 1 ||
(y1 >> Level) - (y0 >> Level) > 1 )
Level++;
Level = FMath::Min( Level, NumLevels - 1 );
if( Level == 0 )
{
float d0 = Sample( x0, y0 );
float d1 = Sample( x1, y0 );
float d2 = Sample( x0, y1 );
float d3 = Sample( x1, y1 );
return FVector2f(
FMath::Min( d0, FMath::Min3( d1, d2, d3 ) ),
FMath::Max( d0, FMath::Max3( d1, d2, d3 ) ) );
}
else
{
FVector2f d0 = Sample( x0, y0, Level );
FVector2f d1 = Sample( x1, y0, Level );
FVector2f d2 = Sample( x0, y1, Level );
FVector2f d3 = Sample( x1, y1, Level );
return FVector2f(
FMath::Min( d0.X, FMath::Min3( d1.X, d2.X, d3.X ) ),
FMath::Max( d0.Y, FMath::Max3( d1.Y, d2.Y, d3.Y ) ) );
}
}
} // namespace Nanite