Foundation 施工笔记 【5】- 纹理与延后渲染初步

Preface Editor暂时还没有任何关于光照,甚至是texture map的相关实现。本篇文章将介绍纹理方面的高效存储及Editor GBuffer的布局,及PBR shading的初步测试。 容器格式 不看轮子和各种私有格式的话,常用的主要有DDS和最近的KTX2。 KTX 虽然工具链很成熟,在新版Vulkan Tutorial中也被绝赞推荐:但由于全平台支持,直接使用的话由于各种编码产生的依赖会多的离谱(--depth=1 clone大小约莫~1GB!),因此这里没有选择。 DDS 最后挑的还是DDS,因为容器本身很简单:"DXT " + DDS_HEADER + DDS_HEADER_DXT10后即为对应编码下linear tiled数据,可以分成layer/mip直接上传 GPU。至于为什么不应该(Linear Tiling)整个上传(或者,GPU上的纹理到存储方式为什么是硬件相关的),请参考 Image Copies - Vulkan Documentation。 实现上主要是读文档——部分结构直接从DirectXTex - DDS.h copy过来了。用DDS有一个好处就是能被第三方工具直接打开,同时,Editor序列化纹理也将如此存储。 纹理格式 运行时解码成全精度,原始的R8G8B8A8UNORM等格式存储诚然是…一种选择。不过记得之前和某个Unity游戏打交道见过其在资产里直接存了原始RGB565(RGB 16 bit)量化格式的纹理做NPR 效果。但是至于为什么要用这种格式,搜了半天也没找到个结果(汗) 纹理压缩,可能除了UI带alpha材质的极端情况外,基本是必做的事情。GPU硬件解码其支持的格式开销是几乎不存在的——参考 Unity 给出的材质格式推荐: DXTc/BCn/ETC 桌面端,支持最广泛的包括各种BCn/Block Compression [n]压缩 - 参见 Understanding BCn Texture Compression Formats - Nathan Reed;同时,BC1,BC2,BC3 也被微软叫成 DXT1, DXT3, DXT5,这里提及以防混淆。最后,在近十年支持DX11级别的桌面硬件中,无脑使用BC6(H),BC7 基本没问题。 移动端,ETC曾是主流:Unity的crunch就提供第一方DTXc/BCn和ETC的支持。现在的移动硬件一概支持更优秀且开源的ASTC:Unity自己也在使用ARM官方的开源astc-codec处理编码。但需要注意的是,桌面硬件上对astc的支持几乎不存在。这点也可以自己利用Vulkan Caps Viewer检查: Basis Universal 可见硬件上——上述压缩编码在桌面/移动端的支持是没有交集的。但是纹理压缩做的工作本身会有很多重叠(如 DCT编码等等)—— basisu 即可高效地存储一种统一编码格式,并在运行时非常快速地转换到目标平台使用编码上传GPU。 额外的,basisu也自带一层哈夫曼编码 - 这是在所有block处理完之后全局进行的,因此整体压缩率在相同平均bpp下也会比单纯的BCn等编码一般地会更高。 BC7 最后在GPU和文件本身存储上还是采用了BC7 - Editor内置了来自crunch作者Richard Geldreich 的 bc7enc 实现。这样也方便直接读取并直接转码JPG/PNG存储的glTF模型纹理。...

December 15, 2025 · 7 min · 1412 words · mos9527

Foundation 施工笔记 【4】- 网格数据量化及压缩

Preface 对网格数据而言,顶点数可以很多很多:如果存储每个顶点的开销能够减少,显然对GPU显存和磁盘存储压力而言是非常好的事情。以下介绍目前Editor内存在的一些量化操作。glTF中的顶点可以有以下属性(参见 Spec): Name Accessor Type(s) Component Type(s) Description POSITION VEC3 float Unitless XYZ vertex positions NORMAL VEC3 float Normalized XYZ vertex normals TANGENT VEC4 float XYZW vertex tangents where the XYZ portion is normalized, and the W component is a sign value (-1 or +1) indicating handedness of the tangent basis TEXCOORD_n VEC2 float unsigned byte normalized unsigned short normalized ST texture coordinates COLOR_n VEC3 VEC4 float unsigned byte normalized unsigned short normalized RGB or RGBA vertex color linear multiplier JOINTS_n VEC4 unsigned byte unsigned short See Skinned Mesh Attributes WEIGHTS_n VEC4 float unsigned byte normalized unsigned short normalized See Skinned Mesh Attributes 下面为完整精度的顶点struct,足矣表示glTF标准中的任何非蒙皮(不看JOINTS, WEIGHTS)网格(vertex color暂时忽略)。...

