mencelot/DK2-Remix-Predetermined-Hashing
GitHub: mencelot/DK2-Remix-Predetermined-Hashing
一个修改版的 DirectX 兼容层 wrapper,通过为《地下城守护者2》运行时动态组合的纹理提供稳定的预定哈希,使其能够接入 NVIDIA RTX Remix 路径追踪渲染并实现可靠的纹理替换。
Stars: 0 | Forks: 0
# DK2 — Remix 预定哈希
这是一个经过修改的 [`dxwrapper`](https://github.com/elishacloud/dxwrapper),它将 **Dungeon Keeper 2**(1999,DirectX 6)接入了 **[NVIDIA RTX Remix](https://github.com/NVIDIAGameWorks/rtx-remix)** 的路径追踪——更具体地说,它通过为 DK2 在运行时组合的纹理提供一个**预先确定的、稳定的哈希**(可离线编写),使这些纹理变得*可替换*。
据我们所知,DK2 是唯一一款在 Remix 上运行的 DirectX 6 游戏。这个仓库就是使其成为可能的 wrapper。这是一个业余项目,很大程度上也是一种实验——请以这种心态来阅读它。
## 为什么会有这个项目
RTX Remix 通过对游戏上传的每个纹理进行**哈希处理**,并允许你替换与该哈希绑定的美术资产,从而替换游戏的纹理。当游戏上传稳定、可识别的纹理时,这种方法非常有效。
但 DK2 并非如此。它是一个 1999 年的引擎,会在**运行时组合纹理**——它使用自己的 LRU 缓存,将精灵(墙壁贴图、火炬火焰、HUD 部件、水面帧)动态地进行装箱打包,放入共享的图集页面中。同一堵墙在不同的运行中可能会落入不同的页面、具有不同的偏移量。因此,对于 Remix 来说,该页面的哈希值会发生**漂移**:你今天标记的纹理明天就会失效。手动标记哈希注定会失败——我们根据经验验证过,某天保存的 41 个哈希值到了第二天全都消失了。
**这里的核心理念——“预定哈希”——就是停止追逐运行时哈希,转而让它们能够提前预知。**
1. **恢复稳定的源身份。** 在 DK2 的主要纹理上传 blit 操作中进行只读拦截,读取游戏*自身*的描述符,该描述符带有稳定的 `EngineTextures` 名称索引。因此,无论图集打包器将其放在哪里,我们都能通过名称知道一个页面*是由什么组成的*。
2. **预定哈希。** 因为我们能够解码源字节,并且我们复制了 Remix 的精确哈希算法(对紧密打包的 mip-0 字节计算 XXH3),所以我们可以**在离线状态下,甚至在游戏运行之前**,计算出 Remix 将为任何给定精灵或规范页面看到的精确哈希。美术资产可以提前针对这些哈希进行制作。
3. **在运行时按名称解析。** 在绑定时,wrapper 会根据名称将漂移的运行时页面解析回其规范的、预定的身份(通过像素与预期的 payload 进行验证,出现任何不匹配都会回退到原始状态),并提供由 `(name, mip)` 作为键构建的 payload 裁剪。
结果:每场游戏约 20 万次绘制都由稳定的、离线已知的身份提供服务——纹理“漂移之战”取得了胜利。深入剖析的文章在 [`DK2_RTX_REMIX_DOCUMENTATION.md`](DK2_RTX_REMIX_DOCUMENTATION.md) 中。
## 目前可行的功能
- **路径追踪的 Dungeon Keeper 2** —— 在原版游戏上实现真正的光线追踪全局光照、反射和自发光火炬光照。
- 大规模的 **PBR 纹理替换** —— 每个 `EngineTextures` 图像都经过了重新制作(PBRify/CHORD pipeline),通过预定哈希层进行绑定,从而确保其能够稳定生效。
- **半透明的静止水面** —— DK2 的 32 帧动画水面被帧折叠为一个稳定的哈希,并替换为路径追踪的半透明材质;逐帧的正弦波几何形状通过逐帧最小二乘法表面拟合在 wrapper 端被扁平化(DK2 的屏幕空间顶点首先被逆投影回世界空间)。
- **响应式光照** —— 移动/熄灭的光源几乎会瞬间更新(Remix 的默认设置会保留过期光源约 100 帧)。
- **黑暗中可读的 UI**、可见的“邪恶之手”光标,以及可选的**高分辨率前端菜单**(2560×1600+)。
- 少数几处**精准的 `DKII.exe` 补丁**(缩小视角、相机俯仰角、菜单分辨率),以及一个**私有 LFH 堆**拦截,绕过了 1999 年 CRT 的小块堆锁。
## *不可行*的功能(诚实说明)
- **几何体 / 网格是尚未探索的领域。** Remix 的网格*替换*是通过几何体哈希绑定的,而 DK2 对此的阻碍与它对纹理的阻碍方式相同,甚至更棘手:
- **LOD** 是在运行时按子网格选择的,其计算方式连专家都称之为谜——因此网格的哈希值会随着相机距离而改变。
- **生物是顶点动画**(变形/形状键,而非骨骼),因此提交的几何体——及其哈希值——*每一帧*都在变化。静态替换无法适应这种情况。
- **模型被拆分**为命名的子网格(例如小恶魔由背部 + 前部 + 镐组成)以进行纹理解析,进一步增加了哈希数量。
- 结论:**静态道具可以替换;动画生物和逐帧批处理的地形则不能**——至少在没有 wrapper 端的几何体身份层或迫使引擎使用单一 LOD 的情况下是不行的。这项工作正在进行中,并在笔记中如实记录,包括那些走不通的死胡同。
## DK2 专属工作的代码位置
这是 **dxwrapper 的一个分支**(经由 [dkollmann 的 RTX-Remix 分支](https://github.com/dkollmann/dxwrapper)),后者是一个庞大的通用 DirectX 兼容性工具包。这里绝大多数文件都是上游代码且未作更改。我们的贡献集中在以下方面:
- `ddraw/IDirectDrawSurfaceX.cpp` —— 预定哈希 / 规范身份 / 名称键层,通用的 UV 分解缓存,以及离线哈希机制。
- `ddraw/IDirect3DDeviceX.cpp` —— XYZRHW→世界逆投影、水面拟合以及各种只读逆向工程探针。
- `ddraw/HeapReplace.cpp`, `ddraw/MenuRes.cpp` —— 堆拦截和菜单分辨率 exe 补丁。
- `Settings/Settings.h` —— 控制上述所有功能的 `Ddraw*` 标志。
## 构建
Visual Studio 2022,MSBuild,**Win32 / Release**,工具集 v143:
```
msbuild dxwrapper.sln /t:dxwrapper /p:Configuration=Release /p:Platform=Win32 /p:PlatformToolset=v143
```
将输出的 `dxwrapper.dll`(以及 `dxwrapper.ini`)放入 DK2 游戏文件夹中,与 RTX Remix runtime 放在一起。单凭这个 wrapper 并不提供 Remix runtime、mod 或重新制作的美术资产。
## 许可证
zlib,继承自 dxwrapper —— 参见 [`License.txt`](License.txt)。各文件的版权头保持完整;此处没有任何内容声称拥有上游代码的所有权。
### 关于本仓库历史的说明
我们的大部分工作是通过实时迭代构建的——编辑、重新构建、在游戏中测试——而没有在开发过程中提交代码。因此,2026-06 工作的提交日期是在发布时根据带日期的项目笔记组装的**忠实重建**,而不是原始的分步历史。日期和描述是真实的;它们只是在事后进行了集中整理。更早的历史(1 月/5 月的火炬、纹理和 XYZRHW 工作)是真实的。逐日记录请参见 [`CHANGELOG.md`](CHANGELOG.md)。
标签:DirectX封装器, macOS, NVIDIA RTX Remix, 光线追踪, 图形渲染, 客户端加密, 游戏模组, 纹理哈希