• 真实感海洋的绘制(三):水面的渲染


    真实感海洋的绘制(三):水面的渲染

    之前的两篇博客:

    1. [真实感海洋的绘制(一):基于统计学模型的水面模拟方法][http://www.cnblogs.com/hehao98/p/8544121.html]

    2. [真实感海洋的绘制(二):使用快速傅里叶变换加速波形计算][http://www.cnblogs.com/hehao98/p/8604163.html]

    根据上述两篇博客,我们已经得到了真实感较高的水面波形和法向量。为了节省所需要的顶点数目,需要将高度场和法线制作成贴图传入着色器,以便从较少的顶点就能渲染很大面积的海面。之后的任务就是对这些波形进行真实感的渲染。

    基本原理

    首先,高度真实感的、基于真实物理的水面光照模型相当复杂,即使能够用计算机计算,也几乎不可能实时地完成。因此,现有的实时水面渲染方法基本不会使用此类模型。本文的方法将采用只计算一次反射和折射的简单模型。

    首先我们先画出高中物理中的反射和折射模型:

    其中,(vec{v_i})是入射光向量,( heta_i)是入射角,(vec{v_r})是反射光向量,( heta_r)是反射角,(vec{v_t})为折射光向量,( heta_t)是折射角,(vec{n})是法线向量。其中,入射角和反射角相等。根据斯涅尔定律(Snell's Law),入射角和折射角满足如下关系

    [n_isin heta_i=n_tsin heta_t ]

    其中,(n_i)(n_t)分别为入射介质和折射介质的折射率,对于空气而言,(n_i=1.00),对于水而言,(n_t=1.33)(近似值)。

    以上讨论反映了在表面某一点的反射情况和折射情况。如果要知道这一点反射了哪里的光,可以从观察点开始做一层光线追踪,也就是假设摄像机在(vec{v_r})所指向的位置,反向计算出(vec{v_i})。之后我们必须计算出(vec{v_i})光的颜色。一般的实现方法是把四周的场景预计算,存储为环境贴图,然后就可以根据(vec{v_i})向量值来计算出这一点的入射光颜色。对于开阔的海面而言,被反射的自然就是天空了。如图所示。

    当然,水面并不是一面完美的镜子。射入水面的入射光,一部分反射了回来,另一部分在折射后进入了水面,与此同时,在水面处也有从水面下经过折射后又反射回来的光。在无限大的水面中,我们可以不考虑水下反射光的复杂性,单纯将其假设为某种固定的颜色。

    对于水面上任何一点,最终摄像机收到的颜色是反射环境的颜色和折射出的水下颜色之和。对于不同的入射角( heta_i),入射光反射的比例(R)和折射进入水面的比例(T)是不一样的,但是满足(R+T=1)。这在物理上被称作费舍尔效果(Fersnel Effect)。利用电磁学理论我们可以推导出(R)有如下的关系

    [R=frac{1}{2}{frac{sin^2( heta_t- heta_i)}{sin^2( heta_t+ heta_i)}+frac{ an^2( heta_t- heta_i)}{ an^2( heta_t+ heta_i)}} ]

    当从空气进入水的时候,入射角为0度时(R=0),然后随着角度变大而变大,当入射角为90度时(R=1)。当从水进入空气时则存在全反射的现象,当入射角大于某个角度后就会全部反射,没有折射。

    因此,对于水面任意一点,我们得到简单的颜色计算公式

    [Color = R * Color_{incident} + (1 - R) * Color_{deepWater} ]

    就可以完成水面的着色。

    一些美化

    显然,由于计算资源的限制,我们是不可能高精度绘制无限大的海面的。为了节省计算资源,一种方法是使用LOD技术(Level Of Details),让近处的网格顶点密度高、远处的顶点密度低。如果有时间的话之后我会研究一下各种LOD技术。在这里,我们先使用一个偷懒的方法:加入薄雾。一方面可以遮挡住远处顶点网格的空缺,另一方面可以适当设置雾的颜色以便在远处和天空盒融为一体,最终能够获得足够好的视觉效果。

    要在计算机中实现雾其实非常简单。雾可以视为一种叠加在已有物体上的颜色,这个颜色随着距离变远而加深,从而在有雾的场景中,一个像素点的颜色可以表示如下

    [Color = (1 - F(d)) * Color_{object} + F(d) * Color_{fog} ]

    其中,(F(d))是雾的参数函数,(d)是这个片元像素距离摄像机的距离,通过选取适当的参数函数,我们可以模拟出比较逼真的雾效果。我选取的参数函数如下

    [F(d)=1 - e^{-cd} ]

    相信学过高中数学的读者都能画出这个函数的图像。其中,(c)是一个常量,其值越大,雾越浓,适当地调整参数可以获得我们想要的效果。

    此外,为了和天空盒的远处相融合,我们需要利用摄像机到片元的方向来取值,从天空盒边缘取得适当的颜色来产生真实的雾效果。

    实现结果

    代码可见[https://github.com/hehao98/OceanSimulator]




    参考文献

    1. Tessendorf, Jerry. Simulating Ocean Water. In SIGGRAPH 2002 Course Notes #9 (Simulating Nature: Realistic and Interactive Techniques), ACM Press.
    2. Johanson, Clase. Real-time water rendering - Introducing the projected grid concept. Master of Science Thesis. Lund University
    3. Toman, Wojciech. Rendering Water as a Post-process Effect. https://www.gamedev.net/articles/programming/graphics/rendering-water-as-a-post-process-effect-r2642/
  • 相关阅读:
    vscode maven
    clojure + sumblime text SublimeREPL
    .zsh_history
    springboot-自动装配
    任务调度-Quartz
    springcloud alibaba
    canal与kafka的结合使用
    centos7安装Zookeeper
    centos7安装kafka
    vmware+centos7 设置静态ip
  • 原文地址:https://www.cnblogs.com/hehao98/p/8709636.html
Copyright © 2020-2023  润新知