December 14, 2025 · 12 min · 2457 words · mos9527

Foundation 施工笔记 【2】- GPU-Driven 管线与剔除

Preface 迄今为止,Editor渲染方面实现仅处理了单个 Mesh 的最简单情况。接下来我们将正式引入场景加载。 在 CPU 上表达物体间关系的方案诸多——本质上也都是为实现某种Scene Graph。同时,本篇体裁内的最终目标仅仅是为了渲染 GLTF 场景。此后内容也将围绕其结构进行展开。 坐标系细节 我们约定使用右手系坐标系统。即在相机视角,$+X$为右,$+Y$为上,$-Z$为前。这也是Blender等的默认坐标系($+Z$指向相机“内”) 透视及视角矩阵 注:$f$与$a$ $$ f = \frac{1}{\tan(fov_y / 2)},a = \text{宽高比} $$ 我们想要让$z$轴上,相机处 $ z= z_{n}$ 的NDC为 $z_{ndc} = 1$; 无穷远,或一定$z_{f}$ 处 $z_{ndc} = 0$ 理由是充分的。简要地,$[1,0]$映射可大幅改善near plane附件深度精度。详细解释及动机还请参考: https://mynameismjp.wordpress.com/2010/03/22/attack-of-the-depth-buffer/ https://developer.nvidia.com/content/depth-precision-visualized 下面直接给出改配置对应透视矩阵,可由代入计算$z=z_n,z_{NDC}=1$, $z = z_f, z_{NDC} = 0$易得 $$ P = \begin{bmatrix} \frac{f}{a} & 0 & 0 & 0 \newline 0 & f & 0 & 0 \newline 0 & 0 & \frac{z_n}{z_f - z_n} & \frac{z_f z_n}{z_f - z_n} \newline 0 & 0 & -1 & 0 \end{bmatrix} $$...

December 13, 2025 · 10 min · 1969 words · mos9527

Foundation 施工笔记 【3】- Profiler 与 Wave Intrisics 实验

