UE4 Texture操作總結
阿新 • • 發佈:2018-02-04
array new man dex this edit 重新 sda ray
項目中經常需要對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的數據。
UE4 Texture操作總結