webgl 基础渲染demo_WebGL + ThreeJS 实现实时水下焦散 Part 1

v2-dcffb0ba43a8b1ac072a9b41de71f793_1440w.jpg?source=172ae18b
知乎视频​www.zhihu.com

采用 WebGL 和 ThreeJS 运行实时焦散运算,需要一点相关基础。本文主要介绍焦散的原理以及计算方法

原作者

https://github.com/martinRenou​github.com

代码和原文

https://github.com/martinRenou/threejs-caustics​github.com

由于本人的笔电还在维修中所以带中文注释的代码要后续补上了

什么是焦散 caustics

焦散是光从表面(在我们的情况下是空气/水界面)折射和反射时出现的光的模式。

由于在水波上发生反射和折射,水起了动态放大镜的作用,形成了这些光的图案。

v2-3f7c6d310f45f102b1d1c7f0cc46f4f3_b.jpg

本文中主要讨论由光的折射引起的焦散,主要是水下发生的事情。

为了能够得到稳定的 60 帧,使用 GLSL 编写的 shaders 在 GPU 上计算。

为了计算焦散,我们需要:

• 计算水面的折射光线(GLSL 中有内置函数)

• 求交算法,计算光线照射到环境的位置

• 通过检查光线会聚的位置来计算焦散强度

v2-38f3a694a587deee65a8bba80fee7f22_b.jpg

创建环境图

当涉及动态阴影计算时,一种众所周知的技术是阴影映射 shadow mapping。通常在视频游戏中使用,效果好且速度快。

阴影映射是一项两步运行的技术:

• 从光的角度看,3D 场景首先在纹理中渲染。 该纹理将包含所有片段的深度(光源和片段之间的距离),而不是包含片段的颜色。 此纹理称为阴影贴图 shadow map。

• 然后在渲染 3D 场景时使用阴影贴图。在屏幕上绘制片段时,我们可以从阴影图中知道光源和当前片段之间是否还有另一个片段。如果是这种情况,则该片段在阴影中,应该将其绘制得更暗一些。

可以对水体焦散运行类似的方法,首先在纹理中渲染水下环境,然后使用该纹理来计算光线与环境之间的交点。 除了渲染片段深度之外,还渲染了环境图中的片段位置,RGB 信道存储 XYZ 位置,alpha 信道存储深度:

v2-e8e6af5573f5f304597573cd9b7b9719_b.jpg

计算光线与环境的交点

现在有了水下环境图,需要计算折射光线与环境之间的交点。

算法如下:

1. 从光线与水面的交点开始

2. 使用折射函数计算折射

3. 从当前位置沿折射射线方向移动,环境图纹理的一个像素

4. 将存储在当前环境纹理像素中的环境深度与当前深度进行比较。如果环境深度大于当前深度,则意味着我们需要走得更远,因此我们再次运行步骤 3。如果环境深度小于当前深度,则意味着光线在您从中读取的位置击中了环境。

焦散纹理

一旦找到交点,就可以使用 Evan Wallace 在其文章中提到的技术来计算焦散强度(和焦散强度纹理)。 产生的纹理如下所示:

v2-ceb5f239ca2cb26c2f1909d6f3f2570c_b.jpg

该纹理包含 3D 空间每个点的光强度信息。当渲染最终场景时,我们可以从焦散纹理中读取此光强度,并得到以下结果:

v2-3d553ec26bb9b8a548c2479257ce80b1_b.jpg

其他

本文重点讨论焦散的计算,但此 demo 中还有其他技术。

关于水面渲染,使用了天空盒纹理和立方体贴图进行反射。还使用简单的屏幕空间折射(请参阅有关屏幕空间反射和折射的这篇文章)在水面上应用了折射,该技术在物理上不是正确的,但在视觉上吸引人且快速。 此外,添加了色差以提高真实感。


后续会介绍下前面焦散纹理的生成方法,以及简单解读下原代码以及 ThreeJS 的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值