资讯详情

3D渲染技术分享:实时3D水面渲染(反射、折射、水深与水岸柔边)

一、开篇

自从上次写了**实时反射Shader增强画面价值** 之后,许多开发者开始尝试用它来渲染水面,但效果并不令人满意。

这是因为除了反射,还有很多细节需要考虑。

在此之前,许多开发者提到了水渲染的需要,许多开发者分享了一些关于水渲染的信息 ,但更集中在卡通着色方向。

水面渲染在3D项目需求量很大,毕竟地球表面水面约占 70.水面效果很难避免8%。

最近的引擎团队 老板还分享了水渲染效果,包括 许多其他实时渲染技术。

但该 基于 延迟渲染管道对项目和设备有很高的要求,所以麒麟子专门准备了这种独立的水效果共享,希望对大家有所帮助。

二、水面渲染工艺

水面渲染技术很多,不同部位的产品对水面有不同的要求。

毛星云的 在本文中,通过对一些3A分析了大作的水面渲染,列出了许多技术要点,感兴趣的朋友可以阅读。

从简单到复杂,水面渲染技术可分为以下三类:

本文实现的是 虽然水面效果不是高端效果,但大部分都是 项目中使用的方案。

基于平面着色的水面渲染主要涉及以下部分:

  • 法线图和光线
  • 岸边浪花

由于时间关系, 暂未实现。

如下所示:

可以看出,要达到所有的效果,至少需要绘制场景 次。

因为这里的深度图只和折射一起使用, 位精度足够,我们可以考虑使用折射图 存储深度信息的通道。

优化后的流程图如下:

三、反射贴图渲染

麒麟子写的另一篇文章 实时反射的相关原理已经完全分析,这里就不再敷述了。需要了解的读者可以查看麒麟子的媒体号。

这里主要讲一讲本 实现步骤。

用代码新建一个

创建节点,添加相机组件,并将 属性与主摄像头同步。

设置反射摄像头的渲染优先级,确保比主摄像头先渲染。

将新创建的 给相机赋值 属性。

以上步骤的代码在 中间,如下图所示:

主摄像机参数中同步。

根据实时反射原理,动态计算主摄像头的镜像位置和旋转。

最后,渲染得到了 如下:

所有物体的材料都需要添加自定义的切割面来切割水面以下的部分。 可以明显看到,上图中倒影,水下部分被切断。

四、折射贴图渲染

折射渲染的原理很简单:

折射渲染的过程与反射渲染大致相同,只有两个小区别:

下面我们来看看,本 折射的实现步骤。

用代码新建一个

创建节点,添加相机组件,并将 属性与主摄像头同步。

设置反射摄像头的渲染优先级,确保比主摄像头先渲染。

将新创建的 给相机赋值 属性。

上述步骤的代码在 中间,如下图所示:

注意红色线框部分,本 折射贴图 标记通道,因此需要保证 通道的值为

主摄像机参数、位置、旋转等信息中同步。

最后,渲染得到了 如下:

五、水面渲染

水渲染主要采用投影纹理技术,将顶点投影坐标转化为UV,采样折射和反射贴图。

由于折射贴图的使用,我们的水面材料不需要打开 Alpha 混合。

折射渲染

屏幕根据投影坐标计算UV。如下所示:

采样折射贴图可获得以下渲染效果:

左边是正常的渲染效果,右边是标记折射内容的效果

使用噪声图扰动折射,可获得以下效果:

反射渲染

屏幕是根据投影坐标计算的,就像折射渲染一样UV。

采样反射贴图可获得以下渲染效果:

用噪声图扰动反射,可以得到以下效果:/>

菲涅尔混合

菲涅尔的计算公式从玉兔的边缘光教程开始,到实时反射等场合,已经出现过很多次了。下面是核心代码:

折射可以视为水体本色,利用菲涅尔因子与反射内容混合,即可实现一个带折射和反射的水体效果。

伪代码如下:

最终可以得到如下显示效果:

完整代码代码请查看项目中的 文件。

六、水深效果

从上面的动画中可以看出,虽然折射和反射效果都有了。但画风有些奇怪,完全没有水面的感觉。

我们来看看,如何获取深度信息,并根据深度信息实现水深效果。

获取深度信息

从上图中,我们可以清晰地看到,靠近岸边的海水的颜色比远处海水的颜色透明得多。

产生这种现象的主要原因,就是 不同。

什么叫基于视线方向的水体厚度,请看下图:

我们通常说的水体深度,是指在忽略视线因素的情况,水面到水底的高度差。

在不追究细节的情况下,我们可以简单地使用高度差来作为水的深度。

一种可能的伪代码如下:

其中 是我们的深度缩放因子,可以用来调节比例尺问题,以及水体能见度线性衰减速率。

而基于视线方向的水体厚度,是指视线方向与水平面和水底交点的距离差。 即图中 点 到 点 的距离。

下面我们来推导一下,使用 来作为深度因子的公式。

许多朋友第一反应是解直线方程,但用的特性来求解会更容易。

为方便对照理解,再贴一次上面的图:

设观察方向为 ,厚度为 则有:

分拆为分量运算可得:

P1.x + viewDir.x * depth = P2.x

P1.z + viewDir.z * depth = P2.z

可推导出:

由此可得如下计算公式:

比起直接使用水体深度来说,多了一次求 单位向量的运算,以及一次除以 运算。

在非极端情况下,多出的这一点纯逻辑运算在 上是可以忽略不计的,可以放心使用。

将上述公式添加到渲染对象的 中,并在折射渲染阶段启用,将结果存入 通道即可。

项目中的 代码如下图所示:

最终得到的深度信息如下:

深度混合

有了上面的深度信息,我们只需要在计算出折射颜色后,再用深度信息与水底颜色混合即可。 代码如下图所示:

由于水体的可见度是非线性的,所以对 使用了 函数,这个 参数默认是

最终可以得到如下效果:

六、水岸柔边

当我们把摄像机拉近,观察水面与物体交接处的时候,可以明显看到一条清晰的边界。

这条边界在反射越强的时候越明显,使我们的水面效果大打折扣。

好在我们已经有了深度信息,可以根据深度来判断出哪里靠近岸边,并修改菲涅尔因子,使反射越靠近岸边的时候越弱即可。

核心代码如下:

最终可以实现在全反射的情况下,水面与岸边依然平滑过渡。效果如下图所示:

再来一张远视角的图:

七、动态天空盒

为了增强氛围感, 中使用了动态天空盒。

这是一个特别简单的高效的动态天空盒方案,仅使用了一个双层纹理混合的半球模型,调节两张纹理的水平方向流动速度即可。

八、关于DEMO

所有效果参数均可调节,如下图所示:

本DEMO可从 Cocos 资源商城获取:

https://store.cocos.com/app/detail/3645

标签: 本色连体二极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台