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 的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337516.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python代码性能分析_使用memory_profiler对代码进行性能分析会增加执行时间

我正在编写一个简单的应用程序,它将大文本文件拆分为较小的文件,并且我已经编写了2个版本,一个使用列表,另一个使用生成器。我使用memory_profiler模块对这两个版本进行了概要分析,并清楚地显示了生成器版本的更好的内…

超硬核C++BestPractices翻译与阅读笔记

点击蓝字关注我们硬货开始这本书的副标题是:45ish Simple Rules with Specific Action items for better C ,这本书是由大佬推荐的, C学习有必要掌握一下这45条最佳实践, 可以很大程度上提升代码的可读性和健壮性, 而且这本书也不…

redis集成spring_将Redis集成到您的Spring项目中

redis集成spring本文介绍如何通过注释配置将Redis缓存集成到您的spring项目中。 我们将从Gradle配置开始。 我们将使用jedis驱动程序。 group com.gkatzioura.spring version 1.0-SNAPSHOTapply plugin: java apply plugin: eclipse apply plugin: idea apply plugin: spring…

Python3实现翻转二叉树问题

Python3实现翻转二叉树问题翻转一棵二叉树。# 二叉树的结构如下 class TreeNode:def __init__(self, x):self.val xself.left Noneself.right None# 解决方案 class Solution:# 从根节点开始递归翻转其左子树和右子树def invertTree(self, root: TreeNode) -> TreeNode:i…

diskgenius单文件专业版_金蝶KIS专业版系列——系统工具六(业务套打工具)

导读:(一)问一问1.1.套打的作用1.2.举例(二)怎么进入套打设计器2.1.入口12.2.入口2(三)怎么使用套打设计器打开套打模板3.1.打开系统标准套打模板3.2.新建一个空白的套打模板3.3.保存套打模板3.…

面试常问的16个C语言问题,你全会吗?

点击蓝字关注我们金三银四不少小伙伴在找工作,这里我给大家分享一下面试中经常会遇到的一些嵌入式C语言问题,你看看能做到全会吗?1、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题&#xff09…

高性能 高可用 可弹性伸缩_性能,可伸缩性和活力

高性能 高可用 可弹性伸缩本文是我们名为Java Concurrency Essentials的学院课程的一部分。 在本课程中,您将深入探讨并发的魔力。 将向您介绍并发和并发代码的基础知识,并学习诸如原子性,同步和线程安全性的概念。 在这里查看 !…

Python3实现32位整数翻转

Python3实现32位整数翻转给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。示例 1:输入: 123 输出: 321示例 2: 输入: -123 输出: -321示例 3: 输入: 120 输出: 21假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 […

iptables命令_程序员最有用的linux命令汇总

总结程序员在工作中,最有用的linux命令如下:1、vi/vim 我们须要在服务器上代码一些代码时候,就用vi/vim命令就可以,vim是vi的升级,本色自带代码高亮工具,利于查看。dd 删除光标所在行o 向光标所在行向下增加…

抽象类和接口设计_如何设计类和接口

抽象类和接口设计本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的旅程! 在这里查看 &#xf…

详解C++异常

点击蓝字关注我们1、异常概念异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。catch: …

Python3 反转一个单链表

Python3 反转一个单链表反转一个单链表。示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL解题: # Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val x # …

python怎么改字体_python,tkinter_Tkinter Label 如何改变Label中的文字样式,例如给文字加删除线,python,tkinter - phpStudy...

Tkinter Label 如何改变Label中的文字样式,例如给文字加删除线 如题。未查到Tkinter下,促发条件后,是否能修改label中文字的样式 class Pomodoro_app(Tk): def add_task(self): global time time StringVar() time.set("Start") t…

使用所有对象共有的方法

本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的旅程! 在这里查看 ! 目录 1.简…

C语言基础知识:指针与数组的区别是什么

点击蓝字关注我们在C语言教程中我们使用通过数组名通过偏移和指针偏移都可以遍历数组,那么指针和数组到底有什么区别??由于数组中的数据在内存中都是连续存放的,数组名默认就是数组的首地址,也是一个特殊的指针&#x…

Python3 三步爬楼梯问题

Python3 三步爬楼梯问题原题地址 https://leetcode-cn.com/problems/three-steps-problem-lcci/ 题目: 三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。…

python去重复功能_消除Python列表重复的几种方法,python,去,一些

做Python123平台上的列表去重题,复述题目: 去除列表中的重复元素,考虑以下几种情况: l [1, 1, 2, 3] l [[1], [1], [2], [3]] l [3, 2, 1, 1] 原文链接: 14025 总结一下网上的方法和我自己想的方法: 不考…

java java se_Java 8 SE可选,严格的方法

java java se大约两周前,Stephen Colebourne提出了使用Optional的实用方法 。 如果您阅读了它,您可能会从我以前的建议中猜到我不同意。 总览 我必须以免责声明开头,然后我将直接解释为什么我认为他的方法不那么理想。 所有不归因于他人的报…

std::thread 还有哪些使用“姿势”?

点击蓝字关注我们C11 线程创建每一个 C11 程序都包含一个主线程即 main() 函数。在 C11 中我们可以通过创建 std::thread 对象来创建新的线程。每个 std::thread 对象都可以与一个线程相关联。需要引用的头文件&#xff1a;1#include <thread>std::thread 的构造函数中接…

Python3反转字符串

Python3反转字符串原题 https://leetcode-cn.com/problems/reverse-string-ii/题目&#xff1a; 给定一个字符串和一个整数 k&#xff0c;你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转。如果剩余少于 k 个字符&#xff0c;则将剩余的所有全部反转。如果有小于…