ue4.26 CurveLinearColorAtlas支持非正方形尺寸
默认CurveAtlas只能是正方形

改代码可以让它支持非正方形:

改法如下:
CurveLinearColorAtlas.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Object.h"
#include "Engine/EngineTypes.h"
#include "Engine/Texture.h"
#include "Engine/World.h"
#include "Engine/Texture2D.h"
#include "CurveLinearColorAtlas.generated.h"
static FName NAME_GradientTexture = FName(TEXT("GradientTexture"));
static FName NAME_GradientBias = FName(TEXT("GradientBias"));
static FName NAME_GradientScale = FName(TEXT("GradientScale"));
static FName NAME_GradientCount = FName(TEXT("GradientCount"));
class UCurveLinearColor;
class UCurveBase;
/**
* Manages gradient LUT textures for registered actors and assigns them to the corresponding materials on the actor
*/
UCLASS()
class ENGINE_API UCurveLinearColorAtlas : public UTexture2D
{
GENERATED_UCLASS_BODY()
#if WITH_EDITOR
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
// How many slots are available per texture
FORCEINLINE uint32 MaxSlotsPerTexture()
{
return TextureSize;
}
// Immediately render a new material to the specified slot index(SlotIndex must be within this section's range)
void OnCurveUpdated(UCurveBase* Curve, EPropertyChangeType::Type ChangeType);
// Re-render all texture groups
void UpdateTextures();
#endif
virtual void PostLoad() override;
bool GetCurveIndex(UCurveLinearColor* InCurve, int32& Index);
UFUNCTION(BlueprintCallable, Category = "Math|Curves")
bool GetCurvePosition(UCurveLinearColor* InCurve, float& Position);
#if WITH_EDITORONLY_DATA
UPROPERTY()
uint32 bIsDirty : 1;
uint32 bHasAnyDirtyTextures : 1;
uint32 bShowDebugColorsForNullGradients : 1; // Renders alternate blue/yellow lines for empty gradients. Good for debugging, but turns off optimization for selective updates to gradients.
TArray<FFloat16Color> SrcData;
#endif
UPROPERTY(EditAnywhere, Category = "Curves")
uint32 TextureSize; // Size of the lookup textures
//yang chao begin
UPROPERTY(EditAnywhere, Category = "Curves")
uint32 TextureSizeX;
//yang chao end
UPROPERTY(EditAnywhere, Category = "Curves")
TArray<UCurveLinearColor*> GradientCurves;
protected:
#if WITH_EDITORONLY_DATA
FVector2D SizeXY;
#endif
};
CurveLinearColorAtlas.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
UCurveLinearColorAtlas.cpp
=============================================================================*/
#include "Curves/CurveLinearColorAtlas.h"
#include "Curves/CurveLinearColor.h"
#include "Components/MeshComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
UCurveLinearColorAtlas::UCurveLinearColorAtlas(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
TextureSize = 256;
TextureSizeX = 256;//yang chao
#if WITH_EDITORONLY_DATA
bHasAnyDirtyTextures = false;
bShowDebugColorsForNullGradients = false;
SizeXY = { (float)TextureSizeX, 1.0f };//yang chao modify TextueSize to TextureSizeX
MipGenSettings = TMGS_NoMipmaps;
#endif
Filter = TextureFilter::TF_Bilinear;
SRGB = false;
AddressX = TA_Clamp;
AddressY = TA_Clamp;
CompressionSettings = TC_HDR;
}
#if WITH_EDITOR
void UCurveLinearColorAtlas::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
// Determine whether any property that requires recompression of the texture, or notification to Materials has changed.
bool bRequiresNotifyMaterials = false;
if (PropertyChangedEvent.Property != nullptr)
{
const FName PropertyName(PropertyChangedEvent.Property->GetFName());
// if Resizing
if (PropertyName == GET_MEMBER_NAME_CHECKED(UCurveLinearColorAtlas, TextureSize)
|| PropertyName == GET_MEMBER_NAME_CHECKED(UCurveLinearColorAtlas, TextureSizeX)//yang chao
)
{
if ((uint32)GradientCurves.Num() > TextureSize)
{
int32 OldCurveCount = GradientCurves.Num();
GradientCurves.RemoveAt(TextureSize, OldCurveCount - TextureSize);
}
Source.Init(TextureSizeX, TextureSize, 1, 1, TSF_RGBA16F);//yang chao modify TextueSize to TextureSizeX
SizeXY = { (float)TextureSizeX, 1.0f };//yang chao modify TextueSize to TextureSizeX
UpdateTextures();
bRequiresNotifyMaterials = true;
}
if (PropertyName == GET_MEMBER_NAME_CHECKED(UCurveLinearColorAtlas, GradientCurves))
{
if ((uint32)GradientCurves.Num() > TextureSize)
{
int32 OldCurveCount = GradientCurves.Num();
GradientCurves.RemoveAt(TextureSize, OldCurveCount - TextureSize);
}
else
{
for (int32 i = 0; i < GradientCurves.Num(); ++i)
{
if (GradientCurves[i] != nullptr)
{
GradientCurves[i]->OnUpdateCurve.AddUObject(this, &UCurveLinearColorAtlas::OnCurveUpdated);
}
}
UpdateTextures();
bRequiresNotifyMaterials = true;
}
}
}
// Notify any loaded material instances if changed our compression format
if (bRequiresNotifyMaterials)
{
NotifyMaterials();
}
}
#endif
void UCurveLinearColorAtlas::PostLoad()
{
#if WITH_EDITOR
if (FApp::CanEverRender())
{
FinishCachePlatformData();
}
for (int32 i = 0; i < GradientCurves.Num(); ++i)
{
if (GradientCurves[i] != nullptr)
{
GradientCurves[i]->OnUpdateCurve.AddUObject(this, &UCurveLinearColorAtlas::OnCurveUpdated);
}
}
Source.Init(TextureSizeX, TextureSize, 1, 1, TSF_RGBA16F);//yang chao modify TextueSize to TextureSizeX
SizeXY = { (float)TextureSizeX, 1.0f };//yang chao modify TextueSize to TextureSizeX
UpdateTextures();
#endif
Super::PostLoad();
}
#if WITH_EDITOR
static void RenderGradient(TArray<FFloat16Color>& InSrcData, UObject* Gradient, int32 StartXY, FVector2D SizeXY)
{
if (Gradient == nullptr)
{
int32 Start = StartXY;
for (uint32 y = 0; y < SizeXY.Y; y++)
{
// Create base mip for the texture we created.
for (uint32 x = 0; x < SizeXY.X; x++)
{
InSrcData[Start + x + y * SizeXY.X] = FLinearColor::White;
}
}
}
else if (Gradient->IsA(UCurveLinearColor::StaticClass()))
{
// Render a gradient
UCurveLinearColor* GradientCurve = CastChecked<UCurveLinearColor>(Gradient);
GradientCurve->PushToSourceData(InSrcData, StartXY, SizeXY);
}
}
static void UpdateTexture(UCurveLinearColorAtlas& Atlas)
{
const int32 TextureDataSize = Atlas.Source.CalcMipSize(0);
FGuid MD5Guid;
FMD5 MD5;
MD5.Update(reinterpret_cast<const uint8*>(Atlas.SrcData.GetData()), TextureDataSize);
MD5.Final(reinterpret_cast<uint8*>(&MD5Guid));
uint32* TextureData = reinterpret_cast<uint32*>(Atlas.Source.LockMip(0));
FMemory::Memcpy(TextureData, Atlas.SrcData.GetData(), TextureDataSize);
Atlas.Source.UnlockMip(0);
Atlas.Source.SetId(MD5Guid, /*bInGuidIsHash*/ true);
Atlas.UpdateResource();
}
// Immediately render a new material to the specified slot index (SlotIndex must be within this section's range)
void UCurveLinearColorAtlas::OnCurveUpdated(UCurveBase* Curve, EPropertyChangeType::Type ChangeType)
{
if (ChangeType != EPropertyChangeType::Interactive)
{
UCurveLinearColor* Gradient = CastChecked<UCurveLinearColor>(Curve);
int32 SlotIndex = GradientCurves.Find(Gradient);
if (SlotIndex != INDEX_NONE && (uint32)SlotIndex < MaxSlotsPerTexture())
{
// Determine the position of the gradient
int32 StartXY = SlotIndex * TextureSize;
// Render the single gradient to the render target
RenderGradient(SrcData, Gradient, StartXY, SizeXY);
UpdateTexture(*this);
}
}
}
// Render any textures
void UCurveLinearColorAtlas::UpdateTextures()
{
// Save off the data needed to render each gradient.
// Callback into the section owner to get the Gradients array
const int32 TextureDataSize = Source.CalcMipSize(0);
SrcData.Empty();
SrcData.AddUninitialized(TextureDataSize);
int32 NumSlotsToRender = FMath::Min(GradientCurves.Num(), (int32)MaxSlotsPerTexture());
for (int32 i = 0; i < NumSlotsToRender; ++i)
{
if (GradientCurves[i] != nullptr)
{
int32 StartXY = i * TextureSizeX;//yang chao modify TextueSize to TextureSizeX
RenderGradient(SrcData, GradientCurves[i], StartXY, SizeXY);
}
}
for (uint32 y = 0; y < TextureSizeX; y++)//yang chao modify TextueSize to TextureSizeX
{
// Create base mip for the texture we created.
for (uint32 x = GradientCurves.Num(); x < TextureSize; x++)
{
SrcData[x*TextureSizeX + y] = FLinearColor::White;//yang chao modify TextueSize to TextureSizeX
}
}
UpdateTexture(*this);
bIsDirty = false;
}
#endif
bool UCurveLinearColorAtlas::GetCurveIndex(UCurveLinearColor* InCurve, int32& Index)
{
Index = GradientCurves.Find(InCurve);
if (Index != INDEX_NONE)
{
return true;
}
return false;
}
bool UCurveLinearColorAtlas::GetCurvePosition(UCurveLinearColor* InCurve, float& Position)
{
int32 Index = GradientCurves.Find(InCurve);
Position = 0.0f;
if (Index != INDEX_NONE)
{
Position = (float)Index;
return true;
}
return false;
}
--补充:
看了下ue5.0的文档,已经支持非正方形了:(面板上有squre resolution勾选,下面有texture height)
Curve Atlases in Unreal Engine Materials | Unreal Engine 5.0 Documentation


浙公网安备 33010602011771号