UE4引擎的CopyTexture, CopyToResolveTarget

Posted 带帯大师兄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4引擎的CopyTexture, CopyToResolveTarget相关的知识,希望对你有一定的参考价值。

前言

在图形渲染各种算法上,特别是对2D纹理的处理上,经常出现一种情况,我们需要将一张纹理的一部分拷贝到另外一张纹理上。如下所示:

 

 UE4提供了CopyTextureCopyToResolveTarget来实现拷贝一张纹理一部分到另外一张纹理上的类似功能。

CopyTexture

CopyTexture的基础介绍

struct FRHICopyTextureInfo

	// Number of texels to copy. By default it will copy the whole resource if no size is specified.
	FIntVector Size = FIntVector::ZeroValue;

	// Position of the copy from the source texture/to destination texture
	FIntVector SourcePosition = FIntVector::ZeroValue;
	FIntVector DestPosition = FIntVector::ZeroValue;

	uint32 SourceSliceIndex = 0;
	uint32 DestSliceIndex = 0;
	uint32 NumSlices = 1;

	// Mips to copy and destination mips
	uint32 SourceMipIndex = 0;
	uint32 DestMipIndex = 0;
	uint32 NumMips = 1;
;

CopyTexture的SourceTextureRHI和DestTextureRHI适用于UE4的UTexture2D, UTextureRenderTarget2D, UTexture2DArray等几种纹理类型进行相关拷贝。

拷贝纹理参数FRHICopyTextureInfo

FRHICopyTextureInfo包含了关于CopySrcTextureCopyDestTexture各种设定参数

Size: 拷贝纹理部分的大小

SourcePosition:SrcTexture拷贝部分的起始位置

DestPosition:DestTexture拷贝部分的起始位置

SourceSliceIndex:SrcTexture拷贝的部分所在SrcTexture纹理数组的数组index(普通纹理就是数组大小为1的纹理数组,默认SliceIndex等于0)

DestSliceIndex:DestTexture拷贝的部分所在DestTexture纹理数组的数组index(普通纹理就是数组大小为1的纹理数组,默认SliceIndex 等于0)

SourceMipIndexSrcTexture拷贝的部分是当前SrcTexture纹理的哪个Mip级

DestMipIndex: DestMipIndex拷贝的部分是当前DestMipIndex纹理的哪个Mip级

NumMips: 这次进行进行N级Mip的拷贝(通常情况下,这个是1,一次一般只拷贝一级Mip)

总结:SrcTexture数组的第SourceSliceIndex个纹理的第SourceMipIndexMip级的[SourcePosition, SourcePosition+Size]范围拷贝到DestTexture数组的第DestSliceIndex个纹理的第DestMipIndex级的[DestPosition, DestPosition+Size]范围

示例

将一张Texture的每级Mip左上角四分之一拷贝到一张RenderTexture对应Mip级的左上角部分

	UFUNCTION(BlueprintCallable, Category = "Test Shader", meta = (WorldContext = "WorldContextObject"))
		static void CopyTextureToRenderTextureAllMips(
			const UObject* WorldContextObject, 
			const UTexture2D* InTexture,
			class UTextureRenderTarget2D* OutputRenderTarget);
