zoukankan      html  css  js  c++  java
  • 正当防卫2 渲染技术

    引用:http://blog.csdn.net/ccanan/article/details/7935183

    http://www.humus.name/Articles/Persson_CreatingVastGameWorlds.pptx

    http://www.humus.name/Articles/Persson_GraphicsGemsForGames.pptx

    humus在siggraph12上做的关于just cause 2的渲染技术的分享,这里并不像voxel cone tracing里面会讲一个大的,一脉相承的道理,主要是各种游戏开发过程中很实用的一些做法,非常不错。

    游戏的一些特点:

    • 大:32kmx32km
    • 动态:动态的天气,日夜变化,各种气候
     
    远处的点光源

    使用sprite emissive来做,可以大量使用,非常高效
     
    浮点数计算
    浮点数的精度问题的确让人比较头痛,绝大多数是对的,%0.9有一定不太能忍的误差,%0.1的会出现明显错误。
    比如这个代码:

    uint32fixed_zs=(uint32(16777215.0f * depth + 0.5f) << 8) | stencil;

    如果depth是1,返回的最终结果不是我们预想的0xffffffff,而是0,因为浮点数的精度问题,在16777215.0f这个数量级上,加0.5f会变成16777216.0f,而不是16777215.5f。

    这里humus列了一个浮点数精度的一个表:


    所以很自然也就引出了float的积累误差的问题,基本道理就是所有的计算,尽可能减少中间步骤,具体到实际的example,包括:

    • 不要localPos乘以worldMatrix,然后乘以viewProjMatrix,最好能直接乘以MVP matrix
    • 尽量不要去invert matrix,如果不得不如此的话,去构建inverse matrix
      • 比如基于translation,scale, rotation的矩阵的inverse,完全可以使用-translation, 1/scale, -rotation来重新构建
    depth buffer的精度
    just cause2使用了reverse depth buffer,也就是near是1,far是0,
    在console上,使用的是24float的depth buffer,那么绝对值越小,float精度越高,这个很明显的会在远处的depth精度上受益。
    在pc上,使用的24bit定点数的depth buffer,定点数其实也会从reverse depth buffre中受益,因为浮点数的积累误差发生在vertex shader计算中,如果使用reverse的,那么精度也会更好。
    当然24bit depth定点数的buffer本身的精度表示能力在reverse还是正常的都是一样的。
     
    shadows
    • 使用3级的cascaded shadow map
    • 3个light view depth,pack到一个buffer上,这样一个sample就可以搞定
    • 使用snapping防止像素抖动,(http://blog.csdn.net/ccanan/article/details/7391961,这里也记录过cryengine也有同样的做法)
    • 在cascade之间使用了dither来过渡自然
    • 在不同的cascade中,设置object投射到屏幕空间的像素数量的阀值,小于这个阀值的就skip,这样远处的cascade可以提出大量的物件,进而提升效率
    • 大量的tweak,在直升机上的时候的shadow的参数和地上跑的时候完全不同,这一点是程序和美术一起猛调
    现存的优化
    • 3张luminance的texture,会pack到一个dxt1的texture里面
    • vertex format压缩
    vertex shader里的压缩
    这部分亮了,首先是定点压缩,读这个paper之前知道的最好的压缩是:http://blog.csdn.net/ccanan/article/details/7172940,8byte搞定tbn矩阵。
    just cause2使用的是4byte(狠!)
    存角度:
    1.   
    1. <span style="font-family:Microsoft YaHei;">float4 angles=In.Tangents*PI2-PI;  
    2. float4 sc0,sc1;  
    3. sincos(angles.x,sc0.x, sc0.y);  
    4. sincos(angles.y, sc0.z, sc0.w);  
    5. sincos(angles.z, sc1.x, sc1.y);  
    6. sincos(angles.w, sc1.z, sc1.w);  
    7. float3 tangent   = float3(sc0.y * abs(sc0.z), sc0.x * abs(sc0.z), sc0.w);  
    8. float3 bitangent= float3(sc1.y * abs(sc1.z), sc1.x * abs(sc1.z), sc1.w);  
    9. float3 normal    = cross(tangent, bitangent);  
    10. normal =(angles.w>0.0f)?normal:-normal;</span>  
    just cause2里面也用了一些quaternion的压缩方式:这个crytek也用了:解压方式略有不同
    1. <span style="font-family:Microsoft YaHei;">void UnpackQuat(float4 q, out float3 t, out float3 b, out float3 n)  
    2. {  
    3.   t = float3(1,0,0) + float3(-2,2,2)*q.y*q.yxw + float3(-2,-2,2)*q.z*q.zwx;  
    4.   b = float3(0,1,0) + float3(2,-2,2)*q.z*q.wzy + float3(2,-2,-2)*q.x*q.yxw;  
    5.   n = float3(0,0,1) + float3(2,2,-2)*q.x*q.zwx + float3(-2,2,-2)*q.y*q.wzy;  
    6. }  
    7.   
    8. float4 quat = In.TangentSpace * 2.0f - 1.0f;  
    9. UnpackQuat(rotated_quat, tangent, bitangent, normal);  
    10. </span>  
    然后一般都是tbn的空间转换,是先解压成3个float3,然后和矩阵做运算,just cause2使用的是quaternion和矩阵做运算,然后解压,可以节省8个指令。

     

    particle trimming

    10年来,几项关键指标的变化,可以看出bandwidth和rop是变化最小的。

    particle一直是消耗ROP的大户,使用接近贴图的非矩形来做particle的geometry,降低覆盖的pixel shader计算。


    最右边的使用8个顶点来trim的情况,已经可以可以把面积减少到原来的%59.

    有专门的工具来自动的进行trim。

     

     

    draw call

    节省drawcall这件事情在2003年有一个文章<batch!batch!batch!>很大声的讲了,但是到了2012年,已经不是这么回事了。

    在pc上,driver model已经非常快了,尤其是在win7和dx11搭配的时候,drawcall的汇编指令是5条,而且里面没有call,是一个jmp,会立即返回。

    在dx9上,还是有点小费,不过已经和我们早先听说的严重程度大不相同了,所以是否instancing的确要认真考虑,而且instancing在gpu里面会消耗更多的性能,在cull的时候会造成很大麻烦,时过境迁也。

    culling

    使用的brute force的cull,其中使用了simd指令。

    just cause 2认为,基于hierarchy的场景管理虽然理论剔除会更高效,但是其中的执行过程非常的不cache友好,而且大量的branch会把节省的性能都吐回去。

    而且hierarchy的维护和实现都麻烦和复杂很多。

    最后just cause2选择的是bruce force box cull。

    话说这个在之前项目里也发生过,一个哥们想测试四叉树到底比暴力做(还没用simd呢)快多少,结果是暴力更快,当然里面四叉树由于疏于维护,性能也不好。

    cull的时候也用到了一些occluder,是美术摆进去的一些box,在大山里面,在大的建筑里面。。。

     

    其他:

    动态降resolution,会从720p逐渐降resolution,最低640p,群众表示比较ok。

    shader performance script,这个会在相关的changelist上面,把shader的消耗(register num, instruction num。。。)和之前的版本做比较。

    了解gpu的指令集,可以让shader写的更快更好。

    要掂量掂量下自己的水平,不要做不成熟的优化和“高瞻远瞩”,很多预先的为以后的事情做出的设计会带来问题。

    细线AA:对于很细的东西,会有比较严重的Alias情况,这里使用一个避免subpixel的方法来达到一个很不错的AA的算法:

    在vertex shader里面把线所处的位置clamp到一个pixel的中心:


    code:

    1. // Compute view-space w  
    2. float w = dot(ViewProj[3], float4(In.Position.xyz, 1.0f));  
    3.   
    4. // Compute what radius a pixel wide wire would have  
    5. float pixel_radius = w * PixelScale;  
    6.   
    7. // Clamp radius to pixel size. Fade with reduction in radius vs original.  
    8. float radius = max(actual_radius, pixel_radius);  
    9. float fade = actual_radius / radius;  
    10.   
    11. // Compute final position  
    12. float3 position = In.Position + radius * normalize(In.Normal);  
  • 相关阅读:
    Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ext JS之验证码
    ABP前端使用阿里云angular2 UI框架NG-ZORRO分享
    ASP.NET Core之跨平台的实时性能监控(2.健康检查)
    应用程序的8个关键性能指标以及测量方法
    ASP.NET Core之跨平台的实时性能监控
    浅析Entity Framework Core2.0的日志记录与动态查询条件
    开发短网址平台的思路
    Nginx解决错误413 Request Entity Too Large
    配置Nginx实现负载均衡
    Windows下Nginx的安装及使用方法入门
  • 原文地址:https://www.cnblogs.com/sode/p/2707032.html
Copyright © 2011-2022 走看看