如果你还没有看我上一篇帖子,建议先看上一篇帖子
上一篇中,成功替换了ps,但是并没有完全替换ps,因为只替换了贴图区域,常量区域(cb)仍然是原来ib的数据。所以这一篇帖子中就是准备替换cb区域的数据,主要是替换控制材质参数的cb区域的数据,不同材质的cb是不一样的,得具体情况具体分析,这里以管理员的衣服材质替换成皮肤材质为例。具体实现难度相对较高,具体可能也会遇上许多问题,我也只能是推测一些参数以及原理,且本次修改的方法不一定是最好的方法,我就不手把手教怎么操作了,此外该方法具体是否有误仍需考证。
具体是实现的效果如下
不替换,只有自发光的贴图

替换后,模型有阴影,边缘光(菲涅尔)

终末地的渲染管线中定义了一个巨大的(4MB)缓冲区,它把所有材质参数,摄像机位置,全局光照,骨骼索引全部丢进去这个缓冲区里,在一次draw中,可以看到尽管有这么多槽位,但是他们的哈希值就只有两个a517561d跟00c6c2c2,这几个槽位完全就是一致的。


根据帧分析文件夹的log内文件夹注册的ps vs的buffer可以看到最后都是1结尾的,AI大人说这是DX11.1的新版本的动态缓冲区的关键词,定义了一个索引pfirstconstant,gpu根据这个索引去对应的cb区域找它要的资源,它又分析到,每次的索引都会变化,这个cb区域是一个环形的动态缓冲区,每次写入时候像队列一样,尾部写入,头部数据清空,所以每一帧的cb区域的值都是不同的,像传送带一样一直循环。

而3dmigoto的源码内没有对pfirstconstant这个变量做解析,因此,直接使用copy cbx,它不会找到对应的偏移区域,只会从首地址开始读,结果就是一堆0数据被读取了,另一种方法是ref cbx,这种方法也不行,因为当你在皮肤ib渲染的时候引用了它的cb区域,它指向的是cb的地址即a517561d,到衣服ib渲染的时候,此时它用的地址仍然是a517561d,结果就变成它仍然是拿衣服的cb区域的值,没有引用到皮肤区域的cb。
但是呢,3dmigoto在进行资源区替换的时候,也不会去读取偏移量,只会按照你资源区域的值从头读取,而皮肤材质参数这种全局定义的值,一般是不会动态变化的,就可以利用这一点,将动态缓冲区的不变的值的cbx区域替换成我们自定义的资源区。
具体的原理是,ps运行到cb5[0]这种变量的时候,如果我们没有替换cb5,gpu就按照它自己的读取方式,到pfirstconstant指定的偏移量的地方,到cb5内读取,如果我们替换了cb5,那3dmigoto就发力了,它直接从偏移量0的地方开始读取,所以我们只需要定义一个简单的buffer文件,将里面的材质参数信息填好即可。
经过分析管理员的皮肤的ps文件,我发现pscb5是材质相关信息,因此只需要替换它即可。
至于怎么填,有两种方法
第一种是牢方法,既然我们知道材质定义区域的值一般不会改变,且ps内有定义cb5的大小,如管理员的pscb5的大小是208字节,13个float,那么就可以直接把哪个全局的cb5文件丢ai分析,分析前得设置一些过滤条件,比如我的ps里面记录了cb5[5]是基础色,那么对应的cb5[5]的值就肯定是1,1,1,1。此外还有一种思路,已知材质参数都是不变的,那么就可以使用局部dump的方法dump两次目标角色的目标ib在不同地方的值,他们之间肯定有一段字节数是相同的,根据这个条件过滤出正确的参数。
第二种方法是使用renderdoc这个软件,可以精确找到偏移量,把它绘制时候的ps的cb5区域的值直接复制黏贴下来即可,关于renderdoc这个软件,可能还需要一些技术过游戏检测。
我使用的是前者,我直接把ps丢ai分析,发现了被使用到的参数都是做什么的,然后修改了一会就行了。
实际上难的点都在分析ps的对应参数信息上了,实际操作很简单,只需要在上一篇中添加ps-cb5 = Resoucepscb5即可。

参数部分这样定义(取决于你的ps内的定义)

ps-cb5.buf文件如下

我给它写了一个简单的模板,以便快速修改值,因为ps定义的值是208字节(13x16),有13个参数,具体参数都是做什么的,每个ps都不一样,且相互关联,一直套娃,这里就不分析了
然后ps-cb5文件,我经过一些分析,写了一个不太准的010模板,有需要的可以自己拿去玩玩(里面的注释是错误的,所有有关sss部分的都一律认为是菲涅尔)