UE4引擎的CopyTexture, CopyToResolveTarget
Posted 带帯大师兄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4引擎的CopyTexture, CopyToResolveTarget相关的知识,希望对你有一定的参考价值。
前言
在图形渲染各种算法上,特别是对2D纹理的处理上,经常出现一种情况,我们需要将一张纹理的一部分拷贝到另外一张纹理上。如下所示:
UE4提供了CopyTexture和CopyToResolveTarget来实现拷贝一张纹理一部分到另外一张纹理上的类似功能。
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包含了关于CopySrcTexture和CopyDestTexture各种设定参数
Size: 拷贝纹理部分的大小
SourcePosition:SrcTexture拷贝部分的起始位置
DestPosition:DestTexture拷贝部分的起始位置
SourceSliceIndex:SrcTexture拷贝的部分所在SrcTexture纹理数组的数组index(普通纹理就是数组大小为1的纹理数组,默认SliceIndex等于0)
DestSliceIndex:DestTexture拷贝的部分所在DestTexture纹理数组的数组index(普通纹理就是数组大小为1的纹理数组,默认SliceIndex 等于0)
SourceMipIndex: SrcTexture拷贝的部分是当前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直接野蛮拷贝效果是问题的。
看看CopyToResolveTarget在DX11的实现
可以看到CopyToResolveTarget在针对DepthStencil类纹理,说采用定制的FResolveDepthPS来进行Copy的,而针对普通纹理,则和CopyTexture一样。 总体上CopyTexture只说CopyToResolveTarget功能上的一个子集。
案例代码下载
https://download.csdn.net/download/qq_29523119/86242859
参考资料
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)
公开课:
效果视频:
效果图片:
简介:
不以单机游戏做演示,第一章的单机游戏只是学习基础!!!
不以单机游戏做演示,第一章的单机游戏只是学习基础!!!
不以单机游戏做演示,第一章的单机游戏只是学习基础!!!
学完基础,直接做多人游戏,带您完整做一个项目!!!
学完基础,直接做多人游戏,带您完整做一个项目!!!
学完基础,直接做多人游戏,带您完整做一个项目!!!
一共七章 上百个视频 从应用层到内核层!!!
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的主要内容,如果未能解决你的问题,请参考以下文章