zoukankan      html  css  js  c++  java
  • 游戏中水的渲染技术系列一

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术具体解释》电子工业出版社等。

    CSDN视频网址:http://edu.csdn.net/lecturer/144

    水的渲染一直是图形学须要解决的问题,网上也有非常多关于这方面的技术实现,本博客的系列文章也是给读者做一个总结,本篇博客主要介绍用傅里叶变换算法实现的水反射,也是一种假反射效果,目的是优化效率。实现的效果例如以下图所看到的:


    使用傅里叶系数来表示地形高度的假反射效果,

    在我们开发的游戏中使用水着色器。告诉读者我将怎样利用引擎处理水的反射,我们自己开发水渲染效果,须要在优化方面考虑,计算每帧渲染时间。

    我们要处理渲染简化的低分辨率反射地图。由于我们还要渲染对于流动的水平面。

    算法的实现事实上都是源于生活,大家假设平时出去旅游,经常会看到山丘的反射,近处反射的比較清晰。但在远处它仅仅是一个黑色的斑点。试想一下,假设我们能够记录每一个水点周围的水面上方的地形的角度,然后我能够在水着色器中使用这个反射光线,它应该是从“天空”过渡到“地形”的点。

    Spherical harmonics球面谐波是一种众所周知的技术,通经常使用于全局照明。

    非常简要地总结:每一个顶点存储一组预先计算的系数,这同意我们重建击中对象的环境光。这些系数基本上存储从每一个方向照耀该点的光的映射图。

    反射/环境光一般是非常低的频率。因此这是这些系数怎样包括这么“多”的信息原因。

    我决定用我引擎中的水尝试相似的技术。每一个顶点保存一组小系数,描写叙述地形在水上方环绕该点的每一个方向上升的角度。这能够用一个四元系列

    的系数来描写叙述 - 基本上是球面谐波的2d方程。当在顶点之间插值时,这些傅里叶系数就能够计算出来了,给读者展示一下效果图吧。


    在水上的一个点周围的採样方向上的各种角度。

    我们计算每一个水顶点的系数。这涉及每一个顶点的操作:

    1、在点周围选择  k个均匀间隔的採样方向。k的值仅仅影响计算,因此您能够将其设置为一定

    的高以实现其仿真度,我眼下使用13。


    2、对于每一个採样方向,运行光线跟踪。一次运行一个高度地图像素。測量水面上方的地形角度。

    你想要精确的反射取决于你离岸的距离,在本文的演示样例应用程序中。我眼下使用5个像素。

    假设你的游戏涉及从低水平面的不同的水观察视角,你将须要使用很多其它(后面很多其它)。


    3、如今我们有一个函数(每2π循环)表示点周围的地形高度。


    4、为了获得表示该函数的傅里叶系数,我们须要对每一个系数的表达式进行积分计算,确切的表达式能够在网

    上找到。我使用数值积分,分辨率为400(比如每一个函数400个样本),使用的数字仅影响计算。


     5、我计算前8个系数,这个数字直接影响效果的品质和性能。8对我的目的来说肯定够好了,当然我们会尽量降低。

    我把我的系数作为16位浮点存储在我的顶点结构中(因此每一个顶点占用16个字节)。

    在水着色器中。我使用反射向量来确定我设置的角度,代码例如以下:

    float3 reflectionRay = reflect(worldPosition - CameraPosition, normal);
    float angle = atan2(-reflectionRay.z, -reflectionRay.x) + PI;
    //这给出了0和2π之间的角度,然后我们能够使用它来查找地形高度。

    本文实现的傅里叶评估函数看起来像这样(t是角度):

    float EvaluateFourier(float t, float4 coefs1, float4 coefs2)
    {
      float4 sins;
      float4 coses;
      sincos(float4(t, 2 * t, 3 * t, 4 * t), sins, coses);
      float value = coefs1.r; // a0
      value += coefs1.g * coses.r; // a1
      value += coefs1.b * sins.r; // b1
      value += coefs1.a * coses.g; // a2
      value += coefs2.r * sins.g; // b2
      value += coefs2.g * coses.b; // a3
      value += coefs2.b * sins.b; // b3
      value += coefs2.a * coses.a; // a4
      return value;
    }

    方程给了我一个角度,这也是算法与编程结合的函数实现,然后我能够比較水面上的反射光线的角度,以确认我们是否应该绘制天空或反射的地形,

    眼下仅仅是使用黑色的反射地形,效果似乎满足需求假设我们想要更好的效果。还能够存储地形的颜色,除了高度。

    当然这将使所需的数据量添加

    四倍。

    那它是怎样工作的呢?

    您能够查看本文顶部的照片作为演示样例。

    这里有一个版本号的顶点网格绘制。每一个顶点存储16字节的数据在我当前的实现。


    上图显示了我使用的顶点分辨率效果。

    在水面上使用的法线贴图有助于实现这样的假反射效果,实现的效果例如以下所看到的:


    以上实现的效果在性能方面也给读者分析一下。这也有助于读者优化Shader的渲染效果:

    上面给读者实现了一种假反射,以避免渲染昂贵的反射贴图,因此它须要具有高性能。不幸的是,这须要大

    量的着色器指令在我当前的实现中评估。

    atan2约有20条指令。HLSL产生4个标量sincos指令,其

    实际上每一个占用8个指令槽。总共,它为像素着色器加入了约64个指令槽。


    针对上述问题。我们的下一步任务是找到一种降低指令数量的方法。

    能够使用

    atan,然后是正弦和余弦。我能够通过做一些三角代替来降低这一点。或者我能够考虑使用e与虚数的幂的和来评估该系列。

    当然我们还能够降低系数的数量。

    另外。我将看到我能否够存储每一个系数在单个字节而不是16位浮点。

    最后总结一下,对于具有很多其它不同视图的游戏,这可能不是一个非常好的选择。还有这个技术的一个问题是它仅仅反射静态对象,

    地形,以及你决定在你的射线检測算法中包括的不论什么其它游戏元素。

  • 相关阅读:
    UVALive 7141 BombX
    CodeForces 722D Generating Sets
    CodeForces 722C Destroying Array
    CodeForces 721D Maxim and Array
    CodeForces 721C Journey
    CodeForces 415D Mashmokh and ACM
    CodeForces 718C Sasha and Array
    CodeForces 635C XOR Equation
    CodeForces 631D Messenger
    田忌赛马问题
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7338984.html
Copyright © 2011-2022 走看看