void UTestCopyRenderFunctionLibrary::CopyTextureToRenderTextureAllMips(
	const UObject* WorldContextObject,
	const UTexture2D* InTexture,
	class UTextureRenderTarget2D* OutputRenderTargetA)

	UWorld* World = WorldContextObject->GetWorld();
	ERHIFeatureLevel::Type FeatureLevel = World->Scene->GetFeatureLevel();

	if (FeatureLevel < ERHIFeatureLevel::SM5)
	
		UE_LOG(LogTemp, Warning, TEXT("FeatureLevel < ERHIFeatureLevel::SM5"));
		return;
	

	if (nullptr == InTexture)
	
		UE_LOG(LogTemp, Warning, TEXT("InTexture Is NULL"));
		return;
	

	FTextureRenderTargetResource* TextureRenderTargetSource = OutputRenderTargetA->GameThread_GetRenderTargetResource();
	FTexture* TextureSource = InTexture->Resource;

	int32 CommonMip = FMath::Min(TextureRenderTargetSource->TextureRHI->GetNumMips(), TextureSource->TextureRHI->GetNumMips());

	ENQUEUE_RENDER_COMMAND(TestShaderCommand)(
		[TextureSource, TextureRenderTargetSource, FeatureLevel, CommonMip](FRHICommandListImmediate& RHICmdList)
		
			if (CommonMip >= 2)
			
				//Test Copy Subregion
				for (int32 MipIndex = 0; MipIndex < CommonMip - 1; ++MipIndex)
				
					FRHICopyTextureInfo CopyInfo;
					CopyInfo.SourcePosition = FIntVector(0, 0, 0);
					CopyInfo.DestPosition = FIntVector(0, 0, 0);
					CopyInfo.SourceMipIndex = MipIndex;
					CopyInfo.DestMipIndex = MipIndex;
					CopyInfo.Size = FIntVector(TextureSource->GetSizeX() / FMath::Pow(2, MipIndex + 1), TextureSource->GetSizeY() / FMath::Pow(2, MipIndex + 1), TextureSource->GetSizeZ() / FMath::Pow(2, MipIndex + 1));
					RHICmdList.Transition(FRHITransitionInfo(TextureRenderTargetSource->TextureRHI, ERHIAccess::Unknown, ERHIAccess::CopyDest));
					RHICmdList.Transition(FRHITransitionInfo(TextureSource->TextureRHI, ERHIAccess::SRVMask, ERHIAccess::CopySrc));
					FRHITexture* Test = TextureSource->TextureRHI.GetReference();
					RHICmdList.CopyTexture(TextureSource->TextureRHI, TextureRenderTargetSource->TextureRHI, CopyInfo);
					RHICmdList.Transition(FRHITransitionInfo(TextureRenderTargetSource->TextureRHI, ERHIAccess::CopyDest, ERHIAccess::SRVMask));
					RHICmdList.Transition(FRHITransitionInfo(TextureRenderTargetSource->TextureRHI, ERHIAccess::CopySrc, ERHIAccess::SRVMask));
				
			
			else
			
				FRHICopyTextureInfo CopyInfo;
				CopyInfo.SourcePosition = FIntVector(0, 0, 0);
				CopyInfo.DestPosition = FIntVector(0, 0, 0);
				CopyInfo.Size = FIntVector(TextureSource->GetSizeX() / 2, TextureSource->GetSizeY() /2, TextureSource->GetSizeZ() / 2);
				RHICmdList.Transition(FRHITransitionInfo(TextureRenderTargetSource->TextureRHI, ERHIAccess::Unknown, ERHIAccess::CopyDest));
				RHICmdList.Transition(FRHITransitionInfo(TextureSource->TextureRHI, ERHIAccess::SRVMask, ERHIAccess::CopySrc));
				RHICmdList.CopyTexture(TextureSource->TextureRHI, TextureRenderTargetSource->TextureRHI, CopyInfo);
				RHICmdList.Transition(FRHITransitionInfo(TextureRenderTargetSource->TextureRHI, ERHIAccess::CopyDest, ERHIAccess::SRVMask));
				RHICmdList.Transition(FRHITransitionInfo(TextureRenderTargetSource->TextureRHI, ERHIAccess::CopySrc, ERHIAccess::SRVMask));
			

		
	);

	FlushRenderingCommands();

SrcTexture: 512 * 512的存在10级Mip的Texture

DestTexture: 512 * 512的存在10级Mip的RenderTexture

 

 

 CopyTexture的使用注意事项

 [1]SrcTexture和DestTexture数组格式匹配,比如都说RGBA8或者RGBA16,格式不匹配可能导致程序崩溃

[2]像MipIndex,SliceIndex, Szie等参数注意不要越界(比如纹理数组Size为5, 在程序指定来SliceIndex = 5), 也可能导致程序崩溃.

[3]当CopySize为0时,会自动拷贝各级Mip, 进行整体拷贝,参考下面

CopyTexture的底层原理

UE4 CopyTexture使用RHI层的东西,在不同的平台下有不同的实现,在DX11下的实现:

 CopySubresourceRegion(CopySize不为0时) 和 CopyResource(CopySize等于0时)

 CopyToResolveTarget

 CopyToResolveTarget在UE4渲染线程经常使用,作用也说用来拷贝FTextureRHI,作用和CopyTexture很类似。

使用案例代码

