unity-shader-游戏渲染效果逆向分析
Posted 蝶泳奈何桥.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity-shader-游戏渲染效果逆向分析相关的知识,希望对你有一定的参考价值。
title: unity-shader-游戏渲染效果逆向分析
categories: Unity3d-Shader
tags: [unity, shader, glsl, 逆向]
date: 2022-07-18 18:59:06
comments: false
mathjax: true
toc: true
游戏渲染效果逆向分析
前篇
都是为了抄别人的效果, 使用 snapdragon profiler 等软件将别人游戏渲染某帧时截取出来, 通过 glsl 逆向还原成对应引擎的 shader 代码.
还原时得有个对比, 比如还原的是 unity 做的游戏, 可以先随便写点 shader, 打包后用 snapdragon 看看 unity shader 的函数最终在渲染时的是怎么样的 glsl, 然后对着要逆向的 游戏 反推回 unity 的 shader.
各种函数的逆向
normalize 归一化
// normalize(_WorldSpaceLightPos0.xyz)
u_xlat0.x = dot(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz);
u_xlat0.x = inversesqrt(u_xlat0.x);
u_xlat0.xyz = u_xlat0.xxx * _WorldSpaceLightPos0.xyz;
UnityObjectToWorldNormal
// UnityObjectToWorldNormal(v.normal)
u_xlat1.x = dot(in_NORMAL0.xyz, unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_WorldToObjectArray[0].xyz);
u_xlat1.y = dot(in_NORMAL0.xyz, unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_WorldToObjectArray[1].xyz);
u_xlat1.z = dot(in_NORMAL0.xyz, unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_WorldToObjectArray[2].xyz);
u_xlat0.x = dot(u_xlat1.xyz, u_xlat1.xyz);
u_xlat0.x = inversesqrt(u_xlat0.x);
u_xlat0.xyz = u_xlat0.xxx * u_xlat1.xyz;
UnityObjectToClipPos
// UnityObjectToClipPos(v.vertex);
u_xlat1 = in_POSITION0.yyyy * unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_ObjectToWorldArray[1];
u_xlat1 = unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_ObjectToWorldArray[0] * in_POSITION0.xxxx + u_xlat1;
u_xlat1 = unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_ObjectToWorldArray[2] * in_POSITION0.zzzz + u_xlat1;
u_xlat1 = u_xlat1 + unity_Builtins0Array[u_xlati0 / 8].hlslcc_mtx4x4unity_ObjectToWorldArray[3];
u_xlat2 = u_xlat1.yyyy * hlslcc_mtx4x4unity_MatrixVP[1];
u_xlat2 = hlslcc_mtx4x4unity_MatrixVP[0] * u_xlat1.xxxx + u_xlat2;
u_xlat2 = hlslcc_mtx4x4unity_MatrixVP[2] * u_xlat1.zzzz + u_xlat2;
u_xlat1 = hlslcc_mtx4x4unity_MatrixVP[3] * u_xlat1.wwww + u_xlat2;
gl_Position = u_xlat1;
saturate
// saturate
#ifdef UNITY_ADRENO_ES3
u_xlat0.x = min(max(u_xlat0.x, 0.0), 1.0);
#else
u_xlat0.x = clamp(u_xlat0.x, 0.0, 1.0);
#endif
大小比较
// bool a = b < c.x;
#ifdef UNITY_ADRENO_ES3
u_xlatb1 = !!(u_xlat16_14<u_xlat16_0.x);
#else
u_xlatb1 = u_xlat16_14<u_xlat16_0.x;
#endif
变量
精读
uniform mediump float -> half (中等精读)
输入输出
in mediump vec4 in_POSITION0;
in mediump vec3 in_NORMAL0;
in mediump vec2 in_TEXCOORD0;
// 对应 unity
struct appdata_t
half4 vertex : POSITION;
half3 normal : NORMAL;
half2 texcoord : TEXCOORD0;
;
输出
out mediump vec2 vs_TEXCOORD0;
out mediump vec3 vs_TEXCOORD1;
// 对应 unity
struct v2f
half4 vertex : SV_POSITION; // unity 必要的属性
half2 texcoord : TEXCOORD0;
half3 tex02 : TEXCOORD1;
;
uniform
uniform vec4 _WorldSpaceLightPos0; // unity 内置的世界空间下的 灯光位置
uniform mediump vec4 _Tint;
uniform mediump vec4 _ColorLight;
uniform mediump vec4 _ColorUnlight;
uniform mediump float _SplitThreshold;
// 对应 unity
_Tint("Tint", Color) = (1,1,1,1)
_ColorLight("ColorLight", Color) = (1,1,0,1)
_ColorUnlight("ColorUnlight", Color) = (0,0,0,1)
_SplitThreshold("SplitThreshold", float) = 1
half4 _Tint;
half4 _ColorLight;
half4 _ColorUnlight;
half _SplitThreshold;
实例01 - 雀魂
房间打牌示意图
测试 shader git 地址: git@gitee.com:yangxuan0261/tdmj_shader.git
主要看的是一下几部分的处理
- 向光/背光 部分
- 描边
- 阴影
1. 先找出牌牌体的渲染
直接修改 fs rgb 值为某个值, 就很容易找到牌体的渲染批次
可以看到 牌体的渲染 和 描边分开的
2. 描边
将牌体放大, shader 处理时剔除掉正面, 只渲染背面, 由于深度关系, 被正常牌体遮挡住, 描边效果就出来了.
而且所有这种牌体放大的模型也可以一个批次处理完成.
3. 阴影
以上是关于unity-shader-游戏渲染效果逆向分析的主要内容,如果未能解决你的问题,请参考以下文章
我的渲染技术进阶之旅OpenGL ES 使用表面剔除和深度测试解决渲染3D模型的时候,出现背面黑点的问题
我的渲染技术进阶之旅OpenGL ES 使用表面剔除和深度测试解决渲染3D模型的时候,出现背面黑点的问题