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