3DPageFlip version 2.0.7.281

Post information

Post Footer automatically generated by wp-posturl plugin for wordpress.

A bug of Away3dLite _uvtData out of index.

At away3dLite, when you change the vetices of the primitive, you may encount this problem:

20120210172343

You may find the place which error took place:

Error

Now, Where can I fix this?  Here is the solution:

insert  the following line into Mesh.as file of away3dLite,:

_screenVertices.length = vertices.length *2/3;

20120210173215

Post information

Post Footer automatically generated by wp-posturl plugin for wordpress.

Category: 3D, As3, away3dlite  Tags: , ,  Comments off

波动仿真算法(Simulation of Wave Motion)

你现在看到的这篇是翻译自OSC.EDU

符号与术语

Ui,j        在点P(i, j) 处波的高度
i             X方向的网格位置
j             Y轴方向的网格位置
n           迭代次数
dt          时间步长(Time step)
mu       粘度系数
il           X方向的网格数目
jl           Y方向的网格数目

问题介绍

波动行为是科学中比较大的研究区域。波也是我们生活中的一部分。你一天中至少要经历一次波。有水波,空气中的波,更甚者,固体中的波。有各种不同大小与形状的波,它们以不同的速度进行移动,它们有不同的波动频率。每次你说话的时候,你就创建了一种波。广播电视台以无线电波的形式传递信号。根据周围环境的不同,波可以表现出不同的行为。声波在隔音的房间里将被吸收,但是它们在金属中会产生不同的声音,并沿着其两端发散, 随着距离的增长,声波将逐渐衰减。这些为什么会发生?我们如何通过电脑来仿真这些波?

幸运的是,一些简单的波可以通过数学来进行描述。生活中的波存在3D空间中。然而,为了使问题简化,我们将在二维平面空间里分析波,比如说,水波,就看起来比较像二维空间的波。很多人都看过当一块石头扔进水塘时在水面上产生的涟漪效果。描述二维空间波动的方程甚至还有一个名字:2D波动方程,其方程式如下:

eq1

其中,a是波传递的速度(例如:我们如果讨论声波的话,a就是声音的速度)。
这是一个2次偏微分方程。微分表示一个变量相对另一个变量的变化,例如,速度,是位移相对于时间的一次微分,同理,加速度是速度相对时间的一次微分,或者说,加速度是位移相对时间的二分微分。(注:这里有一小段对于微分的说明,有不懂者,去回顾一下高数)。

详细的说明本方程不在这篇文章的讨论范围,我们要说的是,这个2D波动方程通过将时间的变化与波的空间梯度(在X,Y上的微分)联系起来,描述波的运动。

单独这个方程本分不足以完全描述波的运动。波的初始形状如何?波的空间范围如何?初始形状与空间范围将如何影响波的运动?因此,当我们尝试回答这个问题时,我们将要考虑波的初始条件与边界条件。

数值化解决方案

我们该如何在电脑上利用一个方程例如波动方程呢? 第一步是描述这个方程,也就是说,在一个单点上近似的算出这个方程的值 ,因为,这个点就可以近似的代表这个点周围的值。 要做到这一点,我们需要先建立一个网格。二维空间的网格看起来如下:

grid

一个离散的方程仅在网格的交点处计算。通过“中心差分法(central differences)”可以将微分方程离散化。放大上面网格中心处的高亮区域,我们可以看看,如何将方程离散化

stencil

利用通过这个方法离散的2D空间,我们可以近似的求取微分方程如下:

deriv

有关中心差分法的知识,你可以访问下面连接,或者看最后一张图
中心差分法-百度百科

如果将上面的方程代入到波动方程中,我们可以得到:
update
其中,
const

初始条件

我们前面提到,波的行为与其初始形状相关,初始形状可以类型于初始扰动,对于这个问题,我们将在网格的正中心给一个正弦波提供一个初始扰动(实际上是余弦波)。我们将通过计算去跟踪波向边界传播的轨迹,然后波将与边界发生碰撞,然后向中心移动。

我们假定在网格各个方向上长度为1.0, 中心点是(0,0),这也就是说左边界、右边界X坐标是x=-0.5, x=0.5, 同理,上边界与下边界的Y坐标分别是Y=0.5, Y=-0.5。如果我们想使波根据原点对称,我们就需要使用极坐标。初始化扰动方程如下:

initial1

其中:

initial2

初始扰动形状如下:

distribution

