这段时间一直在看如何用shader绘制一个流动的水面,直接用贴图(高度图、法向贴图)实现的方法,这里就不讨论了。

搜了一大波博客资料,感觉存在如下一些问题:

1⃣️大多数资料都是基于opengl实现(或者是unity里的shader),过多关注点在渲染上面而不是水波的mesh实现上,让人没有看下去的欲望

2⃣️有的就直接是照搬别人的博客,公式大段大段地搬,却没有自己的一丝见解,太过敷衍

3⃣️代码不加注释,对前来学习者不太友好

4⃣️针对webgl的实现,网上的资料太少(虽然已经有了opengl的实现)

所以在查阅了资料之后,决定写一个webgl版本的实现(three.js + shader)

nvidia官方提供的水波实现方程(其实网上大多数博客里的方程式应该都是源于此处):传送门。

对应的,知乎有一篇文章,基本上就是上面网站的中文版,但是作者加入了一点自己思考后的想法,个人觉得很好,推荐一下:GPU Gems 基于物理模型的水面模拟。

-------------------------------------------------------------------华丽的分割线-------------------------------------------------------------------------

一、PlaneGeometry + ShaderMaterial + 正弦波方程式

    //1.PlaneGeometry
this.seaMaterial = new THREE.ShaderMaterial({
uniforms: {
time:{type:'f',value:},
},
vertexShader: seashader.vs,
fragmentShader: seashader.fs,
side:THREE.DoubleSide,
wireframe: true
});
this.geometry = new THREE.PlaneGeometry( ,,,);
var plane = new THREE.Mesh( this.geometry, this.seaMaterial );
plane.rotation.x= -Math.PI/;
this.scene.add( plane );
const seashader = {
vs:`
uniform float time; void main(){
float x = position.x;
float y = position.y;
float PI = 3.141592653589; float sz = 0.0;
float ti = 0.06;
float index = 1.0;
vec2 dir;//波的方向
//四条正弦波相加
for(int i = ;i<;i++){
ti = ti + 0.0005;
index = index + 0.1;
if(mod(index,2.0)==0.0){
dir = vec2(1.0,ti);
}else{
dir = vec2(-1.0,ti);
}
float l1 = 2.0 * PI / (0.5);//波长
float s1 = 10.0 * 2.0 / l1;//速度
float z1 = 1.0 * sin(dot(normalize(dir),vec2(x,y)) * l1 + time * s1);//正弦波方程式
sz +=z1;
}
gl_Position = projectionMatrix * modelViewMatrix * vec4(x,y,sin(sz) * 10.0,1.0);
}
`,
fs:`
void main(){
gl_FragColor = vec4(./.,./.,./.,1.0);
}
`,
}
//animation
if(this.seaMaterial){
this.seaMaterial.uniforms.time.value += 0.01;
}

参考的水波方程式:

效果如下:

温馨提示:

调参很重要,水波方向、波长、波的叠加数量,如果取值不当,生成的波将会很诡异(和plane尺寸以及分割的分数有关,因为这些参数将会直接影响vs接收的顶点坐标)。

可以看到上述代码vs中顶点z:sin(sz) * 10.0,在测试中,我发现对sz进行sin处理,得到的水波细节会更多一点,就是凹凸的感觉会多一点。

正弦波具有圆润的外观-这可能正是我们想要一个平静的田园池塘所需要的。

二、Gerstner波方程式

接下来只贴shader部分

const gerstnershader = {
vs:`
uniform float time; void main(){
float x = position.x;
float y = position.y;
float PI = 3.141592653589; float sx = 0.0;
float sy = 0.0;
float sz = 0.0; float ti = 0.0;
float index = 1.0;
vec2 dir;//水波方向
for(int i = ;i<;i++){
ti = ti + 0.0005;
index +=1.0;
if(mod(index,2.0)==0.0){
dir = vec2(1.0,ti);
}else{
dir = vec2(-1.0,ti);
}
float l1 = 2.0 * PI / (0.5 + ti);//波长
float s1 = 20.0 * 2.0 / l1;//速度
float x1 = 1.0 * dir.x * sin(dot(normalize(dir),vec2(x,y)) * l1 + time * s1);
float y1 = 1.0 * dir.y * sin(dot(normalize(dir),vec2(x,y)) * l1 + time * s1);
float z1 = 1.0 * sin(dot(normalize(dir),vec2(x,y)) * l1 + time * s1);
sx +=x1;
sy +=y1;
sz +=z1;
}
sx = x + sx;
sy = y + sy;
gl_Position = projectionMatrix * modelViewMatrix * vec4(sx,sy,sin(sz) * 10.0,1.0);
}
`,
fs:`
void main(){
gl_FragColor = vec4(./.,./.,./.,1.0);
}
`,
}

参考的水波方程式:

gerstner波相较正弦波的特点是:波峰陡峭、波谷平坦。

效果如下:

