很久没做mod了,但是做mod已经很久了。当初学做mod的时候,很多都是群u教的(感谢群u开源),后面渐渐的对mod有点见解了之后就可以自己研究一下mod的各种属性数据的作用,还挺有意思的。自然,我能做出来什么东西的话也会秉持这种开源精神。
我之前并没有接触过3dmigoto注入的mod的制作流程,也只是花了一些时间阅读它的wiki(我认为是有必要且有用的),因此对于其工作原理以及语法规范还不是很熟悉,对它的理解也是浅薄片面的,但我发现许多的玩家也想制作mod,而且对于3dmigoto的了解程度也很少,因此本文将尽可能地解释每一个术语的含义,把逻辑讲清楚。另外ini的用法是十分灵活多变的,读者若有更好的方法,欢迎指正。
这个mod教程使用的工具是ssmt3,我会尽可能详细地讲一次利用customshader来替换某一次draw的ps。
这种做法不一定能完美屏蔽色差,实际上游戏原本的渲染流程复杂的多,仅仅替换掉ps这个着色器就想达到跟另一个材质一模一样的效果,还是不够的。如果读者做过终末地的mod就会知道,人物皮肤材质如果用衣服的材质渲染的话,就会出现奇怪的光影信息,而皮肤的材质是不会有那么多反光的,所以本次教程的目的就是消除这些奇怪的反光,并尝试直接使用皮肤的着色器渲染衣服的部位(该拼好模还得拼)


先讲点理论,这样才能理解究竟是怎么实现的跨ps渲染。
1.先来解释一下一些术语的意思
- ib:定义顶点数量以及连接方式的文件
- vb:顶点的缓冲区,存储顶点的各个信息如位置,法线,权重,uv,顶点色等
- vs:顶点着色器,负责计算原始的顶点坐标在经过骨骼变换后在屏幕变换后的结果,在这一步后,只需要经过光栅化,再经过像元着色器(ps)的计算后就可以把图像输出到我们屏幕上
- ps:像素着色器,负责染色,输出每一次draw的最终经过
- ps-tx:像素着色器的某一个槽位存储的信息,ps从里面采样信息进行计算
- vs-tx:顶点着色器的某一个槽位的信息,作用同上
2.终末地模型的渲染管线
我这里以管理员的衣服与身体为例子,直接说结论,一次ib有6次绘制,具体的如下衣服的draw

身体的draw

显然他们是紧邻着的draw
- 前三次绘制阴影相关



显然,他们的vs与ps皆相同,因此我只需要改变模型的输入部分(替换VB,IB),就可以得出正确的阴影效果
- 第四次光栅化阶段

显然他们的顶点着色器也是一样的,像素着色器不同,这是光栅化阶段,负责计算出物体,遮挡信息,是否剔除是否虚化等等,他们ps不同,理论上应该也要更换ps的,否则某些特定条件下会有问题,这里为了简化教程,就不替换了
- 第五次绘制模型主色

这次draw是本文的核心修改流程,是十分关键的一次draw。可以看到他们的vs依旧相同,因此可以替换ps来实现材质的替换
- 第六次绘制轮廓

显然他们的vs即不同,ps也不同,因此需要修改两个着色器,但是我没研究,故先搁置(直接不管)
此外,以上的绘制的实际内容是gemini说的(Gemini说的未必正确无误,请仔细甄别),不过确实说的没错。
此外,终末地的人物模型,即使是主控模型,没有lod的情况下,摄像机拉近与拉远使用的还不是同一个ps,所以实际上要更换两次ps,要dump两次模型(真无敌了)。
另外,终末地的pst0 ps-cbx vs-cbx vs-t0等等插槽,在每一帧,不同ib,dump下来的数据都一模一样,不同帧dump下来的同一个ib的数据不一样,这说明它这些缓冲区是动态变化的。
3.替换ps
所以经过分析,我们只需要替换第五次绘制的ps即可,那么怎么替换呢,具体的ini代码如下
[Resourceps0]
[Resourceps1]
[Resourceps2]
[Resourceps3]
[Resourceps4]
[Resourceps5]
[Resourceps6]
[Resourceps7]
[Resourceps8]
[Resourceps9]
[Resourceps10]
[Resourceps11]
[Resourceps12]
[Resourceps15]
[Resourceps16]
[Resourcepscb2]
[ShaderOverrideps]
hash = 16add12c293b13fa
filter_index = 110
[ShaderOverrideps1]
hash = 7519e61caed641f7
filter_index = 111
[TextureOverride_IB_cced9603_body_Component10]
hash = 149f97a2
Resourceps1 = ref ps-t1
Resourceps2 = ref ps-t2
Resourceps3 = ref ps-t3
Resourceps10 = ref ps-t10
Resourceps11 = ref ps-t11
Resourceps12 = ref ps-t12
Resourceps15 = ref ps-t15
Resourceps16 = ref ps-t16
Resourcepscb2 = ref ps-cb2
[TextureOverride_IB_cced9603_body_Component1]
hash = cced9603
match_first_index = 0
handling = skip
vb0 = Resourcecced9603Position
vb1 = Resourcecced9603Texcoord
vb2 = Resourcecced9603Blend
ib = Resource_cced9603_Component1
if ps == 110
run = CustomShadermainps
endif
if ps == 111
run = CustomShadermainpsnear
endif
if ps !=110 && ps !=111
ps-t14 = Resource_Texture_c624cf92
ps-t15 = Resource_Texture_9d38d199
ps-t16 = Resource-cced9603-1-NormalMap
drawindexed = 173424,89007,0
endif
[CustomShadermainps]
ps-t2 = ref Resourceps2
ps-t3 = ref Resourceps3
ps-t10 = ref Resourceps10
ps-t11 = ref Resourceps11
ps-t12 = ref Resourceps12
ps-t12 = ref Resourceps12
ps-t13 = Resourcebml
ps-t14 = Resource-cced9603-1-NormalMap
ps-t15 = ref Resourceps15
ps-t16 = ref Resourceps16
ps = Mods\gly\ep\7fe8abc33934ad11-ps_replace.txt
drawindexed = 173424,89007,0
[CustomShadermainpsnear]
ps-t2 = ref Resourceps2
ps-t3 = ref Resourceps3
ps-t10 = ref Resourceps10
ps-t11 = ref Resourceps11
ps-t12 = ref Resourceps12
ps-t13 = Resourcebml
ps-t14 = Resource-cced9603-1-NormalMap
ps-t15 = ref Resourceps15
ps-t16 = ref Resourceps16
ps = Mods\gly\ep\ae408ce3351f24c5-ps_replace.txt
drawindexed = 173424,89007,0
这里每一行代码都是核心代码,我建议就按照我的写法写。我将他们分成3段(资源定义区不讲),详细分析各个段落的作用
- 首先是ShaderOverride
[ShaderOverrideps]
hash = 16add12c293b13fa
filter_index = 110
[ShaderOverrideps1]
hash = 7519e61caed641f7
filter_index = 111
这一行使用了filter_index标记了两个身体近处与远处的ps着色器,16add12c293b13fa就是第五次绘制阶段的ps,使用filter_index = 110标记,与下面的textureoverride中的ps=110配合,就可以精准地只替换第五次绘制的ps,而不影响该绘制下的其他的ps
- 然后是TextureOverride
[TextureOverride_IB_cced9603_body_Component10]
hash = 149f97a2
Resourceps1 = ref ps-t1
Resourceps2 = ref ps-t2
Resourceps3 = ref ps-t3
Resourceps10 = ref ps-t10
Resourceps11 = ref ps-t11
Resourceps12 = ref ps-t12
Resourceps15 = ref ps-t15
Resourceps16 = ref ps-t16
这里是把身体原本绘制的槽位记录下来,你不用引用的方法,而是直接每个槽位都用你自己的贴图替换也可以,除了ps-t16这个槽位以外,ps-t16这个槽位是使用的3d纹理。3D 纹理(Volume Texture) 通常用于 体积雾(Volumetric Fog) 或 环境探针(Environment Probe)。这也是为什么如果不替换它,模型在远处会变黑(因为读不到雾效数据,默认为黑)。
3dmigoto没有把它dump下来,因此得引用这个槽位,否则模型拉远了会出现随摄像机变化的,覆盖模型表面的黑影,具体槽位的分布情况下文再作分析。
[TextureOverride_IB_cced9603_body_Component1]
hash = cced9603
match_first_index = 0
handling = skip
vb0 = Resourcecced9603Position
vb1 = Resourcecced9603Texcoord
vb2 = Resourcecced9603Blend
ib = Resource_cced9603_Component1
if ps == 110
run = CustomShadermainps
endif
if ps == 111
run = CustomShadermainpsnear
endif
if ps !=110 && ps !=111
ps-t14 = Resource_Texture_c624cf92
ps-t15 = Resource_Texture_9d38d199
ps-t16 = Resource-cced9603-1-NormalMap
drawindexed = 173424,89007,0
endif
这里首先拦截了hash = cced9603,即管理员衣服的ib(目的就是把管理员的衣服的材质替换成身体的材质),通过skip掉原本的绘制,然后执行我们自定义的绘制,从而实现更换材质的效果。
这里一共有3个判断,前文分析了我们只需要替换掉第五次绘制的draw,那么就通过之前shaderoverride标记的两个ps(远处近处各一个),if语句筛选出来(按照之前fliter标记的值来筛选),分别运行不同的customshader,其余的着色器直接按照衣服的原本的draw来渲染,这一步很关键,不能说只运行我们的customshader就不管原来的绘制了,customshader高度依赖上下文,如果你没有进行第四次绘制(光栅化阶段),那么customshader中物体的因为缺少深度信息或 G-Buffer 数据,导致像素被剔除或无法计算,那么customshader的draw就绘制出来的是空的物体。
if ps !=110 && ps !=111
ps-t14 = Resource_Texture_c624cf92
ps-t15 = Resource_Texture_9d38d199
ps-t16 = Resource-cced9603-1-NormalMap
drawindexed = 173424,89007,0
endif
因此,还要判断除了那两个着色器以外的,就普通地按照衣服的槽位,替换衣服的贴图,然后直接draw
- customshader
首先要了解customshader的生命周期,customshader被调用的时候,会绑定上下文对象(各种vs ps cb tx),在里面可以随意修改槽位与着色器,是相当于一次独立的,完整的绘制,在绘制完成后回到调用它的地方,还原到调用它的时候的状态。
这个是最核心的渲染,要了解整段代码是怎么工作的,就需要知道customshader怎么与textureoverride联动的。
依旧先看代码
[CustomShadermainps]
ps-t2 = ref Resourceps2
ps-t3 = ref Resourceps3
ps-t10 = ref Resourceps10
ps-t11 = ref Resourceps11
ps-t12 = ref Resourceps12
ps-t13 = Resourcebml
ps-t14 = Resource-cced9603-1-NormalMap
ps-t15 = ref Resourceps15
ps-t16 = ref Resourceps16
ps = Mods\gly\ep\7fe8abc33934ad11-ps_replace.txt
drawindexed = 173424,89007,0
[CustomShadermainpsnear]
ps-t2 = ref Resourceps2
ps-t3 = ref Resourceps3
ps-t10 = ref Resourceps10
ps-t11 = ref Resourceps11
ps-t12 = ref Resourceps12
ps-t13 = Resourcebml
ps-t14 = Resource-cced9603-1-NormalMap
ps-t15 = ref Resourceps15
ps-t16 = ref Resourceps16
ps = Mods\gly\ep\ae408ce3351f24c5-ps_replace.txt
drawindexed = 173424,89007,0
显然,这段代码十分简单,就是在替换ps的槽位,以便进入到我们的定义的ps中能读到正确的槽位,这两个customshader在逻辑上完全一致,就简单的替换ps,ps对应的槽位,然后执行一次draw,其中ps = Mods\gly\ep\7fe8abc33934ad11-ps_replace.txt,这个txt文件是在游戏中找到身体的上色阶段的ps,按3dump下来的。
至此,核心代码就完全解析完了,是不是看的懵懵的,来看哈基米怎么说。他说:
简单来说,它的核心目的是:在画衣服(Clothes)的时候,强行窃取身体(Body)的材质数据(光照、纹理、雾效),并使用身体的着色器(Shader)来进行渲染,从而让衣服呈现出和皮肤完全一致的光照质感。
下面我为你详细拆解这段代码的 执行逻辑流程 以及 渲染管线(Render Pipeline) 在每一步具体干了什么。
第一阶段:标记与识别 (Tagging)
Ini, TOML
[ShaderOverrideps]
hash = 16add12c293b13fa
filter_index = 110 ; 标记:这是衣服的【中距离】上色 Shader
[ShaderOverrideps1]
hash = 7519e61caed641f7
filter_index = 111 ; 标记:这是衣服的【近距离】上色 Shader
逻辑分析:
管线行为:当游戏加载这两个 Shader 时,3Dmigoto 给它们打上标签(Tag)。
目的:后续代码可以通过 if ps == 110 快速判断当前显卡是不是准备画衣服,以及是准备画远处的还是近处的。
第二阶段:数据窃取 (Capture)
Ini, TOML
[TextureOverride_IB_cced9603_body_Component10]
hash = 149f97a2 ; 这是身体的 Index Buffer Hash
Resourceps1 = ref ps-t1
Resourceps2 = ref ps-t2
...
Resourceps16 = ref ps-t16
逻辑分析:
触发时机:当 GPU 准备绘制 身体 (Body) 时。
管线行为:
显卡此时绑定了身体的所有贴图(皮肤纹理、LightMap、3D雾效等)。
ref 指令让 3Dmigoto 获取这些显存槽位的 内存地址引用 (Reference)。
这些地址被暂存到变量 Resourceps1 到 Resourceps16 中。
关键点:你使用的是 ref(引用)而不是 copy(复制)。这很省显存,但要求身体必须在衣服之前或者同帧内绘制,且数据未被销毁。
第三阶段:拦截与重组 (Interception & Reassembly)
这是最复杂也是最核心的部分:
Ini, TOML
[TextureOverride_IB_cced9603_body_Component1]
hash = cced9603 ; 这是衣服的 Hash
match_first_index = 0
handling = skip ; 【核心】拦截!阻止游戏原本的绘制
vb0 = ... ; 重新定义顶点缓冲 (Geometry)
ib = ... ; 重新定义索引缓冲
逻辑分析:
触发时机:当 GPU 准备绘制 衣服 (Clothes) 时。
管线行为 (IA Stage):Input Assembler (输入装配器) 准备好了衣服的模型网格。
handling = skip:
3Dmigoto 对显卡说:“停!不要执行原本的 DrawCall。”
原本的衣服渲染被取消了。接下来完全由你的代码接管。
分支判断 (Branching)
代码接着进入了三个 if 判断,决定如何“篡改”这次绘制:
分支 1:如果是中距离上色 (ps == 110)
Ini, TOML
if ps == 110
run = CustomShadermainps ; 跳转到自定义 Shader 逻辑
endif
分支 2:如果是近距离上色 (ps == 111)
Ini, TOML
if ps == 111
run = CustomShadermainpsnear ; 跳转到近距离自定义逻辑
endif
分支 3:如果是其他阶段(如光栅化/阴影/深度)
Ini, TOML
if ps !=110 && ps !=111
; 手动指定资源(因为没有跳转 CustomShader,必须在这里给)
ps-t14 = Resource_Texture_c624cf92
ps-t15 = Resource_Texture_9d38d199
ps-t16 = Resource-cced9603-1-NormalMap
; 手动触发绘制
drawindexed = 173424,89007,0
endif
管线行为:这个分支通常对应 ps=113 (光栅化) 或 ps=100 (阴影)。在这里,你强制显卡使用衣服的法线图 (t16) 和一些基础贴图,然后命令显卡 drawindexed。这保证了衣服在 G-Buffer 里有正确的深度和法线,确保它不会消失,也能产生正确的遮挡关系。
第四阶段:注入与执行 (Injection & Execution)
以 [CustomShadermainps] 为例:
Ini, TOML
[CustomShadermainps]
; 1. 注入身体资源 (The Transplant)
ps-t2 = ref Resourceps2 ; 把刚才从身体偷来的 t2 塞进现在的 t2
...
ps-t16 = ref Resourceps16 ; 把身体的 3D 雾效/环境光塞进来
; 2. 指定衣服独有资源
ps-t13 = Resourcebml ; 衣服自己的混合图
ps-t14 = ...NormalMap ; 衣服自己的法线图
; 3. 偷天换日 (Shader Swap)
ps = Mods\gly\ep\7fe8abc33934ad11-ps_replace.txt ; 强行加载身体的 Shader 代码!
; 4. 最终发射 (Draw)
drawindexed = 173424,89007,0
渲染管线在这里到底干了什么?
几何阶段 (VS):使用的是 衣服 的顶点数据(由 vb0/ib 定义)。显卡计算的是衣服的形状。
光栅化 (RS):显卡把衣服的三角形变成了屏幕上的像素。
像素着色 (PS):这是魔法发生的地方。
显卡运行的是 身体的 Shader 代码。
当 Shader 代码请求 t15 (LightMap) 时,它读到的是 身体的光照数据。
当 Shader 代码请求 t16 (Fog) 时,它读到的是 身体的雾效数据。
当 Shader 代码请求 t14 (Normal) 时,它读到的是 衣服的法线(这保留了衣服的褶皱细节)。
结果:你得到了一个形状是衣服,但材质、反光、透光感完全像皮肤的物体。
它如是说,简单的来说,这段代码的主要功能就是在textureoverride中套了一层customshader,在模型上色阶段,利用dump下来的ps替换游戏原本的ps,其余阶段不变,然后绘制的过程。
原理讲完了,现在就直接讲应该怎么做了
- 首先是ini方面
首先打开ssmt,在游戏中按7 8查找你想要的模型的材质的ib,以及想用谁的ib进行渲染的ib,找到后填入ssmt,记得f8dump帧分析文件

然后点击提取模型,然后再点击打开最近的日志文件,查看对应哈希有哪些draw

找到着色器是b1ca4834786821dd(我发现这个顶点着色器几乎作用于所有人物材质)的文件,找它的ps的哈希

回到游戏按1 2找到对应哈希,dump下来把文件保存好

同样的操作,在视角拉的很近的时候dump一次,重复上面流程,最终得到两个ps文件
接下来就可以着手写ini了
首先是把身体对应的资源区记录下来
具体要记录什么插槽,各种材质要记录的都不一样,要结合dump下来的ps文件分析。其中t0以及t4-t9不需要注册,好像这几个插槽每个ib都是一样的。
[TextureOverride_IB_cced9603_body_Component10]
hash = 149f97a2
Resourceps1 = ref ps-t1
Resourceps2 = ref ps-t2
Resourceps3 = ref ps-t3
Resourceps10 = ref ps-t10
Resourceps11 = ref ps-t11
Resourceps12 = ref ps-t12
Resourceps15 = ref ps-t15
Resourceps16 = ref ps-t16
[ShaderOverrideps]
hash = 16add12c293b13fa
filter_index = 110
[ShaderOverrideps1]
hash = 7519e61caed641f7
filter_index = 111
这里哈希填衣服的对应VS是b1ca4834786821dd的ps的哈希(目标是用衣服的ib但是使用身体的材质),因为是筛选衣服上色阶段的ps,filter_index标记一下备用
[TextureOverride_IB_cced9603_body_Component1]
hash = cced9603
match_first_index = 0
handling = skip
vb0 = Resourcecced9603Position
vb1 = Resourcecced9603Texcoord
vb2 = Resourcecced9603Blend
ib = Resource_cced9603_Component1
if ps == 110
run = CustomShadermainps
endif
if ps == 111
run = CustomShadermainpsnear
endif
if ps !=110 && ps !=111
ps-t14 = Resource_Texture_c624cf92
ps-t15 = Resource_Texture_9d38d199
ps-t16 = Resource-cced9603-1-NormalMap
drawindexed = 173424,89007,0
endif
然后这里是正常的替换vb ib,然后筛选出上色阶段的两个着色器,其余的正常替换插槽,然后draw。
if ps == 110
run = CustomShadermainps
endif
if ps == 111
run = CustomShadermainpsnear
endif
只匹配目标的着色器即16add12c293b13fa才替换ps
然后是
[CustomShadermainps]
ps-t2 = ref Resourceps2
ps-t3 = ref Resourceps3
ps-t10 = ref Resourceps10
ps-t11 = ref Resourceps11
ps-t12 = ref Resourceps12
ps-t13 = Resourcebml
ps-t14 = Resource-cced9603-1-NormalMap
ps-t15 = ref Resourceps15
ps-t16 = ref Resourceps16
ps = Mods\gly\ep\7fe8abc33934ad11-ps_replace.txt
drawindexed = 173424,89007,0
[CustomShadermainpsnear]
ps-t2 = ref Resourceps2
ps-t3 = ref Resourceps3
ps-t10 = ref Resourceps10
ps-t11 = ref Resourceps11
ps-t12 = ref Resourceps12
ps-t13 = Resourcebml
ps-t14 = Resource-cced9603-1-NormalMap
ps-t15 = ref Resourceps15
ps-t16 = ref Resourceps16
ps = Mods\gly\ep\ae408ce3351f24c5-ps_replace.txt
drawindexed = 173424,89007,0
这一堆槽位该怎么替换,需要结合帧分析的log以及ssmt使用,要查看log文件对应draw的地方注册了什么槽位,在里面搜索对应的ps的哈希即可找到那一次draw


(这里draw的序号是218是因为之前的帧分析文件删了,重新dump了一次),注意到这里注册了16个槽位,那么我们也应该替换16个槽位,但是有一些槽位是没必要替换的,比如t0 t4-t9。
然后打开ssmt,发现t13 t14是基础色与法线,t12是什么不知道(那就保留引用),那么除了这两个槽位,其余槽位统统都引用皮肤自己的。

[TextureOverride_IB_cced9603_body_Component10]
hash = 149f97a2
Resourceps1 = ref ps-t1
Resourceps2 = ref ps-t2
Resourceps3 = ref ps-t3
Resourceps10 = ref ps-t10
Resourceps11 = ref ps-t11
Resourceps12 = ref ps-t12
Resourceps15 = ref ps-t15
Resourceps16 = ref ps-t16
Resourcepscb2 = ref ps-cb2
皮肤ib149f97a2
然后再customshader中引用即可。
到这里,一次替换基本上就完成了
到这里,整个“跨材质渲染(Shader Swap)”的流程就讲解完毕了。回顾一下,我们其实只做了一件事:“移花接木”。
我们并没有真的去修改游戏的源代码,也没有重写复杂的 Shader 算法。我们只是利用 3Dmigoto 强大的拦截与注入功能,做了一个聪明的“中间人”:
骗过 GPU:让它拿着衣服的网格(VB/IB),却以为自己在画身体。
偷天换日:在绘制的一瞬间,把身体的光照、雾效、材质参数塞给它,并强制运行身体的 Shader 代码。
智能分流:根据游戏原本的意图(是画远处还是近处),智能地切换到对应的身体 Shader,保证了完美的 LOD 兼容性。
这种方法最大的优势在于“原生感”。因为我们直接使用了游戏自带的身体 Shader 和环境数据,所以渲染出来的效果(透光感、环境反射、阴影)与原版皮肤完全一致,没有任何色差或违和感。这是单纯修改贴图永远无法达到的高度。
希望这篇教程能帮你打开 Mod 制作的新思路。3Dmigoto 的潜力远不止于此,理解了管线和数据流,你就能随心所欲地控制画面。
在实际操作中,你可能会遇到各种奇怪的问题。这里列出了一些最常见的“坑”和解决方案:
模型全黑 / 只有轮廓
原因:99% 是因为 EnvMap(环境光) 或 Fog(雾效) 没给对。
解法:检查 ps-t16(雾效)和 ps-t4 到 ps-t9(环境光)是否正确捕获并注入。特别注意,不同距离的 Shader,雾效所在的槽位可能不一样(比如中距离在 t16,近距离在 t19,轮廓线在 t13)。请务必对照 Log 确认。
模型闪烁 / 第一帧黑屏
原因:使用了 ref(引用),但衣服比身体先画,导致第一帧读到了空数据。
解法:对于关键数据(如 LightMap ps-t15 和 Fog ps-t16),改用 copy(复制)。虽然开销微增,但稳如老狗。
拉近后模型消失
原因:只替换了中距离 Shader,没替换近距离的。
解法:终末地有 远近有不同的ps。你需要像教程里那样,同时拦截 ps=110(中距离)和 ps=111(近距离),甚至可能有更远处的 ps,都要一一替换。
影子穿帮 / 影子形状不对
原因:只改了主色 Shader,没改 Shadow Caster(阴影投射) 的 DrawCall(通常是 ps=100 或类似的)。
解法:找到绘制阴影的那一次 Draw(通常在主色绘制之前),把它的 IB/VB 也替换成衣服的。
关于 drawindexed 的数字
提醒:教程代码里的 drawindexed = 173424,89007,0 是我这个模型的参数。你直接复制粘贴必炸!
解法:请务必从你自己的 log.txt 或者 FrameAnalysis 文件里,找到你那件衣服对应的 IndexCount 和 StartIndexLocation,填入你自己的数值。
Crash / 游戏崩溃
原因:通常是 drawindexed 越界,或者 Shader 代码里引用了不存在的 Buffer(比如 t0 没注入),或者vs ps的输入输出端对不上,比如你只替换了ps,却忽略了这两个ib的vs根本不一致。
解法:vs也替换,ps也替换,对应的槽位都替换。
ps:写的太多了,难免有混乱或者错误之处,如有遗漏之处,后续会改正(可能)
附件是完整的ini,包括光栅化阶段也替换了对应的ps,轮廓线部分目前看来有点问题,也暂时没有替换
模型变黑
原因:在引用皮肤的ps槽位的时候,有可能ps还没初始化就开始捕获了,可能是没有引用到正确的槽位,终末地的一个ib的多次draw的ps槽位不一定都一样(具体逻辑我也不清楚),建议加一段
[ShaderOverrideps6]
hash = 7fe8abc33934ad11
filter_index = 116
然后再在皮肤ib对应部位加过滤在引用



闽公网安备35010302000678号


















































