请选择 进入手机版 | 继续访问电脑版
查看: 547|回复: 0

逼真的HTML5 3D水波动画 可多视角浏览

[复制链接]

1306

主题

1306

帖子

4336

积分

超级版主

Rank: 8Rank: 8

积分
4336
发表于 2018-1-22 16:40:35 | 显示全部楼层 |阅读模式
这是一款基于HTML5的3D水波动画特效,它的效果非常逼真,水池中的石头在水中沉浮,泛起了一层层水波。同时我们可以拖拽鼠标从不同的视角来浏览水池,3D效果非常不错。另外,我们可以按“G”键来让水池中的石头上下浮动,按“L”键添加灯光效果,设计相当完美。同时说明一下,这款3D水波动画是基于WebGL渲染技术的,大家可以了解一下WebGL。

HTML代码
  1. <img id="tiles" src="tiles.jpg">
  2. <img id="xneg" src="xneg.jpg">
  3. <img id="xpos" src="xpos.jpg">
  4. <img id="ypos" src="ypos.jpg">
  5. <img id="zneg" src="zneg.jpg">
  6. <img id="zpos" src="zpos.jpg">
复制代码
JavaScript代码
  1. function Water() {
  2.   var vertexShader = '\
  3.     varying vec2 coord;\
  4.     void main() {\
  5.       coord = gl_Vertex.xy * 0.5 + 0.5;\
  6.       gl_Position = vec4(gl_Vertex.xyz, 1.0);\
  7.     }\
  8.   ';
  9.   this.plane = GL.Mesh.plane();
  10.   if (!GL.Texture.canUseFloatingPointTextures()) {
  11.     throw new Error('This demo requires the OES_texture_float extension');
  12.   }
  13.   var filter = GL.Texture.canUseFloatingPointLinearFiltering() ? gl.LINEAR : gl.NEAREST;
  14.   this.textureA = new GL.Texture(256, 256, { type: gl.FLOAT, filter: filter });
  15.   this.textureB = new GL.Texture(256, 256, { type: gl.FLOAT, filter: filter });
  16.   this.dropShader = new GL.Shader(vertexShader, '\
  17.     const float PI = 3.141592653589793;\
  18.     uniform sampler2D texture;\
  19.     uniform vec2 center;\
  20.     uniform float radius;\
  21.     uniform float strength;\
  22.     varying vec2 coord;\
  23.     void main() {\
  24.       /* get vertex info */\
  25.       vec4 info = texture2D(texture, coord);\
  26.       \
  27.       /* add the drop to the height */\
  28.       float drop = max(0.0, 1.0 - length(center * 0.5 + 0.5 - coord) / radius);\
  29.       drop = 0.5 - cos(drop * PI) * 0.5;\
  30.       info.r += drop * strength;\
  31.       \
  32.       gl_FragColor = info;\
  33.     }\
  34.   ');
  35.   this.updateShader = new GL.Shader(vertexShader, '\
  36.     uniform sampler2D texture;\
  37.     uniform vec2 delta;\
  38.     varying vec2 coord;\
  39.     void main() {\
  40.       /* get vertex info */\
  41.       vec4 info = texture2D(texture, coord);\
  42.       \
  43.       /* calculate average neighbor height */\
  44.       vec2 dx = vec2(delta.x, 0.0);\
  45.       vec2 dy = vec2(0.0, delta.y);\
  46.       float average = (\
  47.         texture2D(texture, coord - dx).r +\
  48.         texture2D(texture, coord - dy).r +\
  49.         texture2D(texture, coord + dx).r +\
  50.         texture2D(texture, coord + dy).r\
  51.       ) * 0.25;\
  52.       \
  53.       /* change the velocity to move toward the average */\
  54.       info.g += (average - info.r) * 2.0;\
  55.       \
  56.       /* attenuate the velocity a little so waves do not last forever */\
  57.       info.g *= 0.995;\
  58.       \
  59.       /* move the vertex along the velocity */\
  60.       info.r += info.g;\
  61.       \
  62.       gl_FragColor = info;\
  63.     }\
  64.   ');
  65.   this.normalShader = new GL.Shader(vertexShader, '\
  66.     uniform sampler2D texture;\
  67.     uniform vec2 delta;\
  68.     varying vec2 coord;\
  69.     void main() {\
  70.       /* get vertex info */\
  71.       vec4 info = texture2D(texture, coord);\
  72.       \
  73.       /* update the normal */\
  74.       vec3 dx = vec3(delta.x, texture2D(texture, vec2(coord.x + delta.x, coord.y)).r - info.r, 0.0);\
  75.       vec3 dy = vec3(0.0, texture2D(texture, vec2(coord.x, coord.y + delta.y)).r - info.r, delta.y);\
  76.       info.ba = normalize(cross(dy, dx)).xz;\
  77.       \
  78.       gl_FragColor = info;\
  79.     }\
  80.   ');
  81.   this.sphereShader = new GL.Shader(vertexShader, '\
  82.     uniform sampler2D texture;\
  83.     uniform vec3 oldCenter;\
  84.     uniform vec3 newCenter;\
  85.     uniform float radius;\
  86.     varying vec2 coord;\
  87.     \
  88.     float volumeInSphere(vec3 center) {\
  89.       vec3 toCenter = vec3(coord.x * 2.0 - 1.0, 0.0, coord.y * 2.0 - 1.0) - center;\
  90.       float t = length(toCenter) / radius;\
  91.       float dy = exp(-pow(t * 1.5, 6.0));\
  92.       float ymin = min(0.0, center.y - dy);\
  93.       float ymax = min(max(0.0, center.y + dy), ymin + 2.0 * dy);\
  94.       return (ymax - ymin) * 0.1;\
  95.     }\
  96.     \
  97.     void main() {\
  98.       /* get vertex info */\
  99.       vec4 info = texture2D(texture, coord);\
  100.       \
  101.       /* add the old volume */\
  102.       info.r += volumeInSphere(oldCenter);\
  103.       \
  104.       /* subtract the new volume */\
  105.       info.r -= volumeInSphere(newCenter);\
  106.       \
  107.       gl_FragColor = info;\
  108.     }\
  109.   ');
  110. }

  111. Water.prototype.addDrop = function(x, y, radius, strength) {
  112.   var this_ = this;
  113.   this.textureB.drawTo(function() {
  114.     this_.textureA.bind();
  115.     this_.dropShader.uniforms({
  116.       center: [x, y],
  117.       radius: radius,
  118.       strength: strength
  119.     }).draw(this_.plane);
  120.   });
  121.   this.textureB.swapWith(this.textureA);
  122. };

  123. Water.prototype.moveSphere = function(oldCenter, newCenter, radius) {
  124.   var this_ = this;
  125.   this.textureB.drawTo(function() {
  126.     this_.textureA.bind();
  127.     this_.sphereShader.uniforms({
  128.       oldCenter: oldCenter,
  129.       newCenter: newCenter,
  130.       radius: radius
  131.     }).draw(this_.plane);
  132.   });
  133.   this.textureB.swapWith(this.textureA);
  134. };

  135. Water.prototype.stepSimulation = function() {
  136.   var this_ = this;
  137.   this.textureB.drawTo(function() {
  138.     this_.textureA.bind();
  139.     this_.updateShader.uniforms({
  140.       delta: [1 / this_.textureA.width, 1 / this_.textureA.height]
  141.     }).draw(this_.plane);
  142.   });
  143.   this.textureB.swapWith(this.textureA);
  144. };

  145. Water.prototype.updateNormals = function() {
  146.   var this_ = this;
  147.   this.textureB.drawTo(function() {
  148.     this_.textureA.bind();
  149.     this_.normalShader.uniforms({
  150.       delta: [1 / this_.textureA.width, 1 / this_.textureA.height]
  151.     }).draw(this_.plane);
  152.   });
  153.   this.textureB.swapWith(this.textureA);
  154. };
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

快速回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

快速回复 扫码关注微信二维码 返回顶部 返回列表