用shader实现流动的水面(webgl)的更多相关文章

  1. Professional.WebGL.Programming-Chapter 2(高级WebGL编程——第二章)

    (目前发现一些文章被盗用的情况,我们将在每篇文章前面添加原文地址,本文源地址:http://www.cnblogs.com/idealer3d/p/3508251.html) 这一章主要通过创建一个三 ...

  2. 教你用webgl快速创建一个小世界

    收录待用,修改转载已取得腾讯云授权 作者:TAT.vorshen Webgl的魅力在于可以创造一个自己的3D世界,但相比较canvas2D来说,除了物体的移动旋转变换完全依赖矩阵增加了复杂度,就连生成 ...

  3. WebGL简易教程(二):向着色器传输数据

    目录 1. 概述 2. 示例:绘制一个点(改进版) 1) attribute变量 2) uniform变量 3) varying变量 3. 结果 4. 参考 1. 概述 在上一篇教程<WebGL ...

  4. 网页万能排版布局插件,web视图定位布局创意技术演示页

    html万能排版布局插件,是不是感觉很强大,原理其实很简单,不过功能很强大哈哈,大量节省排版布局时间啊! test.html <!doctype html> <html> &l ...

  5. Angle

    1 What is Angle. The goal of ANGLE is to allow Windows users to seamlessly run WebGL and other OpenG ...

  6. JavaScript 移动和触摸框架

     jQuery Mobile : 是 jQuery 在手机上和平板设备上的版本号. jQuery Mobile 不仅会给主流移动平台带来jQuery核心库.而且会公布一个完整统一的jQuery移动UI ...

  7. 从0开发3D引擎(九):实现最小的3D程序-“绘制三角形”

    目录 上一篇博文 运行测试截图 需求分析 目标 特性 头脑风暴 确定需求 总体设计 具体实现 新建Engine3D项目 实现上下文 实现_init 实现"获得WebGL上下文" 实 ...

  8. Cesium参考资源

    Reference resources cesium官网 cesium 下载 cesium官方文档 APIs cesium-workshop github cesium 官方示例 cesium git ...

  9. WebGL的shader

    WebGL的shader(着色器)有2种:vertexShader(定点着色器)和 fragmentShader(片段着色器) 顶点着色器:定义点的位置.大小 片元着色器:定义画出来的物体的材质(颜色 ...

随机推荐

  1. thymeleaf小知识

    1.根据不同性别,显明不同的默认图片:th:if th:src   图片路径 <img th:if="${gender=='男'}" id="admission_p ...

  2. http方式获取远程文件内容

    public class HttpServer { /// <summary> /// 读取远程文件的内容 /// </summary> /// <param name= ...

  3. [原创]在Windows平台使用msys2、mingw64和vscode编写和调试C/C++代码

    相关名词就不解释了,这里主要讲讲在vscode里怎么配,这里假设大家相关工具已经装好. 题外话:里面的大多数坑都是windows平台和linux平台的差异造成的,如果在linux平台配置,应该会顺利很 ...

  4. Google 的Web开发相关工具

    一.PageSpeed Insights PageSpeed Insights 能够针对移动设备和桌面设备生成网页的实际性能报告,并能够提供关于如何改进相应网页的建议. 在线工具:https://de ...

  5. 洛谷P2789 直线交点数 [数论,递归]

    题目传送门 题目描述 平面上有N条直线,且无三线共点,那么这些直线能有多少不同的交点数? 输入格式 一个正整数N 输出格式 一个整数表示方案总数 输入输出样例 输入 #1 4 输出 #1 5 说明/提 ...

  6. Centos7安装Redis5.0.3

    1.切换目录 cd tmp 2.下载 wget http://download.redis.io/releases/redis-5.0.3.tar.gz 3.解压,删除压缩包 tar xzf redi ...

  7. codeforces#1148E. Earth Wind and Fire(贪心)

    题目链接: http://codeforces.com/contest/1148/problem/E 题意: 给出两个长度为$n$的序列,将第一个序列变成第二个序列,顺序不重要,只需要元素完全相同即可 ...

  8. Mybatis源码学习之parsing包(解析器)(二)

    简述 大家都知道mybatis中,无论是配置文件mybatis-config.xml,还是SQL语句,都是写在XML文件中的,那么mybatis是如何解析这些XML文件呢?这就是本文将要学习的就是,m ...

  9. HDU 4635 Strongly connected ——(强连通分量)

    好久没写tarjan了,写起来有点手生,还好1A了- -. 题意:给定一个有向图,问最多添加多少条边,让它依然不是强连通图. 分析:不妨考虑最大时候的临界状态(即再添加一条边就是强连通图的状态),假设 ...

  10. HDFS CheckPoint && SavePoint

    HDFS CheckPoint && SavePoint 标签(空格分隔): Hadoop HDFS CheckPoint HDFS 将文件系统的元数据信息存放在 fsimage 和一 ...