我们重新思考一下有离散方程,如果我们要计算第一阶段的波高,就需要提供第1阶段与第0阶段的值,我们知道当n=1时为初始值,那当n=0时,波高是什么呢?我们将使用一个零梯度初始条件,在数学上是:

zerog1,这也就是说,在离散方程中:

zerog2

如果我们将其代入到原始的离散方程中,我们将得到:

start

第一次迭代。这就是所谓的“开始公式。”

边界条件

另一个影响波行为的因素是不同的边界类型,在这里我将考虑两种不同类型的边界条件,它们分别是固定边界与不限边界。为了理解这两种边界类型,想象一条绳子,其一端被固定在墙上,另一端自由。如果你在这绳的中部摇动绳子,那么,由此产生的波将沿着绳子向两端运动。波在绳子的固定与自由端表现出不同的行为。我们如何在数学上描述这种情况呢?

假定我们2D网格的左边界是固定的,那么这个边界条件的离散形式是:

fixbc

同理,假定右边办是自由的,这个边界条件的离散形式是:

freebc1

将这两个代入到主有离散方程中,我们得到:

freebc2

基本框架

下面是解决这个问题的代码基本框架

  • 定义变量与常量
  • 计算x,y数组
  • 计算U的初始值
  • 第一次迭代公式,边界条件
  • 应用通用公式,边界条件,直到n=NEND。
  • 为每次NFREQ迭代,写一个数据帧。
  • 完成

其中: NEND,最后一次迭代N值,大约是300-500。 NFREQ,等待写入输出的迭代次数

GRAPHICS

如果我们不能真实的明白其原理,这些数字又有什么用呢?有人说,一张图胜千百个文字,用在这里刚好。我们的仿真将在10000个网络点阵中几百次迭代计算波的高度。如果每个表示波高的数值是一个字长,那么,仿真中的一帧将包含10000个文字。为了理解波的运动,我们需要让所有计算得到的帧运动起来。假设我们有180帧,那么总字数是1800000, 所以,在我们这副图将值180万字。

为了使波可视化,有两种方法,第一个且最有说服力的方法是将这些2D波在3D空间中展示出来,第二种方法是根据波的高度给网格上上不种的颜色。

你可以使用AVS/Express将结果可视化。

附注

  • Use different combinations of boundary conditions and initial conditions to further investigate wave behavior.
  • Use a non-uniform grid. This may require you to change how you do your visualizations.
  • Add the following term to the left side of the 2-D wave equation and vary mu to determine its effect on the wave:
  • Instead of the initial conditions shown above, initialize all values to zero and add a forcing function f(t) at some location in the grid. This can be either calculated (eg.f(t)=cos(2*pi*omega*t)) or read from a file (eg. data from a digital recording of a sound).

 

difference
                                                                          (点击图片直接查看大图)

Post information

Post Footer automatically generated by wp-posturl plugin for wordpress.

Category: Default, 翻译  Tags:  Comments off

(中文) 2011年总结。

Sorry, this entry is only available in 中文.

Post information

Post Footer automatically generated by wp-posturl plugin for wordpress.

Category: Personal  Comments off

Add Cube class to Away3dLite Flash 3D engine which support change the material of each Cube face.

Up to now, The flash 3D engine Away3DLite  have no build in Cube primitive, just got a Cube6, which could not change the material of each cube face.   So, I decide to do something. I have spent one  afternoon to write and debug this Cube class. In order to make it better to use, I give the Cube class  of Away3dLite the same user interface to the Cube of Away3d.  Following comes the code:

 

package away3dlite.primitives
{
	import away3dlite.primitives.Data.CubeMaterialsData;
	import away3dlite.arcane;
	import away3dlite.events.MaterialEvent;
	import away3dlite.materials.Material;
	import away3dlite.primitives.AbstractPrimitive;

	use namespace arcane;
	/**
	 * The Cube class
	 *
	 * @author Neugls
	 * @see http://www.neugls.info
	 *
	 * */
	public class Cube extends AbstractPrimitive
	{

		private var _cubeMaterials:CubeMaterialsData;
		private var _leftFaces:Vector.; 			//faces index
		private var _rightFaces:Vector.;
		private var _bottomFaces:Vector.;
		private var _topFaces:Vector.;
		private var _frontFaces:Vector.;
		private var _backFaces:Vector.;
		private var _cubeFaceArray:Vector.

		private var _width:Number = 100;
		private var _height:Number = 100;
		private var _depth:Number = 100;
		private var _segmentsW:int = 1;
		private var _segmentsH:int = 1;
		private var _segmentsD:int = 1;

		/**
		 * Creates a new Cube object.
		 *
		 * @param	material	Defines the global material used on the faces in the cube.
		 * @param	width		Defines the width of the cube.
		 * @param	height		Defines the height of the cube.
		 * @param	depth		Defines the depth of the cube.
		 * @param	segmentsW	Defines the number of horizontal segments that make up the cube.
		 * @param	segmentsH	Defines the number of vertical segments that make up the cube.
		 * @param	segmentsD	Defines the number of depth segments that make up the cube.
		 * @param	pixelBorder	Defines the texture mapping border in pixels used around each face of the cube.
		 */
		public function Cube(material:CubeMaterialsData=null, width:Number=100, height:Number=100, depth:Number=100, segmentsW:int=1, segmentsH:int=1, segmentsD:int=1)
		{

			super(null);

			_width = width;
			_height = height;
			_depth = depth;
			_segmentsW = segmentsW;
			_segmentsH = segmentsH;
			_segmentsD = segmentsD;
			cubeMaterials=material?material:new CubeMaterialsData();

			_leftFaces=new Vector.();
			_rightFaces=new Vector.();
			_bottomFaces=new Vector.();
			_topFaces=new Vector.();
			_frontFaces=new Vector.();
			_backFaces=new Vector.();

			type = "Cube";
			url = "primitive";
		}

		private function BuildFace(whichFace:Vector.,material:Material):void{
			whichFace.push(int(_indices.length/3)-2);
			whichFace.push(int(_indices.length/3)-1);
			_faceMaterials[int(_indices.length/3)-2]=material;
			_faceMaterials[int(_indices.length/3)-1]=material;
		}

		protected override function buildPrimitive():void{
			super.buildPrimitive();

			_leftFaces.length=0;
			_rightFaces.length=0;
			_bottomFaces.length=0;
			_topFaces.length=0;
			_frontFaces.length=0;
			_backFaces.length=0;

			var i:int;
			var j:int;

			var a:int;
			var b:int;
			var c:int;
			var d:int;
			var inc:int = 0;

			for (i = 0; i <= _segmentsW; i++) {
				for (j = 0; j <= _segmentsH; j++) {

					//create front/back
					_vertices.push(_width/2 - i*_width/_segmentsW, _height/2 - j*_height/_segmentsH, -_depth/2);
					_vertices.push(_width/2 - i*_width/_segmentsW, _height/2 - j*_height/_segmentsH, _depth/2);

					_uvtData.push(1-i/_segmentsW, 1-j/_segmentsH, 1);
					_uvtData.push(i/_segmentsW, 1-j/_segmentsH, 1);

					if (i && j) {
						a = 2*((_segmentsW + 1)*j + i);
						b = 2*((_segmentsW + 1)*j + i - 1);
						c = 2*((_segmentsW + 1)*(j - 1) + i - 1);
						d = 2*((_segmentsW + 1)*(j - 1) + i);

						_indices.push(c,d,b);
						_indices.push(d,a,b);
						BuildFace(_frontFaces,_cubeMaterials.front);

						_indices.push(c+1,b+1,d+1);
						_indices.push(d+1,b+1,a+1);
						BuildFace(_backFaces,_cubeMaterials.back);
					}
				}
			}

			inc += 2*(_segmentsW + 1)*(_segmentsH + 1);

			for (i = 0; i <= _segmentsW; i++) {
				for (j = 0; j <= _segmentsD; j++) {

					//create top/bottom
					_vertices.push(_width/2 - i*_width/_segmentsW, _height/2, -_depth/2 + j*_depth/_segmentsD);
					_vertices.push(_width/2 - i*_width/_segmentsW, -_height/2, -_depth/2 + j*_depth/_segmentsD);

					_uvtData.push(i/_segmentsW, j/_segmentsD, 1);
					_uvtData.push(i/_segmentsW, 1-j/_segmentsD, 1);

					if (i && j) {
						a = inc + 2*((_segmentsW + 1)*j + i);
						b = inc + 2*((_segmentsW + 1)*j + i - 1);
						c = inc + 2*((_segmentsW + 1)*(j - 1) + i - 1);
						d = inc + 2*((_segmentsW + 1)*(j - 1) + i);

						_indices.push(c,b,d);
						_indices.push(b,a,d);
						BuildFace(_topFaces,_cubeMaterials.top);

						_indices.push(c+1,d+1,b+1);
						_indices.push(b+1,d+1,a+1);
						BuildFace(_bottomFaces,_cubeMaterials.bottom);
					}
				}
			}

			inc += 2*(_segmentsW + 1)*(_segmentsD + 1);

			for (i = 0; i <= _segmentsH; i++) {
				for (j = 0; j <= _segmentsD; j++) {

					//create left/right
					_vertices.push(_width/2, _height/2 - i*_height/_segmentsH, -_depth/2 + j*_depth/_segmentsD);
					_vertices.push(-_width/2, _height/2 - i*_height/_segmentsH, -_depth/2 + j*_depth/_segmentsD);

					_uvtData.push(j/_segmentsD,1-i/_segmentsH, 1);
					_uvtData.push(1-j/_segmentsD, 1-i/_segmentsH, 1);

					if (i && j) {
						a = inc + 2*((_segmentsH + 1)*j + i);
						b = inc + 2*((_segmentsH + 1)*j + i - 1);
						c = inc + 2*((_segmentsH + 1)*(j - 1) + i - 1);
						d = inc + 2*((_segmentsH + 1)*(j - 1) + i);

						_indices.push(c,d,b);
						_indices.push(d,a,b);
						BuildFace(_rightFaces,_cubeMaterials.right);

						_indices.push(c+1,b+1,d+1);
						_indices.push(d+1,b+1,a+1);
						BuildFace(_leftFaces,_cubeMaterials.left);
					}
				}
			}
		}

		/**
		 * Defines the face materials of the cube.
		 */
		public function get cubeMaterials():CubeMaterialsData
		{
			return _cubeMaterials;
		}

		public function set cubeMaterials(val:CubeMaterialsData):void
		{
			if (_cubeMaterials == val)
				return;

			if (_cubeMaterials)
				_cubeMaterials.removeOnMaterialChange(onCubeMaterialChange);

			_cubeMaterials = val;

			_cubeMaterials.addOnMaterialChange(onCubeMaterialChange);
		}

		private function onCubeMaterialChange(event:MaterialEvent):void
		{
			switch (event.extra) {
				case "left":
					_cubeFaceArray = _leftFaces;
					break;
				case "right":
					_cubeFaceArray = _rightFaces;
					break;
				case "bottom":
					_cubeFaceArray = _bottomFaces;
					break;
				case "top":
					_cubeFaceArray = _topFaces;
					break;
				case "front":
					_cubeFaceArray = _frontFaces;
					break;
				case "back":
					_cubeFaceArray = _backFaces;
			}

			for each (var i:int in _cubeFaceArray)
			_faces[i].material = event.material as Material;
		}

		/**
		 * Defines the width of the cube. Defaults to 100.
		 */
		public override function get width():Number
		{
			return _width;
		}

		public override function set width(val:Number):void
		{
			if (_width == val)
				return;

			_width = val;
			_primitiveDirty = true;
		}

		/**
		 * Defines the height of the cube. Defaults to 100.
		 */
		public override function get height():Number
		{
			return _height;
		}

		public override function set height(val:Number):void
		{
			if (_height == val)
				return;

			_height = val;
			_primitiveDirty = true;
		}

		/**
		 * Defines the depth of the cube. Defaults to 100.
		 */
		public function get depth():Number
		{
			return _depth;
		}

		public function set depth(val:Number):void
		{
			if (_depth == val)
				return;

			_depth = val;
			_primitiveDirty = true;
		}

		/**
		 * Defines the number of horizontal segments that make up the cube. Defaults to 1.
		 */
		public function get segmentsW():Number
		{
			return _segmentsW;
		}

		public function set segmentsW(val:Number):void
		{
			if (_segmentsW == val)
				return;

			_segmentsW = val;
			_primitiveDirty = true;
		}

		/**
		 * Defines the number of vertical segments that make up the cube. Defaults to 1.
		 */
		public function get segmentsH():Number
		{
			return _segmentsH;
		}

		public function set segmentsH(val:Number):void
		{
			if (_segmentsH == val)
				return;

			_segmentsH = val;
			_primitiveDirty = true;
		}

		/**
		 * Defines the number of depth segments that make up the cube. Defaults to 1.
		 */
		public function get segmentsD():Number
		{
			return _segmentsD;
		}

		public function set segmentsD(val:Number):void
		{
			if (_segmentsD == val)
				return;

			_segmentsD = val;
			_primitiveDirty = true;
		}
	}
}

