如何基于Canvas来模拟真实雨景Part2:重力掉落和雨滴融合

techbrood 发表于 2016-05-21 15:17:47

标签: canvas, html5, 下雨, 窗户, 教程

- +

Part1中我们已经建立了绘制环境、背景和雨点对象。本文我们将接着讲述更为吸引人的动画部分。

重力掉落

我们先复习下自由落体的基本公式:

速度-时间公式:Δv=gΔt
位移-时间公式;h=gt^2/2
速度-位移公式:v^2=2gh

重力只作用于物体的y轴方向,一个处于自由落体状态的雨滴,不计空气阻力和风力的时候,其运动将符合上面的规律。

力作用于物体上时都会产生加速度(重力产生重力加速度g=9.8),因此我们需要给雨滴y轴的速度分量(vy)添加一个时间增量。

我们假定每秒帧数(fps)为30,那么每次刷新的时间间隔为1/30秒,乘以g,速度增量约为0.33的样子。但是,雨滴在窗户上的情况要复杂得多,因为其还受到窗户的阻力,下落的形式可能会包含滚动和滑动,其摩擦力的计算方法也不相同,另外窗户上的灰尘导致各个点的阻力并不完全相同,总体上我们可以认为越小的雨滴受窗户的影响越大(因其接触面积相对占比大更容易被吸附住),因此我们还需要给vy添加一个和雨滴半径成反比的随机摩擦系数,这样就造成一个时快时慢乃至有些雨点会停留在窗户上的效果。

在有风的环境中(通常是有的),除了y方向的速度,我们还要考虑x方向的速度,总的速度为:

v = Math.sqrt(vx*vx, vy*vy);

当然在画布上,我们还是按照x,y轴分开来计算偏移的。

RainyView.prototype.gravity = function(drop) {
  this.g = 9.8;
  this.fps = 30;
  var r_base = 3;
  if (drop.yspeed) {
    friction = this.base_friction + Math.ceil(Math.random() * this.g) / (Math.floor(drop.r) - r_base + 1);
    drop.yspeed += Math.floor(this.g - friction)/this.fps; 
    if(drop.yspeed < 0) drop.yspeed = 0;
    drop.xspeed += Math.floor(drop.r);
  } else {
    drop.yspeed = 0.01; //给定一个启动速度
    drop.xspeed = 0;
  }

  drop.y += drop.yspeed;
  drop.draw();
  return false;
};

你还可以给上面代码中的速度增量乘上一个系数来调整实际的动画效果,不需要过度模拟真实情况。

碰撞融合

要检测粒子(雨滴)之间的碰撞情况,数学上来讲就是计算两个雨滴中心点的距离,如果小于等于半径之和,则两个水滴已经碰在了一起,将开始融合。但是我们不能遍历所有的粒子,这样的计算效率是很差的。我们实际上只需要计算相邻粒子之间的距离,为此一个常用的方法是建立和画布对应的相邻矩阵,每个粒子占据矩阵中的一个位置,其相邻粒子最多有4个。我们每次移动雨滴粒子的时候,计算一下和相邻粒子的距离,决定是否进行融合。

RainyView.prototype.collision = function(drop, collisions) {
	var item = collisions;
	var drop2;
	// 计算矩阵(链表结构)中相邻粒子的距离,取出第一个需要融合的雨滴粒子
	while (item != null) {
		var p = item.drop;
		var radiusSum = drop.r + p.r;
		var dx = drop.x - p.x;
		var dy = drop.y - p.y;
		if(Math.abs(dx) < radiusSum) {
			if(Math.abs(dy) < radiusSum) {
				if (Math.sqrt(Math.pow(drop.x - p.x, 2) + Math.pow(drop.y - p.y, 2)) < (drop.r + p.r)) {
					drop2 = p;
					break;
				}
			}
		}
		item = item.next;
	}

	if (!drop2) {
		return;
	}

	// 移除高一点的雨滴,融合到低一点的雨滴中
	var higher,
		lower;
	if (drop.y > drop2.y) {
		higher = drop;
		lower = drop2;
	} else {
		higher = drop2;
		lower = drop;
	}

	this.clearDrop(lower);
	// force stopping the second drop
	this.clearDrop(higher, true);
	this.matrix.remove(higher);
	lower.r = Math.sqrt(higher.r*higher.r + lower.r*lower.r);//合并雨滴
	lower.draw();

	lower.collided = true;
};

解决了重力掉落和碰撞检测后,我们需要实现一个“下雨”的动画主函数,这个函数用来驱动每个雨滴的运动:

RainyView.prototype.animate = function() {
	var dropsClone = this.drops.slice();
	var newDrops = [];
	for (var i = 0; i < dropsClone.length; ++i) {
		if (dropsClone[i].move()) {//该函数定义参见Part1
			newDrops.push(dropsClone[i]);
		}
	}
	this.drops = newDrops;
	window.requestAnimFrame(this.animateDrops.bind(this));
};

这样基本上就完成了整个的下雨动画,为了更加逼真,你还可以添加雨滴的滑落轨迹(水渍效果)和雨滴的反射效果(参考CSS3泡沫一文中的方法),还有一些实现细节,这里不做描述。

最终的效果看起来会是下面这样:

blob.png

你可以自己在线试试

后续我们计划讲解如何使用WebGL来实现3D版本的雨滴效果。

possitive(21) views24329 comments0

发送私信

最新评论

请先 登录 再评论.
相关文章
  • CentOS6 Apache2.2多站点HTTPS配置

    可以使用letsencrypt(certbot)免费证书服务。支持多系统、多站点和多目录,支持wildcard(通配符域名),90天生效,可用定时任务自动更新。需要注意一点的是apache2.4以下版本需要在默认的ssl配置中添加如下的指令:NameVirtualHost

  • 增强现实引擎ARToolKit工作原理简介

    ARToolkit是一个基于CV(计算机视觉)和Marker(标识)的开源增强现实引擎。其具备如下功能特性:A. 鲁棒跟踪,包括基于标记的跟踪与基于特征的跟踪;

  • ARCore基本概念和工作原理简介

    谷歌的WebAROnARCore项目基于Android手机提供的ARCore增强现实引擎,要了解WebAROnARCore,需要先了解ARCore的工作原理。基本上ARCore做了两件事,首先跟踪手机...

  • CSS3原生变量(Native Variables)新特性简介

    对Web开发者来说,一个盼望已久的特性是CSS终于支持原生变量了!
    变量是程序语言中用来解决代码重复和进行表达式计算的关键概念(想想数学方程式中的x)。...

  • React JSX语法简介

    JSX是一种类似XML的标签语法,用来简化代码,我们可以不使用JSX,但了解并使用也没什么坏处:)在React中,JSX是一个使用 React.createElement() API的快捷方式...

  • JavaScript语言多编程范式简介

    和C++等语言类似,JS支持多范式(paradigms)编程。我们常常混合这些范式来完成一些大型Web项目。JS支持3种编程范式:命令式、面向对象和函数式。命令式(Imperative JavaScript)命令式就是简单的从上而下完成任务,流水账过程式编码风格:function

  • 使用CSS3 box-decoration-break特性实现多行文本样式

    当文章中的长文本被自动断行为多行文本时,其样式可能会出乎我们的设计。本文介绍如何使用CSS3中的box-decoration-break特性来处理多行元素样式。
    按照规范...

  • CSS3弹性布局内容对齐(justify-content)属性使用详解

    内容对齐(justify-content)属性应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐。该操作发生在弹性长度以及自动边距被确定后。 它用来在存...

  • HTML5、Hybrid APP、Native APP对比和技术选型

    HTML5和Native APP都很容易理解。为了获得HTML5的移植性和移动本地应用的高性能,搞出来一些混合APP的解决方案。比如Apache的Cordova(也就是以前的PhoneGap),...

  • 学习使用CSS制作进度条

    进度条是基础的界面控件,可用于多种场合,比如任务完成进度,手机充电状态等。本文介绍一个简单实用的进度条制作方法。预期效果如下图所示:直观上,我们可以把该进度条控件分为2个部分,外部的边界用来表示固定的目标范围,里面的条形部分用来表示当前进度。外部目标范围元素的CSS代码编写如下:.pb-scope

  • 三维向量的简单运算和实用意义

    在WebGL的实际应用中我们广泛使用向量的几何运算来计算角度、距离,判断点线、点面之间的关系,比如物体之间的碰撞检测。本文简要介绍三维计算机图形学中常用的...

  • WebGL入门教程1 - 3D绘图基础知识

    现代浏览器努力使得Web用户体验更为丰富,而WebGL正处于这样的技术生态系统的中心位置。其应用范围覆盖在线游戏、大数据可视化、计算机辅助设计、虚拟现实以及数...

  • 使用Canvas绘制完美的不完美圆形

    真实世界是不完美的,当我们需要模拟真实世界时,经常需要引入不完美/不规则的形状。比如陨石、雨滴、行星、树叶、绵延的海岸线、云朵等。本文介绍如何基于Canva...

  • 如何基于Canvas来模拟真实雨景Part1:预备知识和创建基本对象

    我们之前使用CSS3实现过

  • inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移

    在表单修改界面中常会使用一个标签、一个内容加一个修改按钮来组成单行界面,如图1所示。那么在表单总长度受限的情况下,当中间的邮箱名称过长时,会遮盖到旁边...

  • 更多...