- 游戏开发
- 开发工具
【免费下载链接】GI-Model-Importer
Tools and instructions for importing custom models into a certain anime game
本篇技术指南以 GI-Model-Importer(GIMI)仓库中的效果与着色器修改教程为核心,系统讲解如何使用 3DMigoto GIMI 开发版修改原神中的技能效果、灯光效果,以及任何不通过纹理或缓冲区控制的游戏内对象。你将依次掌握三个难度递增的实战案例——为迪卢克的火焰重新着色、为钟离的柱子制作多颜色循环效果、为雷电将军打造随时间流动的动画线条,从而理解像素着色器(PS)与顶点着色器(VS)的工作原理,获得独立创作效果类 Mod 的能力。
本文所有操作均基于本仓库 Guides/CN_EffectModdingTutorial.md 的核心流程展开,并补充了 使用指南、故障排查 以及Tools/目录下相关脚本的实现细节,方便读者按难度循序渐进、随时回查。
前提条件与环境准备
需要安装什么
本教程要求安装3dmigoto GIMI Dev(开发)版本。GIMI 是作者基于 3DMigoto 修改、使其兼容原神的版本(见 README.md),仓库提供了两个发行版本:
- 开发版(for development):所有功能开启,包括屏幕顶部和底部的绿色文本,用于制作 Mod,但运行较慢;
- 游玩版(for playing mods):关闭了开发功能(无绿色文本),运行更快,适合加载现成 Mod 游玩。
效果修改必须使用开发版,因为你需要依靠绿色文本(HUD)来读取当前选中的着色器/缓冲区哈希,并进行转储操作。安装与注入的细节参见 README.md 的 Installation Instructions 部分。
重要:默认关闭的着色器转储能力
GIMI默认禁用转储着色器的能力,因为转储出的着色器可能干扰 Mod 运行。要重新启用,需要编辑d3dx.ini,确保marking_actions行在列表中包含hlsl和asm两项:
marking_actions = include, hlsl, asm如果缺少hlsl,按数字键盘3后 ShaderFixes 文件夹中不会出现转储出的着色器文件。此外,如果在尝试本教程内容后遇到 Mod 故障,请尝试清空 ShaderFixes 文件夹——有时转储出的着色器会导致某些 Mod 出现故障(这也是 CN_Troubleshooting.md 中反复出现的建议)。
关键快捷键速查表
结合本教程与 CN_UsageInstructions.md,完整的关键操作如下:
| 按键 | 功能 |
|---|---|
数字键盘0 | 开启/关闭狩猎模式(显示绿色文本) |
数字键盘+ | 将所有当前选中的缓冲区重置为 0(搜索/重载前建议重置) |
数字键盘1/2 | 循环像素着色器(PS) |
数字键盘3 | 复制当前 PS 哈希值并转储到 ShaderFixes |
数字键盘4/5 | 循环顶点着色器(VS) |
数字键盘6 | 复制 VS 哈希值 |
数字键盘7/8 | 循环索引缓冲区(IB) |
数字键盘9 | 复制 IB 哈希值 |
数字键盘//* | 循环顶点缓冲区(VB) |
数字键盘- | 复制 VB 哈希值 |
F8 | 执行 Frame Analysis Dump(帧分析转储) |
F9 | 在修改模式与无修改模式之间切换 |
F10 | 重新加载 Mod / 着色器 |
关于各类对象的含义:**顶点缓冲区(VB)**包含绘制到屏幕上的物体的顶点信息;**索引缓冲区(IB)**包含顶点如何连接形成模型的信息;**顶点着色器(VS)**控制物体在屏幕上绘制的位置;像素着色器(PS)决定物体的外观、绘制的纹理与颜色。由于本教程关注颜色,核心操作对象是 PS。
案例一:改变角色攻击颜色(迪卢克的火焰)
这是基础/中级难度章节,不需要任何前置的编程或着色器知识。核心思路:找到负责绘制火焰的像素着色器 → 转储 → 修改它的输出颜色。
第一步:挑选合适的场景
找一个屏幕上物体尽可能少、但你想要的效果仍会显示的地方。屏幕上的对象越多,寻找着色器时循环遍历的时间就越长。起始海滩区域通常是个不错的选择。
第二步:触发效果并暂停
触发想要修改的效果,然后进入暂停菜单。本例对迪卢克技能的火焰效果感兴趣,所以按下E键后立即暂停。注意:对于只有在游戏未暂停时才显示的效果,获取着色器会更困难一些(后面会单独讲解应对方法)。
第三步:循环像素着色器
在数字键盘上按1和2循环像素着色器(PS)。当你找到正确的 PS 时,对应的效果就会在游戏中消失。例如:
- 控制挥动中心火焰的着色器;
- 控制周围火焰云的着色器。
两个都需要处理。本教程示例中这两个着色器的哈希值为e75b3ffb93a1d268和dd0757868249aaa5。注意:着色器哈希值可能在不同游戏版本之间改变,你的哈希值可能不相同。
第四步:转储着色器到 ShaderFixes
在数字键盘上按3,将 PS 哈希值复制到剪贴板,同时把着色器保存到 ShaderFixes 文件夹中。着色器文件名称类似hash-ps_replace.txt。如果按3后没有显示文件,请确认d3dx.ini的marking_actions中包含hlsl和asm(见顶部重要说明),然后按F10刷新。
少数着色器不会正确反编译为hlsl(高级着色器语言),而会退回为asm(汇编)。这些着色器仍然可以工作,但编辑起来更笨拙。本教程不涉及 asm,但概念相同——只是语法更难阅读。
第五步:理解着色器文件的输入与输出
用任意文本编辑器(Notepad / Notepad++ / Sublime Text 等)打开转储出的文件。文件看起来很吓人,但不需要理解全部细节即可进行基本修改。
最关键的是 main 函数下方的输入和输出声明。示例文件有 9 个输入(编号v0~v8)和 1 个输出(o0)。输出o0的类型是float4,包含x、y、z、w四个分量,接受浮点数(十进制)输入。
注意:
//和/**/表示代码注释,会被程序忽略。3dmigoto 还会把asm代码导出到hlsl代码下方——本文所说的“末尾”,指的是return语句之前,而不是之后;return之后的所有内容都被注释掉,默认不会运行。如果看到div、mul、mov等汇编指令,说明已经跑得太远了。
第六步:强制覆盖输出值
在代码末尾(return之前)添加一行,把o0的值强制设为常量,即可覆盖游戏计算的值并替换为我们自己的值:
o0.xyz = float3(0, 0, 0);保存文件,在游戏中按F10重新加载(记得先按+重置缓冲区)。3dmigoto 会自动从 ShaderFixes 文件夹加载着色器。
第七步:验证各分量对应的颜色
通过逐项实验可以确认o0.xyz对应效果的RGB 颜色:
- 将
x和z设为 0、y设为 1 → 效果变绿; - 将
x和y设为 0、z设为 1 → 效果变蓝; - 三者全为 0 → 黑色。
w分量似乎与效果的宽度/发射有关。注意:并不总是o0是颜色——有些着色器有多个输出,颜色可能在o1、o2等;示例中的火焰着色器只有一个输出o0,属于比较简单的情况。
第八步:实际修改颜色
现在可以自由改色了。例如:
- 三个分量都设为 0 → 迪卢克的火焰变成黑色;
r和b设为 1、g设为 0 → 紫色;- 不设常量,而是改变色调——减少红色、增加绿色和蓝色,可创造鲑鱼粉颜色(此时火焰纹理仍然可见,因为没有被完全覆盖)。
除了改变输出,也可以用类似方法通过修改输入来改变效果(把覆盖行放在输入正常加载之后),但需要反复试验推断哪个变量控制什么。
第九步:收集更多着色器
改变效果颜色的基本过程是:找到哈希 → 转储 → 修改输入或输出。但只处理两个 PS 远远不够——示例中迪卢克火焰还包含多个独立绘制的部分:
| 哈希值 | 控制的部位 |
|---|---|
0fa220b5adced192 | 火花 |
bf7eb60b256538c7 | 剑边的火焰 |
439c03865c4ce77e | 鸟 |
7690cf4aa6647c6c | 元素爆发期间的剑辉 |
收集所有不同的着色器是编辑效果时花费时间最多的部分。即使把所有上述部分都变黑,元素爆发期间仍会出现火焰——因为爆发期间无法暂停游戏,需要更进阶的手段。
第十步:获取无法暂停时出现的着色器
有三种方法:
- 无限爆发能量法:在 grasscutter(私服)上启用无限爆发能量,在能量满溢时反复施放元素爆发。适用于任何可重复触发的事情,但比较耗时;
- 禁用爆发相机法:站在浅水区或背对墙壁施放爆发,可以禁用爆发相机,从而在爆发时正常暂停,留出时间循环哈希;
- 作弊软件降速法:使用 Akebi 等工具将游戏速度降到 1 以下,用慢动作观看效果。注意:在官方服务器上使用作弊软件可能导致封号,如采用此方法建议只在私人服务器上进行。
对于只在过场动画中出现或难以重现的效果,最快的方法是帧转储(Frame Analysis Dump):效果在屏幕上显示时按F8执行转储。由于不知道具体哈希,需要一次完整转储,因此请确保有 5~10GB 空闲空间、且屏幕上对象尽可能少(密集区域按 F8 甚至可能导致游戏崩溃或长时间卡顿,详见 CN_UsageInstructions.md)。
帧转储后生成 FrameAnalysis 文件夹,其中的o0、o1文件显示每个绘制 ID 所绘制的内容,非常适合分离出具体效果对应的 ID。文件命名格式类似:
000352-o0=3315d2b5-vs=f6a1f24f9c9b28c2-ps=a69e25f25a6c8e04.dds通过查看这些文件(例如ps=a69e25f25a6c8e04就是像素着色器哈希),可以逆向定位地面发光效果等难以直接转储的部分。示例中还找到了000353(ps=4d4da8a4cbe1149a)和000365(ps=622a52d3edcf0363)对应的着色器。
第十一步:转储剩余着色器
按数字键盘+重置缓冲区,施放元素爆发,在效果显示期间用1/2循环。即使循环到目标哈希时效果已经离开屏幕,只要在效果出现时就开始循环,它就会出现在列表中并可转储。例如 PS4d4da8a4cbe1149a在元素爆发未激活时也能被转储出来。用此技术可转储a69e25f25a6c8e04、4d4da8a4cbe1149a、622a52d3edcf0363三个剩余着色器。
第十二步:选择性应用——只影响迪卢克
修改完成后会发现一个严重问题:所有火焰都被改为黑色了,不只是迪卢克的。切换火系角色(如胡桃)时,效果同样生效;如果别人创建了修改胡桃或可莉火焰的 Mod,也会与迪卢克的修改互相重叠。因此需要一种机制,仅当迪卢克在场上时应用效果。
所有方法都遵循同一原则:确定迪卢克在场时成立的某些条件,然后仅在该条件为真时应用效果。
方案 A:VB 哈希 + 全局变量标记
首先确定迪卢克唯一的 VB 哈希(VB 可用数字键盘/和*循环,用-复制)。示例使用56159d74。然后构建一个.ini:
[Constants] global $ActiveCharacter [Present] post $ActiveCharacter = 0 [TextureOverride迪卢克VB] hash = 56159d74 match_priority = 1 $ActiveCharacter = 1[Present]在每一帧开始时运行一次,把$ActiveCharacter设为 0;当匹配到迪卢克的 VB 哈希时,将其置为 1。match_priority = 1是为了确保这个效果不干扰任何已加载的迪卢克 Mod——如果该效果作为 Mod 的一部分而不是单独添加,可以省略它。
方案 B:ShaderOverride + CustomShader
定义自定义着色器并执行替换,仅在$ActiveCharacter == 1时运行:
[ShaderOverride迪卢克Flame] hash = 4d4da8a4cbe1149a if $ActiveCharacter == 1 run = CustomShader迪卢克Flame endif [CustomShader迪卢克Flame] ps = 4d4da8a4cbe1149a-ps_replace.txt handling = skip drawindexed = auto这种方案通常可行,但 3dmigoto 有时无法正确编译hlsl(会报错),且对asm不起作用。优点是着色器可随 Mod 文件夹一起打包,且不影响其他 Mod 对同一着色器的修改。
方案 C:向着色器传递自定义变量
为每个着色器创建覆盖段,把$ActiveCharacter写入自定义常量寄存器:
[ShaderOverride迪卢克Flame] hash = 0fa220b5adced192 x160 = $ActiveCharacter然后在着色器中定义新常量,并仅在常量等于 1(角色在场上)时执行效果:
float4 IniParams : register(c160);这样迪卢克保持修改后的效果,胡桃则显示正常。方案 C 的机制将在下一节深入讲解。
案例二:将自定义值传递到着色器(循环颜色)
本节演示如何从.ini文件把自定义值加载到着色器中,并利用它制作在多种颜色之间自动循环的效果,同时学习如何定位着色器中控制**发射(emission)**的部分——这比直接改效果颜色更有挑战性。本节为中等难度,要求理解上一节大部分内容,对.ini文件和着色器有基本熟悉,并具备基础编程知识。
第一步:收集着色器哈希
从收集着色器哈希开始,这次目标是钟离的柱子。与迪卢克火焰不同,这个哈希不会让整个柱子消失,只会让纹理消失——因为柱子使用多个着色器绘制,跳过一部分后仍有轮廓保留。示例哈希为4c99fec14dca7797,按3转储到 ShaderFixes。最终目标是改变黄色裂隙效果的颜色,同时保持其他部分不变。
第二步:分析更复杂的着色器
打开着色器,它比火焰着色器(9 输入 1 输出)更复杂,有 6 个输出——因为它承担多种职责:绘制纹理、处理发光、计算阴影等。采用与之前相同的方法,将每个输出设为常量来探明用途:
o0与轮廓有关(使轮廓变厚/变薄,可用F9在修改/无修改模式间切换对比);o1.xyz对应颜色 RGB,w控制亮度;o2也能控制颜色;o3~o5用途不明确,但似乎影响线的粗细。
问题来了:这些输出会改变整个柱子的颜色,而不仅是黄色地理线。需要更深入地挖掘。
第三步:理解着色器中的关键符号
在继续之前,先解释着色器中最重要的一类符号:
| 符号 | 含义 |
|---|---|
v0,v1,v2… | VB 文件中加载的输入数据:顶点位置、顶点颜色(与纹理颜色不同)、UV 贴图、混合权重等 |
o0,o1,o2… | 输出目标,是实际绘制到屏幕上的内容(在 VS 情况下则传递给 PS) |
t0,t1,t2… | 纹理——典型如 DDS 纹理,某些情况下也可以是缓冲区;.ini中的ps-t0、vs-t0、ps-t1、vs-t1等即对应它们 |
r0,r1,r2… | 寄存器——着色器存储计算结果的临时变量 |
cb0,cb1,cb2… | 常量缓冲区——游戏传给着色器的值,代表当前游戏状态,如对象全局位置、自游戏开始以来经过的时间 |
有了这些概念,就可以只聚焦感兴趣的那部分代码,而不是试图理解全部 200 多行。
第四步:定位控制辉光的代码
钟离柱子的辉光来自 diffuse 纹理alpha 层之上的发光部分,diffuse 加载在插槽 0(可通过柱子的 hash.json 或查看 Mod 的ps-t0确认)。因此,关注代码中涉及t0的任何部分,特别是涉及w 分量的部分(它代表发光)。
t0在着色器中被加载了两次:一次在约第 100 行的变量r2,一次在约第 235 行的输入变量r0。判断哪个是正确目标有两种方式:阅读代码推理,或逐个尝试。测试表明:把第一处r2.X设为常数会把柱子变绿但保持裂隙效果正常——说明第二处代码块才是目标。
颜色通常由 3 个分量的变量表示,最接近该代码块的是r1(显示在下方 3 行处)。把r1.x设为 1 后,成功移除了辉光的红色分量——r1正是控制柱子辉光 RGB 的寄存器。
注意:这并不代表
r1总是负责代码中所有位置的辉光颜色,它只是保留了该特定时间点的辉光值。寄存器在执行计算时会被着色器重用,其“含义”会逐行变化——这与输入/输出不同。同理可推断:从你认识的某个组件出发(如特定纹理或 VB 值),在着色器代码中搜索周边内容,即可定位任意效果的控制代码。
第五步:通过 .ini 传递自定义值
只有一种颜色是无趣的。实际上可以把自定义值从.ini传给着色器,步骤如下:
- 在 3dmigoto 声明区(文件顶部)定义要使用的变量。
180是任意选择的,但理想情况下应选大于 100 的数字,避免意外干扰游戏使用的变量;
float4 IniParams : register(c180);- 将 R、G、B 设置在前一步找到的
t0加载行之后:
r1.x = IniParams[0].x; r1.z = IniParams[0].y; r1.w = IniParams[0].z;注意:这里的
r1有x、z、w分量而非x、y、z,但它们仍对应 RGB,只是字母不同。
- 在
.ini中,找到柱子的 IB 后设置三个值(可通过数字键盘7/8循环 IB 直到柱子消失,或查找 hash.json 直接定位):
[TextureOverridePillarIB] hash = 34e18b4f x180 = 1 y180 = 0 z180 = 0成功!线条被设置为红色。修改.ini中的值即可换色——例如设为紫色:
x180 = 1 y180 = 0 z180 = 1注意,这种方案并不完美——会牺牲一些动画效果以换取自定义颜色。动画方案的实现将在最后一节介绍。
第六步:用 time 变量自动循环颜色
3dmigoto 提供名为time的特殊变量,表示游戏开始后经过的秒数。利用它可以在颜色间自动循环:
[TextureOverridePillarIB] hash = 34e18b4f if time % 3 <= 1 x180 = 1 y180 = 0 z180 = 0 else if time % 3 <= 2 x180 = 0 y180 = 1 z180 = 0 else x180 = 0 y180 = 0 z180 = 1 endif其原理是把当前时间放入 3 个桶中的 1 个,然后据此把柱子设为红色、绿色或蓝色(每 3 秒循环一次)。改变数字即可调整周期快慢,或增加/删除颜色。从源码结构看,这正是 Tools/genshin_animation_creator.py 生成动画类 Mod 时使用的同类机制——该脚本通过$frame、$speed、$start_frame、$end_frame等变量在[Constants]段声明状态,并在[Present]段逐帧推进帧计数。
第七步:用 CustomShader 加载着色器
与之前类似,也可以在.ini中直接加载着色器,而不把它放在 ShaderFixes 中:
[TextureOverridePillarIB] hash = 34e18b4f run = CustomShaderPillarColor [CustomShaderPillarColor] if time % 3 <= 1 x180 = 1 y180 = 0 z180 = 0 else if time % 3 <= 2 x180 = 0 y180 = 1 z180 = 0 else x180 = 0 y180 = 0 z180 = 1 endif ps = 4c99fec14dca7797-ps_replace.txt handling = skip drawindexed = auto这在大多数情况下可行,但存在一个编译小故障:柱子消失后约 1 秒内会留下残留。也可以像上一节那样限制该着色器仅在钟离在场时生效——不过此着色器似乎没有被其他对象共享,所以不像迪卢克火焰那样必要。
案例三:动画效果(Cyber Bodysuit Raiden 的流动线条)
最后一节演示如何结合前两节的原理创建动画效果:在雷电将军的身体上制作随时间流动的发光线条。本节为高级难度,假设你理解前两节、知道如何制作 Mod,并具备基础编程知识。
第一步:找到控制绘制的着色器
雷电将军至少使用两个着色器——一个用于身体对象、一个用于服装对象。我们关注身体对象,因为它具有所需的发射效果(之前通过反复试验发现)。哈希值为7d2763cf91813333,转储到 ShaderFixes。
第二步:定位发射部分
发射位于 diffuse 纹理(槽 0)的 alpha 层之上,因此查找与t0.w相关的代码。着色器中只有一条相关行。测试确认它就是发光的原因。通过添加条件,可以只在 alpha 值大于某个任意数字的像素上触发修改,从而只影响纹理的发光部分。
第三步:准备控制纹理
在 Blender 的纹理绘制选项卡中绘制线条(也可以用 paint.net / Photoshop 直接在纹理上绘制)。diffuse 纹理最终输出必须是BC7 SRGB格式的.dds。建议在单独图层上绘制,便于日后分离。
把线条从 diffuse 纹理中分离出来,放入另一个空白纹理——称为control纹理。这个纹理本质上是告诉着色器纹理的哪些部分会有动画效果的映射(因为 diffuse/光贴图的所有四个通道都已在使用中)。它应该是BC7 Linear类型,因为希望颜色值均匀分布。为了简单起见,将所有颜色通道设为相等(如统一黑色但颜色值大于 0,以便不依赖 alpha 通道也能与背景区分);如果愿意,也可以用每个颜色通道分别控制不同的事物。
第四步:把控制纹理传给着色器
在 Mod 的.ini中的BodyOverride部分添加新纹理:
[TextureOverrideRaidenShogunBody] hash = 428c56cd match_first_index = 17769 ib = ResourceRaidenShogunBodyIBZipped ps-t0 = ResourceRaidenShogunBodyDiffuseRed ps-t1 = ResourceRaidenShogunBodyLightMap ps-t26 = ResourceRaidenShogunBodyControl [ResourceRaidenShogunBodyControl] filename = RaidenShogunBodyControl.dds这里选择加载到插槽 26。建议不要低于 20——曾见过游戏用到这么高的槽位(绝大多数东西使用<10,极少有高于 5 的重要资源)。
第五步:在着色器中加载控制纹理
在着色器顶部附近添加变量,然后模仿t0/t1的加载方式载入新纹理:
float4 IniParams : register(c180);r2.xyzw = t26.SampleBias(s0_s, v2.xy, r0.x).xyzw;选择r2是因为它会被我们从 diffuse 加载的任何内容所取代,不会破坏其他代码行(另一个选择是创建额外寄存器变量)。
第六步:条件渲染
添加条件:只对 control 纹理中红色通道值大于 0 的像素生效——将其设为绿色;否则从原始 diffuse 纹理加载像素:
r2.xyzw = t26.SampleBias(s0_s, v2.xy, r0.x).xyzw; if (r2.x > 0){ r2.xyz = float3(0,1,0); r2.w = 0.6; } else{ r2.xyzw = t0.SampleBias(s0_s, v2.xy, r0.x).xyzw; }(这些值本应标准化,但这里随意设置影响不大。)现在线条的颜色和位置完全由控制纹理与着色器计算控制,而不是从原始纹理读取。因此改变r2.xyz = float3(R,G,B)即可轻松换色,甚至可以像上一节那样把颜色值放在.ini中,甚至让颜色循环。
第七步:添加时间动画
先在 Mod 的.ini中把时间变量传入着色器:
[TextureOverrideRaidenShogunBody] hash = 428c56cd match_first_index = 17769 ib = ResourceRaidenShogunBodyIBZipped ps-t0 = ResourceRaidenShogunBodyDiffuseRed ps-t1 = ResourceRaidenShogunBodyLightMap ps-t26 = ResourceRaidenShogunBodyControl x180 = time在着色器中定义新变量:
#define TIME IniParams[180].x把 control 纹理的线条从常量黑色改为黑到白的渐变,这样r2.x的值将从 0 线性增加到 1(这正是 control 纹理必须保存为BC7 Linear的原因,否则值会偏移导致问题)。然后用TIME与r2.x比较,决定绘制模型的哪个部分。由于r2.x在 0~1 范围内,需要把TIME也归入该范围——用模运算符切分为重复的桶,再除以最大值:
if (r2.x > TIME%2/2){ r2.xyz = float3(0,1,0); r2.w = 0.6; } else{ r2.xyzw = t0.SampleBias(s0_s, v2.xy, r0.x).xyzw; }TIME%2/2使时间每 2 秒在 0 和 1 之间循环。也可以用1- TIME%2/2反转方向:
if (r2.x > 1-TIME%2/2){ r2.xyz = float3(0,1,0); r2.w = 0.6; } else{ r2.xyzw = t0.SampleBias(s0_s, v2.xy, r0.x).xyzw; }第八步:定义线条出现的范围
上述效果中线条逐渐出现/消失,作者希望更“矩阵”风格:线条在身体上移动。于是定义出现范围,只允许与TIME%2/2最多相差 0.2 的值:
r2.xyzw = t26.SampleBias(s0_s, v2.xy, r0.x).xyzw; if (r2.x > TIME%2/2 && r2.x < TIME%2/2+0.2){ r2.xyz = float3(0,1,0); r2.w = 0.6; } else{ r2.xyzw = t0.SampleBias(s0_s, v2.xy, r0.x).xyzw; }效果更好但速度偏快,且线条在循环开始时同时出现,开始/停止点明显。作者最终确定的方程是:
if (r2.x > 0 && (TIME % 3)/2.5 > r2.x && (TIME % 3)/2.5-0.2 < r2.x){ r2.xyz = float3(0,1,0); r2.w = 0.6; } else{ r2.xyzw = t0.SampleBias(s0_s, v2.xy, r0.x).xyzw; }循环每 3 秒一次,时间被放在 0~1.2 范围(除以 2.5 而不是 3)——额外的 0.2 边让线条在循环结束时逐渐出现和消失。
第九步:让颜色循环
颜色也不必固定为绿色,可以用数学让颜色循环——本质是使用不同步的正弦波在色轮周围传播:
if (r2.x > 0 && (TIME % 3)/2.5 > r2.x && (TIME % 3)/2.5-0.2 < r2.x){ r2.xyz = float3((sin(TIME)+1)/2, (sin(TIME+2)+1)/2, (sin(TIME+4)+1)/2); r2.w = 0.6; } else{ r2.xyzw = t0.SampleBias(s0_s, v2.xy, r0.x).xyzw; }第十步:已知问题与局限
作者在实战中总结出以下已知问题:
- 角色切换后线条不会立即出现 1~2 秒:因为角色加载到游戏几秒钟内实际使用不同的着色器,可找到该着色器并替换来消除;
- 倒影没有线条:反射使用不同的着色器,可通过查找并替换修复;
- 与移除透明滤镜 Mod 冲突:有人使用移除透明滤镜 Mod 时会有覆盖雷电的着色器;解决办法是对着色器文件做 diff,找出差异并应用到自己的文件;
- 部分角色在雷电出场时损坏:原因未知,损坏部分甚至不使用同一着色器,难以定位;
- 彩虹色在数学上不完全合理:diffuse 纹理使用
SRGB颜色空间而非线性,需要额外步骤转换颜色(可观察到线条不会精确呈现红/绿/蓝); - 着色器哈希值跨版本变化:这比角色哈希更常见,因此效果类 Mod 可能比角色 Mod 需要更频繁地更新。
拓展:不止于颜色
这种技术不限于颜色——可以把r2设置为从不同纹理中采样(在不同纹理之间做选择),可以在 control 纹理上使用单独通道获得不同效果,也可以用不同变量做切换。注意,实现完整 Cyber Bodysuit Raiden Mod 还包含开关效果、限制生效角色、让用户自定义颜色等切换逻辑,这些均已在前两节的.ini技巧中覆盖。
与效果修改相关的仓库辅助工具
仓库Tools/目录提供了若干与颜色、发光、透明度相关的脚本,可作为效果修改工作流的补充:
- genshin_set_color.py:强制将 texcoord 输出的 COLOR 分量设为指定值,典型用法
python genshin_set_color.py -n CharTexcoord.buf --stride X -a 0移除角色轮廓;stride 大多为 12 或 20(可从 Mod 文件夹.ini的 texcoord 段确认),-r/-g/-b/-a接受 0~255 的整数值; - genshin_set_transparency.py:为 Body/Head/Dress/Extra 生成透明效果,通过
-b/-hd/-d/-e选择部位、-t R G B设置 RGB 混合因子; - genshin_animation_creator.py:将多个 Mod 的
.ini合并并注入动画帧推进逻辑($frame/$speed/$start_frame/$end_frame),用单个按键切换动画播放,与本文的time动画思想同源; - genshin_swap_global_cn.py:在国际服与国服被和谐的服装模型(莫娜、琴、安柏、罗莎莉亚)之间互换,通过
remap.json与all_hash_data.json重映射 Blend 缓冲与绘制哈希。
常见问题与故障排查要点
结合 CN_Troubleshooting.md,效果/着色器修改中最常见的几类问题与对策:
- 绿色文本不显示:确认使用的是开发版(精简版没有绿色文本),并确保以管理员身份运行 GIMI 加载器与原神;
- 转储出的着色器导致 Mod 故障:清空 ShaderFixes 文件夹;必要时同时清空 ShaderCache;
- 按 F10 后 Mod 未生效:确认 Mod 放在正确 Mods 文件夹,且每个角色一次只能有一个对应文件夹;
- 修改没有覆盖全部效果:说明还有未转储的着色器(如阴影、反射、轮廓由其他 PS 绘制),继续循环或使用帧转储补齐哈希;
- 着色器反编译为 asm 而非 hlsl:仍可编辑,只是语法更难读,概念相同;
- 效果与其他人/其他角色的 Mod 冲突:使用
$ActiveCharacter标记 + VB 哈希 + ShaderOverride/CustomShader 的组合做条件限制。
总结
本教程通过三个难度递增的实战案例,完整覆盖了 3DMigoto GIMI 效果修改的核心技术链条:
- 基础改色(迪卢克火焰):转储 PS → 修改
o0.xyz,理解输出与 RGB 的关系; - 自定义值与循环(钟离柱子):理解
v/o/t/r/cb符号体系,定位t0/r1控制发射,通过IniParams(x180等)把.ini的值传入着色器,用time实现颜色循环; - 动画创作(雷电将军):利用
control纹理 + 时间变量 + 条件分支,把静态线条变成随时间流动的动画,并用正弦波实现彩虹色。
掌握这些原理后,你就拥有了使用着色器更改既有效果、甚至生成自定义效果的大部分基础知识。建议在实践中按“找哈希 → 转储 → 定位 → 修改 → 限制生效条件”的流程反复练习,并结合本仓库的 使用指南、故障排查 以及 纹理修改教程、效果修改技巧 等文档持续深化。
- 游戏开发
- 开发工具
【免费下载链接】GI-Model-Importer
Tools and instructions for importing custom models into a certain anime game
相关推荐
3步跑通GetQzonehistory:把QQ空间历史说说导成Excel和图片
3步跑通GetQzonehistory:把QQ空间历史说说导成Excel和图片 周末搬宿舍,老手机相册导到一半,你突然想打开QQ空间对一对2016年毕业旅行那批
游戏开发开发工具OpCore-Simplify 使用指南:从硬件报告到 OpenCore EFI 的 6 步本地流程
OpCore Simplify 使用指南:从硬件报告到 OpenCore EFI 的 6 步本地流程 在黑苹果安装里,制作 OpenCore EFI 是最耗时的
游戏开发开发工具Godot Engine着色器动画:10个动态材质效果实现技巧 🎨
Godot Engine着色器动画:10个动态材质效果实现技巧 🎨 Godot Engine是一款功能强大的开源游戏引擎,其着色器系统让开发者能够创建令人惊叹
游戏开发图形学跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考