void UTestCopyRenderFunctionLibrary::CopyToResolveTarget(
	const UObject* WorldContextObject,
	class UTexture2D* InTexture,
	const UTexture2D* OutTexture,
	FIntVector CopySize)

	UWorld* World = WorldContextObject->GetWorld();
	ERHIFeatureLevel::Type FeatureLevel = World->Scene->GetFeatureLevel();

	if (FeatureLevel < ERHIFeatureLevel::SM5)
	
		UE_LOG(LogTemp, Warning, TEXT("FeatureLevel < ERHIFeatureLevel::SM5"));
		return;
	

	if (nullptr == OutTexture)
	
		UE_LOG(LogTemp, Warning, TEXT("InTexture Is NULL"));
		return;
	


	FTexture* SourceTexture = InTexture->Resource;
	FTexture* TargetTexture = OutTexture->Resource;

	ENQUEUE_RENDER_COMMAND(TestShaderCommand)(
		[SourceTexture, TargetTexture, FeatureLevel, CopySize](FRHICommandListImmediate& RHICmdList)
		
			FResolveParams ResolveParams;
			ResolveParams.Rect = FResolveRect(0, 0, SourceTexture->GetSizeX(), SourceTexture->GetSizeY());
			ResolveParams.DestRect = FResolveRect(0, 0, SourceTexture->GetSizeX(), SourceTexture->GetSizeY());
			RHICmdList.Transition(FRHITransitionInfo(TargetTexture->TextureRHI, ERHIAccess::Unknown, ERHIAccess::CopyDest));
			RHICmdList.Transition(FRHITransitionInfo(SourceTexture->TextureRHI, ERHIAccess::SRVMask, ERHIAccess::CopySrc));
			RHICmdList.CopyToResolveTarget(SourceTexture->TextureRHI, TargetTexture->TextureRHI, ResolveParams);
			RHICmdList.Transition(FRHITransitionInfo(TargetTexture->TextureRHI, ERHIAccess::CopyDest, ERHIAccess::SRVMask));
			RHICmdList.Transition(FRHITransitionInfo(SourceTexture->TextureRHI, ERHIAccess::CopySrc, ERHIAccess::SRVMask));
		);

 连参数的作用也很类似,不过严格来说CopyToResolveTarget使用 范围比CopyTexture要广,比如说普通纹理(UTexture2D, UTexture2DArray, UTextureRenderTarget2D)使用CopyTexture不存在什么问题,但是SceneDepthTexture这种Texture使用CopyTexture直接野蛮拷贝效果是问题的。

看看CopyToResolveTargetDX11的实现

 可以看到CopyToResolveTarget在针对DepthStencil类纹理,说采用定制的FResolveDepthPS来进行Copy的,而针对普通纹理,则和CopyTexture一样。 总体上CopyTexture只说CopyToResolveTarget功能上的一个子集。

 案例代码下载

https://download.csdn.net/download/qq_29523119/86242859

参考资料

https://docs.microsoft.com/zh-cn/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-copysubresourceregion

UE4/UE5引擎 FPS游戏逆向工程

课程详细目录 : UE4/UE5引擎 FPS游戏逆向工程 · 语雀

工具:

提供可调试EAC调试器(免费)

提供可注入EAC BE的内核层注入器 成品 + 源码(免费)、后期会教写一个内核层注入器

提供内核层dump工具 成品 + 源码(免费) ,解决游戏文件不能直接ida分析问题 // 注: 非dump sdk,请分辨清楚

提供内核层dump sdk脚本 成品 + 源码(免费) // 支持为受保护的游戏dump sdk

实战游戏:

单机游戏 UE4引擎(无保护)、

POLYGON UE5引擎(EAC)、

GUNDAM EVOLUTION 高达进化(EAC)、

超级人类 UE4引擎(BE)、

Apex(EAC)

公开课:

暗藏c的个人空间_哔哩哔哩_Bilibili

效果视频:

暗藏c的个人空间_哔哩哔哩_Bilibili

效果图片:

简介:

不以单机游戏做演示,第一章的单机游戏只是学习基础!!!

不以单机游戏做演示,第一章的单机游戏只是学习基础!!!

不以单机游戏做演示,第一章的单机游戏只是学习基础!!!

学完基础,直接做多人游戏,带您完整做一个项目!!!

学完基础,直接做多人游戏,带您完整做一个项目!!!

学完基础,直接做多人游戏,带您完整做一个项目!!!

一共七章 上百个视频 从应用层到内核层!!!

01 UE4引擎:

// 在 01 UE4引擎 这一环节,只是基础的了解一下UE引擎,打下深厚的基础

// 各种绘制算法 + 内存自瞄 + 静默自瞄 + 子弹追踪 + 各种变态功能都在 02 UE5

00 必要前提 // dx内绘基础

01 自写 DX11Hook 框架

02 解决内绘更改分辨率崩溃问题

03 通过UE引擎源码分析GName算法

04 IDA查找GName

05 CE查找GName

06 C++编写GetName函数

07 验证GName算法

08 IDA查找GWorld

09 玩家类继承关系

10 GWorld结构详解及修复GWorld结构

11 遍历所有Actor坐标 // 实践前面所学

12 寻找世界坐标转屏幕坐标CALL

13 调用世界转屏幕CALL并绘制名字

14 过滤Actors 只绘制敌人

15 寻找敌人骨骼并绘制骨骼索引