Preface 目前为止,Foundation 还没有直接,不依赖于外部工具的性能评估工具。同时:之前读过的 【技术精讲】AMD RDNA™ 显卡上的Mesh Shaders(二):优化和最佳实践 提到了剔除部分一些Wave Instrisic的优化还暂时没有实现。鉴于后者效果的衡量也可以通过前者反映,且未来好处良多:索性在本篇对这两个方向进行探索。 内置 Profiler 工具上,NV/AMD 也早有了非常成熟的toolchain,即NVIDIA Nsight Graphics,Radeon™ Developer Tool Suite。CPU侧自己也很早集成了tracy profiler:这些都离不开外部工具的加持。当然:内置工具主要是方便即时反馈。真正有诊断意义的数据还是要从第一方,驱动级工具获取分析的。 时序获取 Query 类 API 覆盖率相当广泛 - Vulkan (1.0+),DX12 等等皆有第一方支持 - 为我们的 RHI 及 Renderer 每个pass添加也并非难事。以下为 Renderer 中节选: void Execute(size_t thread_id) noexcept override { ZoneScoped; ZoneNameF("<%s>", pass->name.c_str()); *cmd = r->ExecuteAllocateCommandList(pass->queue, thread_id); (*cmd)->Begin(); (*cmd)->WriteTimestamp(queryPool, RHIPipelineStageBits::TopOfPipe, pass->handle * 2); (*cmd)->BeginTransition(); for (auto& [res, desc] : (*barriers)) { res.Visit([&](RHIBuffer* p) { (*cmd)->SetBufferTransition(p, desc); }, [&](RHITexture* p) { (*cmd)->SetImageTransition(p, desc); }); } (*cmd)->EndTransition(); (*cmd)->DebugBegin(pass->name....

December 6, 2025 · 3 min · 632 words · mos9527

Foundation 施工笔记 【1】- Mesh Shader 自适应 LOD

Preface 预谋多时而虽迟但到的 Foundation 博文系列。 特别中二的名字以外,项(天)目(坑)并非最近开始的工作(开始于约莫 ~2023)。期间诸多内容,如各类无锁 (Lock-free) 数据结构、RHI、RenderGraph细节、Shader 反射等,也都是实现期间相当想留一笔的工作… 嘛、反正也是后期也不得不记的事,不如梭哈开篇为好——那么就开始吧? 注: Foundation 文档:https://mos9527.com/Foundation/ Mesh Shader? 注: 参考性内容 - 酌情跳过。 深入了解,还请参阅以下文档: Introduction to Turing Mesh Shaders - NVIDIA 【技术精讲】AMD RDNA™ 显卡上的Mesh Shaders(一): 从 vertex shader 到 mesh shader 脱离 Fixed Function 的整套Input Assembler/Vertex+Geometry管线,繁而就简:Fragment/Pixel之前,Compute模式的Mes 足矣且充分地代替这些功能。 额外的,前置还可以有Task/Amplification环节生成 Mesh Shader WorkGroup(同时,Task Shader 也支持 Indirect Dispatch)。很显然,这样的架构是相当适合当代 GPU-Driven 渲染器的实现的。 最小单元(Primitive)仍然还是三角形 - 为饱和CS单元利用率,Mesh Shader同时引入了Meshlet - 依据一定指标对Mesh进行分区 - 直接地减小overhead, 间接的提供压缩(index buffer压到N个micro buffer/uint8),剔除机会,和… Enter Nanite 作为 UE5 的招牌特性,Nanite 利用新管线的高粒度与可控性实现了消除 LOD 过渡的任务。...

December 5, 2025 · 8 min · 1503 words · mos9527

PJSK Blender卡通渲染管线重现【1】- 预备工作

Preface 同上次封笔算是承上启下了,刚好能从琢磨卡通渲染的部分(重新)入手…毕竟旧工作这方面留下的问题远远比解决的多 集训前时间也算充裕,看看能写多少吧 版本: 日服 5.0.0 (烤森更新) 设备:Mac Mini M4 (2024) 1. 预备工作 之前有在 Android 实机(注:Pixel 2 XL)上用 RenderDoc 跑过捕捉…除了设备性能相对羸弱和捕捉死慢以外可用性其实不错 不过如今有了 Mac 这方面也许可以不用强加这种限制 先前捣鼓 GPTK 的时候读过它的 README,注意到这段相当有趣: …and inserting the following environment variables to enable Metal debugging and processing of debug information: MTL_CAPTURE_ENABLED=1 D3DM_DXIL_PROCESS_DEBUG_INFORMATION=1 改个环境变量就能调试…比在 Win 上捕捉第三方 Game 得方便太多;应付后者用 RenderDoc/PIX 还学会了各种奇怪的注入方式(?)——不过,回到正题,这个变量放到wine + D3DMetal转译层以外好用吗? 游戏准备 Apple Silicon 的 Mac 无一例外都可以原生跑 iPhone/iPad OS 上的 App —— CPU,GPU零 overhead 不过注意“可以”,AppStore上并搜不到多少能直接装的应用… 但是万幸还有PlayCover可以直接装解密过的 IPA;后者 armconverter 上一搜即得...

November 20, 2025 · 1 min · 207 words · mos9527

PJSK Blender卡通渲染管线重现【2】- 角色及舞台 Shader

Preface Shader部分其实已经有不少现成工作,比如 https://github.com/KH40-khoast40/Shadekai https://github.com/festivities/SekaiToon 至于为什么要自己重新造轮子…有时间。还要什么理由?除此之外(敲黑板)最后实现是要进 Blender 的嘛… PV:愛して愛して愛して 在Xcode调试Metal甚至有Render Graph方式呈现的资源依赖…库克太谢谢你了🥲 上一篇并没有往SRP后处理前的工作去看;这里直击SRPBatcherPass 很巧的是恰好这个Pass处理的正包含角色部分,下面逐步分析 注: 后文向量都将以图示方向表示 1. Eye-Highlight 简明概要的效果 - 即给角色眼睛表现添加卡通风格高光 这部分由额外Mesh表达(注意缩写ehl),在Pass中作为第一个Mesh出现 回到 Metal 调试,观察反编译可知几个效果上的细节 高光‘闪烁’效果 u_xlat0.x = FGlobals._SekaiGlobalEyeTime * UnityPerMaterial._DistortionFPS; u_xlat0.x = floor(u_xlat0.x); u_xlat0.x = u_xlat0.x / UnityPerMaterial._DistortionFPS; u_xlat1.x = u_xlat0.x * UnityPerMaterial._DistortionScrollX; u_xlat1.y = u_xlat0.x * UnityPerMaterial._DistortionScrollY; u_xlat0.xy = fma((-u_xlat1.xy), float2(UnityPerMaterial._DistortionScrollSpeed), input.TEXCOORD5.xy); u_xlat16_0.xy = _DistortionTex.sample(sampler_DistortionTex, u_xlat0.xy).xy; u_xlat16_2.xy = fma(u_xlat16_0.xy, half2(2.0, 2.0), half2(-1.0, -1.0)); u_xlat0.xy = float2(u_xlat16_2.xy) + float2(UnityPerMaterial._DistortionOffsetX, UnityPerMaterial._DistortionOffsetY); u_xlat1.x = UnityPerMaterial....

November 20, 2025 · 11 min · 2187 words · mos9527

PJSK Blender卡通渲染管线重现【3】- SDF 面部渲染实现

Preface 在v2面部模型更新后游戏终于引入了SDF面部阴影;实现上和市面上已有的大部分方案大同小异 本文分享自己在Blender中正确实现该效果的一种思路 注意: 由于个人水平有限错误难免,强烈推荐阅读以下文本作为预备知识: 二次元角色卡通渲染—面部篇 by MIZI 卡通渲染——360度脸部SDF光照方案 by Yu-ki016 Signed Distance Field by 欧克欧克 1. SDF 概述 SDF面部阴影在解决朴素法线/N dot L阈值阴影在极端光照角度表现上的不足以外提供了表现上相当大的自由 具体实现上也相当简洁,以下是HIFI Rush中的应用例 图源:Tango Gameworksのチャレンジが詰まったカートゥーン調リズムアクションゲーム『Hi-Fi RUSH(ハイファイラッシュ)』(1)キャラクター・モー*ション・エフェクト編 美术在(凭不同光照角度于原几何上的)渲染输出为蓝本,手绘出基于角度的阈值图后经某种合成算法后生成一张以亮度映射到光照角度的SDF图像 着色上,SDF可以将点/Fragment渲染的问题转换为物体/Object整体渲染的问题 ​ 最后的着色与且仅与光照角度有关(敲黑板),某种程度上来说等效于对法线一致的平面作阴影 合成上,有 Valve 在 SIGGRAPH 2007 上做的技术分享 和相当多教程会介绍的8-points Signed Sequential Euclidean Distance Transform/8SSEDT 在之后的文章中将会对这两者进行更深入的实现和剖析 当然,本篇还是以复现游戏效果为主 2. 游戏内实现 抽出游戏所用的SDF贴图如下 在 Photoshop 中查看阈值,很显然是上文所介绍过的类似模型 回忆我们所需的阈值对应光照角度;接下来马上就会用到(再次敲黑板) 3. Blender 实现 光照角度 从角度出发,考虑单个光向量$l$ —— 如图(来自 RTR4 …当然这里和BRDF并没有直接联系 由于对称性很显然只凭$ \mathbf{\hat{n}} \cdot \mathbf{\hat{l}}$ 我们只能获得 $\theta \in [0,90\degree]$的光照角($<0$ 部分背光故省去)...

August 27, 2025 · 3 min · 552 words · mos9527

Project SEKAI 逆向 - 笔记归档

Preface Cutoff: 24/01/05 Revision: 24/09/26 其实分析工作主要是在此后才真正起步…不过实在找不到时间写帖子orz 对最新知识有兴趣或也想参与研究的话,还请参阅以下Repo及其Wiki: https://github.com/mos9527/sssekai https://github.com/mos9527/sssekai_blender_io Project SEKAI 逆向(1): 文件解密及API初步静态分析 分析版本:ColorfulStage 2.4.1 (Google Play 美服) 追加(2025/05/04): 若可能,请尝试使用iOS版本分析(如 https://decrypt.day/app/id1557595935);这些版本不需要下文对Metadata/IL2CPP的提取、反混淆,可直接分析 追加(2025/07/27): iOS 发行于 5.5.0 也已实施 Metadata 保护;同时,以下解密 Metadata流程仍然一致;最后对于日服 Android 发行,sssekai 提供手段 供自动化静态分析并解密 Metadata 1. 解密 Metadata 利用 Il2CppDumper 对apk中提取出来的global-metadata.data和il2cpp.so直接分析,可见至少metadata有混淆 IDA静态分析libunity.so, 定位到export的il2cpp_init;没有发现有关混淆的处理 考虑直接分析il2cpp.so,定位到global-metadata.dat有关流程 从这里的xref可以很轻松的摸到Il2Cpp的metadata加载流程 (注:部分变量已更名) _BYTE *__fastcall MetadataLoader::LoadMetadataFile(char *a1) { unsigned __int64 v2; // x8 char *v3; // x9 __int64 v4; // x0 _BYTE *v5; // x8 unsigned __int64 v6; // x9 const char *v7; // x0 int v8; // w21 int v9; // w20 _BYTE *mapped_metadata; // x19 __int64 v11; // x8 __int64 v13; // [xsp+0h] [xbp-E0h] BYREF unsigned __int64 v14; // [xsp+8h] [xbp-D8h] char *v15; // [xsp+10h] [xbp-D0h] size_t len[2]; // [xsp+30h] [xbp-B0h] __int64 v17[2]; // [xsp+80h] [xbp-60h] BYREF char *v18; // [xsp+90h] [xbp-50h] char *v19; // [xsp+98h] [xbp-48h] BYREF __int64 v20; // [xsp+A0h] [xbp-40h] unsigned __int8 v21; // [xsp+A8h] [xbp-38h] _BYTE v22[15]; // [xsp+A9h] [xbp-37h] BYREF _BYTE *v23; // [xsp+B8h] [xbp-28h] sub_17A953C(); v19 = "Metadata"; v20 = 8LL; v2 = (unsigned __int64)(unsigned __int8)v13 >> 1; if ( (v13 & 1) !...

August 27, 2025 · 10 min · 1944 words · mos9527

算竞笔记 - 题集/板子整理(C++)

Preface 参考主要来自《算法竞赛入门经典:训练指南》、OIWiki、CP Algorithms等资源和多方博客、课程,在自己的码风下所著 注: 部分实现可能用到较新语言特性,烦请修改后在较老OJ上使用;原则上提供的代码兼容符合Cpp14及以上标准的编译器 以下板子/题目为自己接触ACM一年期间积累。现整理为单个、便携式 Markdown 文档方便打印。体量较大,还请谅解。 [TOC] Header #include "bits/stdc++.h" using namespace std; typedef long long ll; typedef double lf; typedef pair<ll, ll> II; typedef vector<ll> vec; const inline void fast_io() { ios_base::sync_with_stdio(false); cin.tie(0u); cout.tie(0u); } const lf PI = acos(-1); const lf EPS = 1e-8; const ll INF = 1e18; const ll MOD = 1e9 + 7; const ll DIM = 1e5; int main() { fast_io(); /* El Psy Kongroo */ return 0; } 数学 快速幂 // 注:爆int64考虑__int128或相关intrinsic // MSVC: https://codeforces....

August 27, 2025 · 104 min · 22116 words · mos9527