The following comes the CubeMaterialsData class:

package away3dlite.primitives.Data
{
	import away3dlite.events.MaterialEvent;
	import away3dlite.materials.Material;
	import away3dlite.materials.WireframeMaterial;

	import flash.events.EventDispatcher;

	public class CubeMaterialsData extends EventDispatcher
	{

		/**
		 * Dispatched when the cube materials object has one of it's materials updated.
		 *
		 * @eventType away3dLite.events.MaterialEvent
		 */
		[Event(name="materialchanged",type="away3dlite.events.MaterialEvent")]

		private var _materialchanged:MaterialEvent;
		private var _left:Material;
		private var _right:Material;
		private var _bottom:Material;
		private var _top:Material;
		private var _front:Material;
		private var _back:Material;

		private function notifyMaterialChange(material:Material, faceString:String):void
		{
			if (!hasEventListener(MaterialEvent.MATERIAL_CHANGED))
				return;

			//if (!_materialchanged)
			_materialchanged = new MaterialEvent(MaterialEvent.MATERIAL_CHANGED, material);
			/*else
			_materialchanged.material = material; */

			_materialchanged.extra = faceString;

			dispatchEvent(_materialchanged);
		}

		/**
		 * Defines the material applied to the left side of the cube.
		 */
		public function get left():Material
		{
			return _left;
		}

		public function set left(val:Material):void
		{
			if (_left == val)
				return;

			_left = val;

			notifyMaterialChange(_left, "left");
		}

		/**
		 * Defines the material applied to the right side of the cube.
		 */
		public function get right():Material
		{
			return _right;
		}

		public function set right(val:Material):void
		{
			if (_right == val)
				return;

			_right = val;

			notifyMaterialChange(_right, "right");
		}

		/**
		 * Defines the material applied to the bottom side of the cube.
		 */
		public function get bottom():Material
		{
			return _bottom;
		}

		public function set bottom(val:Material):void
		{
			if (_bottom == val)
				return;

			_bottom = val;

			notifyMaterialChange(_bottom, "bottom");
		}

		/**
		 * Defines the material applied to the top side of the cube.
		 */
		public function get top():Material
		{
			return _top;
		}

		public function set top(val:Material):void
		{
			if (_top == val)
				return;

			_top = val;

			notifyMaterialChange(_top, "top");
		}

		/**
		 * Defines the material applied to the front side of the cube.
		 */
		public function get front():Material
		{
			return _front;
		}

		public function set front(val:Material):void
		{
			if (_front == val)
				return;

			_front = val;

			notifyMaterialChange(_front, "front");
		}

		/**
		 * Defines the material applied to the back side of the cube.
		 */
		public function get back():Material
		{
			return _back;
		}

		public function set back(val:Material):void
		{
			if (_back == val)
				return;

			_back = val;

			notifyMaterialChange(_back, "back");
		}

		/**
		 * Get the indicated face material from the obj
		 * */
		private function getMaterial(Obj:Object,face:String):Material{
			if(!Obj||!Obj[face]||!(Obj[face] is Material))
				return new WireframeMaterial(Math.random()*0xFFFFFF);
			return Obj[face] as Material;
		}

		/**
		 * Creates a new CubeMaterialsData object.
		 *
		 * @param	init			[optional]	An initialisation object for specifying default instance properties.
		 */
		public function CubeMaterialsData(init:Object = null)
		{
			_left = getMaterial(init,"left");
			_right = getMaterial(init,"right");
			_bottom = getMaterial(init,"bottom");
			_top = getMaterial(init,"top");
			_front = getMaterial(init,"front");
			_back = getMaterial(init,"back");
		}

		/**
		 * Default method for adding a materialChanged event listener
		 *
		 * @param	listener		The listener function
		 */
		public function addOnMaterialChange(listener:Function):void
		{
			addEventListener(MaterialEvent.MATERIAL_CHANGED, listener, false, 0, false);
		}

		/**
		 * Default method for removing a materialChanged event listener
		 *
		 * @param	listener		The listener function
		 */
		public function removeOnMaterialChange(listener:Function):void
		{
			removeEventListener(MaterialEvent.MATERIAL_CHANGED, listener, false);
		}
	}
}

Like this :

1

2

You can download it from here.

Click HERE to DOWNLOAD

When you are reading this article, I am trying to make this update to the svn of Away3dLite.

Post information

Post Footer automatically generated by wp-posturl plugin for wordpress.

Category: 3D, As3, away3dlite  Tags: ,  Comments off