Sunday, August 10, 2014

Alternative3D Code Reading Notes


layout: post title: Alternative3D Code Reading Notes ---

1. 向量和矩阵乘法

stage3d和alternative3d都使用列向量:
matrix multiply.png
Figure 1. 列向量乘法
按照AGAL的文档 What is AGALm44 destination, source1, source2的作用为:
destination.x = (source1.x * source2[0].x) + (source1.y * source2[0].y) + (source1.z * source2[0].z) + (source1.w * source2[0].w)

destination.y = (source1.x * source2[1].x) + (source1.y * source2[1].y) + (source1.z * source2[1].z) + (source1.w * source2[1].w)

destination.z = (source1.x * source2[2].x) + (source1.y * source2[2].y) + (source1.z * source2[2].z) + (source1.w * source2[2].w)

destination.w = (source1.x * source2[3].x) + (source1.y * source2[3].y) + (source1.z * source2[3].z) + (source1.w * source2[3].w)
因此在上通过Context3D.setProgramConstantsFromByteArray传矩阵到显卡时,需要按行来上传。

2. 世界坐标与视角

游戏中第一人称人物的头顶z,左手y,看着x 人物的视角用Eular坐标表示:yaw表示身体垂直方向的旋转,pitch表示低头,roll为0

2.1. Eular角对应的矩阵

Table 1. 视角
yawpitchroll
z
y
x
按照我们人的特性,肯定是先yaw,再pitch,再roll 这三次旋转表示为 r(yaw) = r(z) r(pitch) = r (y) r(roll) = r(x)
为了得到一个代表欧拉旋转的矩形,需要把这几个矩阵方向连接得(注意我们是列向量,矩阵从右乘到左):
EulaToMatrix.png
其中:
EulaToMatrix2.png
得:
EulaToMatrix3.png
Math3D.vector3DAngleVectors
/**
注意上述公式计算出的R(Eula}可以表示为[R(front), R(Left), R(Up)]
而下面的函数计算的是R(front), R(Right), R(Up)
*/
public static function vector3DAngleVectors( angles:Vector3D, forward:Vector3D, right:Vector3D, up:Vector3D ):void{
 var  angle:Number;
 var  sr:Number;
 var  sp:Number;
 var  sy:Number;
 var  cr:Number;
 var  cp:Number;
 var  cy:Number;

 angle = angles.y * (Math.PI*2 / 360);
 sy = Math.sin(angle);
 cy = Math.cos(angle);
 angle = angles.x * (Math.PI*2 / 360);
 sp = Math.sin(angle);
 cp = Math.cos(angle);
 angle = angles.z * (Math.PI*2 / 360);
 sr = Math.sin(angle);
 cr = Math.cos(angle);

 if (forward)
 {
  forward.x = cp*cy;
  forward.y = cp*sy;
  forward.z = -sp;
 }
 if (right)
 {
  right.x = (-1*sr*sp*cy+-1*cr*-sy);
  right.y = (-1*sr*sp*sy+-1*cr*cy);
  right.z = -1*sr*cp;
 }
 if (up)
 {
  up.x = (cr*sp*cy+-sr*-sy);
  up.y = (cr*sp*sy+-sr*cy);
  up.z = cr*cp;
 }
}

2.2. 从世界坐标变换到摄像机坐标

首先我们定义四个坐标系:
  • C(world),世界
  • C(camera_translate),经过位移后摄像机坐标
  • C(camera_translate_rotate),经过位移,再经过yaw, pitch, roll的摄像机坐标,在此坐标系内,x方向的为可见,z方向为上方
  • C(camera_translate_rotate_flip),用来投影的坐标,在此坐标内,-z方向的为可见,y为上方
对应于一个顶点P
  • P(world) = M(translate) * M(rotate) * M(flip) * P(camera)
假设摄像机在世界的位置为pos
EulaToMatrixFlip.png

3. 缩放的实现

缩放有两种实现方式:
  • 设置ViewPort
  • 设置ScissorRectangle + 设置投影矩阵
当需要达到UI不缩放,3D缩放的效果时(主要为了提高性能),需要用到后者。方法如下:
  1. 初始化
    1. 通过Context3D.configureBackBuffer设定ViewPort参数
    2. 获得3D的x,y轴缩放比例
    3. 应用x,y缩放比例到投影矩阵
  2. 渲染
    1. 设置ScissorRectangle
    2. 将3D部分应用投影变换后,调用drawTriangles
    3. 关闭ScissorRectangle
    4. 将UI按照整个ViewPort渲染
一开始可能以为,只要设置投影矩阵的x,y轴缩放就行了。只这样做的话,的确会使得场景变小,但是ViewPort内的可见物体也更多了。因为原先被视锥裁剪掉的三角形,现在有部分因为又落入了视锥内。加上ScissorRectangle正好抵消的这种作用。

0 评论: