如何使用端游工具分析外部Android手游渲染

发表于2016-04-13
评论1 1.21w浏览
一、写在前面
  我只有6年的端游开发经验,除了业余时间捣鼓一下手游开发,没有在工作中实际的参与手游开发。所以,下面的分析过程,更多的是从端游的角度去分析手游的渲染流程。Nsight和GPA的用法就不详细介绍了,可能会跳过许多的操作步骤。

二、摘要
  最终结果使用NSight截取了一帧Android游戏,存储,回放都没有问题,所有的渲染资源,包括模型,贴图,Shader,调用序列都能正确还原。下面的截图,是"乱斗西游" 初始关卡的场景。


  GPA也可用于分析,但是会有一部分的渲染资源无法还原。下面的截图,也是乱斗西游" 初始关卡的场景。


三、过程
1、软件准备
  Intel GPA, NVIDIA Nsight, BlueStacks
  没有去仔细试过每一个软件的版本兼容性,我这里的环境是,Intel GPA 2014 R2,NSight 3.2,BlueStacks 0.98.
2、截取BlueStacks的渲染帧
  NSight
a、无法直接使用VS的启用External Program附件NSight上去, 而是需要使用NSight Hud附加。


b、启动后,已经可以看到Nsight附加,此时已经可以看到绘制信息


c、Ctrl+Z, Space, Save Capture
  Save Capture的目的有两个,1.是为了在VS中打开,拥有更详细的渲染信息,例如Shader信息,模型信息; 2. 是为了能够以后直接起动截帧就好,无需再次启动游戏.
  如果满足与查看一下贴图和渲染序列,那么此时已经可以达到要求,此时可以像PerfHud一样,拖动时间轴,浏览Draw Call


d、找到Save的帧(Nsight Save的帧其实是一个D3D工程),一般的路径在¥Documents¥NVIDIA Nsight¥Captures, 在VS里添加工程


e、此时工程可以编译通过,但是无法运行,一旦运行就会退出,可能会有各种原因,但是问题目前已经回到了一个基础的D3D程序范畴。
  针对我这个版本的截帧,需要手动修改一下CPP文件,因为生成的CPP多创建了一个Windows窗口,注释掉他


f、重新编译工程,再运行,就是一个Native的D3D程序了:


g、此时已经可以想调试D3D Native程序一样调试它了。


h、简单分析一下主地表的绘制吧


  贴图和模型就不细说了,主要看看Pixel Shader,主要是比较简单,实例足够了:
//
// Generated by Microsoft (R) HLSL Shader Compiler 9.30.9200.20499
//
// Parameters:
//
//   sampler2D _SamplerDiffuse0;
//   sampler2D _SamplerLightmap1;
//   float _blendValue;
//
//
// Registers:
//
//   Name              Reg   Size
//   ----------------- ----- ----
//   _blendValue       c3       1
//   _SamplerDiffuse0  s0       1
//   _SamplerLightmap1 s1       1
//
    ps_3_0
    dcl_texcoord v0.xy
    dcl_texcoord1 v1.xy
    dcl_2d s0
    dcl_2d s1
    texld r0, v1, s1
    texld r1, v0, s0
    mul r0.xyz, r0, r1
    mul oC0.w, r1.w, c3.x
    add oC0.xyz, r0, r0
// approximately 5 instruction slots used (2 texture, 3 arithmetic)
  我们可以看到,BlueStacks已经把GLSL的Shader ASM转成了HLSL的Shader ASM了,变量名之类的都保留了。
  Shader ASM的阅读肯定会比直接的Shader效率会低,HLSL 的 Shader ASM可以参考下面的文章:
  https://msdn.microsoft.com/en-us/library/windows/desktop/bb219840(v=vs.85).aspx
  我们看到他的Pixel Shader, 使用了一个BlendValue,c3. 为 1,通过参数表可查:


  DiffuseMap的W分量都为1


  所以OutputColor.w = DiffuseMap.W x 1 = 1
  而RGB Color的输出却比较奇怪,输出的颜色是两倍DiffuseColor X LightMap:
  OutputColor.RGB = Diffuse  X LightMap + Diffuse  X LightMap.
  仔细查看了一下光图的数值,发现这样相加并不会溢色,因为即使光图中最亮的部分,他的值都小于<0.6.


  只是觉得,直接把光图的亮度提高一倍就可以解决这个问题,不知道为什么Shader里多加了一次。
关于上面的乘以2的问题,在unity的论坛有关于它的讨论,大概的原因是为了兼容unity以前的版本所以才这样做的,后面的unity5里已经去掉了。

四、GPA截取
1、GPA的截取比较快捷,直接勾上Auto-Detect选项,然后双击运行游戏


2、截取帧并分析,Ctrl+Shift+C后,截取一帧,并打开:


3、我们看到丢失了一部分Draw的信息,例如后半段UI的绘制过程,他直接变成了一个DrawCall


  实际的绘制其实不是这样的,NSight的截取的帧里的UI绘制信息是正确的,如下图,并不是一个全屏的DrawCall:


五、总结
  所以,通过端游方法分析PC上运行的Android游戏,方法上是可行的,所有的渲染信息几乎都保留了下来,可以方便的参考原型,制作美术规范等工作。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引