16 UE引擎骨骼算法详解 // 主要是讲解UE引擎的骨骼算法,以及解决外部骨骼闪烁

17 解决骨骼闪烁问题

18 寻找骨骼相对坐标转世界坐标CALL

19 用CALL的方式来获取骨骼坐标

20 通过骨骼名来绘制骨骼,解决骨骼索引不同问题

21 寻找摄像机组件 // UE引擎障碍判断

22 寻找射线CALL (障碍判断CALL)

23 射线CALL参数详解并修复函数

24 使用射线CALL做障碍判断

02 UE5引擎: // 带领做一个完整的逆向工程

00 内核注入器的使用

01 基础环境配置

02 复习内绘框架

03 改变框架使其适配注入器

04 寻找GWorld GName等

05 UWorld结构

06 GetName函数

07 UE5坐标与UE4的不同

08 寻找世界坐标转屏幕坐标call

09 绘制所有Actor名字

10 寻找玩家数组 只绘制玩家

11 区分阵营 不绘制队友

12 寻找骨骼以及骨骼坐标call

13 绘制骨骼 // 各种绘制算法

14 绘制菜单

15 绘制2D自适应方框

16 绘制3D旋转方框

17 绘制2D旋转雷达

18 绘制射线

19 绘制朝向

20 绘制血量以及过滤死亡敌人

21 UE5障碍判断

22 内存自瞄实现 // 三种自瞄方式

23 分析射击call

24 静默自瞄实现

25 子弹追踪实现

26 自瞄范围实现

27 分析武器类 // 武器类功能

28 武器无扩散实现

29 武器无后座实现

30 武器全自动实现

31 子弹瞬击实现

32 人物无限耐力实现 // 人物类功能

33 人物加速实现

34 解决游戏崩溃问题

35 通过特征码搜索技术,来达到游戏更新 辅助"免更新"

03 引擎绘制: 

01 引擎绘制跟内绘区别

02 ida分析虚表,快速定位引擎挂钩函数

03 寻找引擎绘制函数

04 ida寻找GEngine

05 使用引擎字体渲染

04 转储(Dump) SDK:

00 基础环境搭建

01 寻找 GUObjectArray

02 修复 TUObjectArray 结构

03 修复 FUObjectItem 结构

04 修复 UObject 结构

05 dump下所有UObject信息

06 修复 UEnum 结构

07 修复 UFunction 结构

08 修复 UStruct 结构

09 修复 FField 结构

10 修复 FProperty 结构

11 Dump SDK // dump sdk 学习

12 通过ida分析出UEnum结构偏移

13 通过ida分析出UStruct结构偏移

14 通过ida分析出UFunction 结构偏移

15 通过ida分析出FField结构偏移

16 通过ida分析出FProperty 结构偏移 // 因为如果结构加密,ce寻找有可能找不到,于是有了ida寻找偏移

17 使用驱动读写来dump驱动保护游戏 // 更改dump脚本 使其支持dump驱动保护游戏

05 对抗结构加密:

GUNDAM EVOLUTION(高达进化) 驱动dump 解决不能直接ida分析

GUNDAM EVOLUTION(高达进化) GWorld解密

GUNDAM EVOLUTION(高达进化) GName解密

GUNDAM EVOLUTION(高达进化) GObject解密

GUNDAM EVOLUTION(高达进化) dump sdk

超级人类 结构加密对抗

// 超级人类对大量结构进行了加密 如GName、dump sdk 结构基本全被加密

// 除此之外 还对游戏文件进行加密处理 使其不能ida静态分析

// 这一环节我们要学习如何对抗加密算法

06 内核基础:

00 内核基础必要前提

01 驱动与R3通讯

02 Cr3方式 驱动读取数据

03 Cr3方式 驱动写入数据

04 Mdl方式 驱动读取数据

05 Mdl方式 驱动写入数据

06 驱动层申请内存

07 驱动层释放内存

08 驱动层修改页保护属性

09 补充

07 内核反射注入(无模块注入,内存注入):

00 内核注入必要前提

01 内存展开DLL

02 修复 重定位表

03 修复 导入表

04 修复 TLS

05 Call ShellCode的几种方式

06 如何绕过eac be等驱动保护,来Call ShellCode

07 组装ShellCode

08 抹除反射注入特征

09 Apex (EAC)注入测试

以上是关于UE4引擎的CopyTexture, CopyToResolveTarget的主要内容,如果未能解决你的问题,请参考以下文章

UE4 编译虚幻引擎

如何隐藏UE4引擎目录?

虚幻引擎UE4-命令行使用的一些技巧

UE4引擎无法启动,

ue4 虚幻四引擎项目无法打包,求帮助!

UE4 插件扩展引擎工具栏