GPU_GEMS_自然态_渲染水焦散


前言

第二篇,我看了下比上一篇短一点
b( ̄▽ ̄)d 直接正题罢。


一、简介

在这里插入图片描述
焦散是指当光线穿过一个透明物体时,由于对象表面的不平整,使得光线折射并没有平行发生,出现漫折射,投影表面出现光子分散。

焦散是由从曲面反射或折射的光线产生的,因此仅聚焦在接收表面的某些区域。

本章的目的是展示一种用于渲染实时焦散的新技术,从物理基础到实现细节描述该方法。以美学体验为导向,不刻意遵守真实的物体细节。

二、数学物理依据

计算水下焦散是一个复杂的过程,涉及数以百万计的单个光子,并发生许多相互作用。

在这里插入图片描述
在折射下会有:
在这里插入图片描述
假设入射、透射和表面法线是共面的:
在这里插入图片描述
在折射之后,光子随着深入,有一些会减弱,但有一些会打到海底。海浪形成的各种透镜会造成聚集光的效果。

从模拟的角度来看,焦散通常通过正向或反向光线追踪来计算。

有两种实现光线追踪的方法:

  • 前向光线追踪,计算从光源打出来的
  • 后向光线追踪,试图计算给定点的所有入射光的总和,理想情况下,这将通过求解来自被照亮点上方的所有光的半球积分来实现(可以看games101)。原理大概是,从被打中的点出发,向外发送射线,只有那些实际上最终击中光源的光线才对焦散有贡献,其余的光线只是作为错误假设而被丢弃。
  • 但是我们两种方法都没有用:只有一小部分计算时间有助于最终结果。在商用焦散处理器中,有用光线与总光线的比率通常在 1% 到 5% 之间。
  • 我们的方案:光线从太阳追踪到波浪网格中的每个顶点。这些光线使用斯涅尔定律折射,因此产生了新的光线。

三、理论方法

我们用来模拟水下焦散的算法只是上一节中解释的反向蒙特卡洛光线追踪思想的简化。

我们只计算到达光源的一个子集。因此,该方法具有非常低的计算成本。

这是子集的筛选条件:

  • 我们假设我们在中午计算赤道上的焦散。这意味着太阳就在我们的正上方。
    在这里插入图片描述
    太阳距离地球的距离在 147 到 1.52 亿公里之间,具体取决于一年中的不同时间,它的直径为 142 万公里,太阳光照射的夹角为 0.53 度。
  • 海底被感照射点上方垂直发出的光线照亮。水的透明度在每延米 77% 到 80% 之间,因此每米有 20% 到 23% 的入射光被介质吸收,用于加热。
  • 从逻辑上讲,这意味着当光线从进入水中到到达海底的那一刻传播最短距离时,形成焦散最清晰。因此,焦散对于垂直光线而言将是最大的,并且对于侧向进入水中的光线而言将不那么可见。

在这里插入图片描述

  • 我们从制作完成地平面之后开始。使用第二个加法混合通道在其上渲染焦散。为此,我们创建了一个与波浪网格具有相同粒度的网格,并将使用焦散值按顶点着色:0 表示无光照;1 表示一束非常聚焦的光击中海底。为了构建这种照明,使用了反向光线追踪:对于我们网格的每个顶点,我们将其垂直投影,直到到达位于其正上方的顶点。然后,我们使用有限差分计算波在该点的法线。使用矢量和法线,并使用 Snell 定律(水的折射率为 1.33),我们可以创建从波传播到空气中的次级射线。这些射线是为海底带来照明的潜在候选者。为了测试它们,我们计算了每一个与垂直线之间的角度。因为太阳距离很远,我们可以简单地用这个角度来衡量照度:越接近垂直方向,从那个方向射入海洋的光就越多

五、实际方法

1、OPENGL

伪代码:
1、画海底。
2、对于网格中的每个顶点:

  • 发送垂直射线。
  • 将射线与海洋表面的网格碰撞。
  • 逆向使用斯涅尔定律计算折射光线。
  • 使用折射光线计算“太阳”贴图的纹理坐标。
  • 将纹理坐标应用于更精细网格中的顶点。

3、渲染海洋表面。

2、HLSL

(我今天才知道HLSL是高级渲染语言的简称)

计算每个像素而不是每个顶点的焦散可以提高整体视觉质量,并将效果与几何复杂性解耦。

有两种方法把这个过程从顶点着色器转换到像素着色器上,两种都使用波函数的偏导数来生成法线

  • 第一种方法利用程序纹理可以在屏幕空间中渲染这一事实,从而在只有一小部分像素可见时节省渲染时间。但是可见的像素多了,效率就低了
  • 第二种方法是在纹理空间中渲染到固定分辨率的渲染目标。尽管在纹理空间中渲染具有在每一帧保持恒定工作负载的优势,但仅渲染可见像素的好处就失去了。此外,很难衡量哪种渲染目标分辨率最适合当前场景。

该效果计算了波函数的法线,以追踪射线的路径到平面上的截点——在本例中为海底。为了生成法线,可以很容易地找到波函数在x和y中的偏导数。请注意,这种方法允许我们拥有一个不平的海底面,并且这个可变深度可以很容易地编码为顶点属性的标量分量。

波函数:
在这里插入图片描述
其中i表示用于生成波的阶数(翻译为八音度?这个英语我没太懂);c 1、c 2和c 3是常数,分别给出波的频率、幅度和速度;x和y的取值范围为 0 到 1(含),合起来表示单位正方形上的一个点。

得到偏导数:
在这里插入图片描述
在这里插入图片描述
偏导数实际上是切线在计算点的分量。因为该函数实际上表示高度或z ,所以关于z的偏导数只是 1。法线是切线向量的叉积,
在这里插入图片描述
渲染焦散线所需的最后一个方程是线到平面的截距。我们可以使用以下方法计算从一条线上的一点到平面上的交点的距离:
在这里插入图片描述
在这里插入图片描述
代码:

 float4 main(VS_OUTPUT vert,              uniform     sampler2D LightMap : register(s0) ,              uniform     sampler2D GroundMap : register(s1) ,              uniform     float Timer) : COLOR {    // 从波函数的梯度生成法线(线方向)和     与水平面拦截。     // 我们使用屏幕空间 z 来衰减效果以避免混叠。     float2 dxdy = gradwave(vert.Position.x, vert.Position.y, Timer); 
 
  float3截距 = line_plane_intercept(vert.Position.xyz,                        float3 (dxdy,饱和(vert.Position.w)),                         float3 (0, 0, 1), -0.8); 
  // 输出     float4颜色;colour.rgb = ( float3 ) tex2D (LightMap, intercept.xy * 0.8); colour.rgb += ( float3 ) tex2D (GroundMap, vert.uv); 颜色.a = 1;   返回颜色;}

总结

焦散比我想的短

猜你喜欢

转载自blog.csdn.net/woshi_wst/article/details/125743959