UE4 Texture操作總結


項目中經常需要對texture進行讀寫操作,所以做個總結。

方法1:

  

DynamicTexture = UTexture2D::CreateTransient(SizeX, SizeY);
 
// Allocate the texture HRI
DynamicTexture->UpdateResource();
 
// Use this function to update the texture rects you want to change:
// NOTE: There is a method called UpdateTextureRegions in UTexture2D but it is compiled WITH_EDITOR and is not marked as ENGINE_API so it cannot be linked from plugins.
 
void UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData)
{
    if (Texture->Resource)
    {
        struct FUpdateTextureRegionsData
        {
            FTexture2DResource* Texture2DResource;
            int32 MipIndex;
            uint32 NumRegions;
            FUpdateTextureRegion2D* Regions;
            uint32 SrcPitch;
            uint32 SrcBpp;
            uint8* SrcData;
        };
 
        FUpdateTextureRegionsData* RegionData = new FUpdateTextureRegionsData;
 
        RegionData->Texture2DResource = (FTexture2DResource*)Texture->Resource;
        RegionData->MipIndex = MipIndex;
        RegionData->NumRegions = NumRegions;
        RegionData->Regions = Regions;
        RegionData->SrcPitch = SrcPitch;
        RegionData->SrcBpp = SrcBpp;
        RegionData->SrcData = SrcData;
 
        ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
            UpdateTextureRegionsData,
            FUpdateTextureRegionsData*, RegionData, RegionData,
            bool, bFreeData, bFreeData,
            {
            for (uint32 RegionIndex = 0; RegionIndex < RegionData->NumRegions; ++RegionIndex)
            {
                int32 CurrentFirstMip = RegionData->Texture2DResource->GetCurrentFirstMip();
                if (RegionData->MipIndex >= CurrentFirstMip)
                {
                    RHIUpdateTexture2D(
                        RegionData->Texture2DResource->GetTexture2DRHI(),
                        RegionData->MipIndex - CurrentFirstMip,
                        RegionData->Regions[RegionIndex],
                        RegionData->SrcPitch,
                        RegionData->SrcData
                        + RegionData->Regions[RegionIndex].SrcY * RegionData->SrcPitch
                        + RegionData->Regions[RegionIndex].SrcX * RegionData->SrcBpp
                        );
                }
            }
            if (bFreeData)
            {
                FMemory::Free(RegionData->Regions);
                FMemory::Free(RegionData->SrcData);
            }
            delete RegionData;
        });
    }
}

注意需要添加RHI和RenderCore模塊,在4.17以后可以直接使用UTexture2D::UpdateTextureRegions。

方法2:

Texture = UTexture2D::CreateTransient(SizeX, SizeY);
FTexture2DMipMap& Mip = [Texture]->PlatformData->Mips[Level];
void* Data = Mip.BulkData.Lock( LOCK_READ_WRITE );
FMemory::Memcpy( Data, NewData, DataSize );
Mip.BulkData.Unlock( );
Texture->UpdateResource();

這種方法每次調用都會Lock/UnLock,和updateResource,每次都會刪除RHI Texture並重新創建,所以這種做法效率不高,最好不要在Tick等頻率高得地方使用。而且UpdateResource只能在主線程中調用。

判斷texture是否初始化用PullTextureTorS->IsValidLowLevel(),重新創建要注意把原有的texture刪除。

PullTextureTorS->ConditionalBeginDestroy();
                PullTextureTorS = UTexture2D::CreateTransient(width, height, PF_R8G8B8A8);
                PullTextureTorS->UpdateResource();

方法3:獲取render target的數據

TArray<FColor> rawData;
rawData.AddUninitialized(dataSize);
FTextureRenderTargetResource* renderTarget = tempTexture->GameThread_GetRenderTargetResource();
            renderTarget->ReadPixelsPtr((FColor*)rawData.GetData());
videoCapture->updateClientData((char *)rawData.GetData(), widht, height);

上述示例將rendertarget的數據拷貝到rawData,但是要注意ReadPixels這個操作很耗時,相當於把數據從GPU拷貝到CPU,而且會調用FlushingRenderCommand,這個函數會阻塞游戲線程,目前沒有在UE4中找到更快的做法,Unity中倒是有將Rendertexture的數據給到一個Texture2D,unity的texture2d可能在CPU中有一份鏡像,所以不太耗時。UE4中RHI接口,即RHICommanList中可能會找到如何實現比較快的獲取到Rendertarget的數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM