在stage3D中实现火炬之光遮挡透视的X-ray效果实际上很简单。
渲染流程如下

1.渲染所有物体+场景
2.正常渲染主角
3.使用X-ray Shader再渲染一次主角

这个渲染顺序是必须的,必须把遮挡物体都事先渲染完毕。
之后展开第3点看看具体的渲染流程

设置 depthFunc 为 Greater, writeDepth 为 false
此时渲染的主角只会显示在 遮挡物体上
之后对该角色的像素着色器,使之显示单一颜色,无论蓝色,黄色,红色都可以
为了使Shader只渲染出轮廓,可以将 相机位置当做灯光位置和模型的法线点乘,求出夹角,将该值作为输出像素的透明度值和RGB进行混合输出。

像素着色器AGAL如下
[cc lang=”actionscript3″]
public override function getFragmentProgram():ByteArray
{
var shaderConstant : ShaderConstants;
var index : uint;
index = m_params.fragmentShaderConstants.push(new ShaderConstants(fcXray)) – 1;
shaderConstant= m_params.fragmentShaderConstants[index];
shaderConstant.vector = Vector.([
10/255,72/255,247/255,0.5,
1,0,0,0]);
shaderConstant.numRegisters = 2;

var code : String =
“nrm ft1.xyz v”+vProjPos+”.xyzn” +
“dp3 ft0.a ft1.xyz fc”+fcCameraPos+”.xyzn”+
“sat ft0.a ft0.an”+
“mov ft0.r fc”+fcXray+”.rn”+
“mov ft0.g fc”+fcXray+”.gn”+
“mov ft0.b fc”+fcXray+”.bn”+
“mul ft0.rgb ft0.rgb ft0.aaan”+
“mov oc ft0n”;

return new AGALMiniAssembler().assemble(Context3DProgramType.FRAGMENT, code);
}
[/cc]

fcXray 的值为
[10/255,72/255,247/255,0.5,1,0,0,0]
占用两个寄存器,前3个值可以调节输出的颜色
fcCameraPos 为外部传入的相机位置,已经归一化和反转过

因为工作原因,开始转向cocos2d-x开发方向了。
自然的,凭着之前引擎的经验偏向底层渲染研究。

在此期间看了两本书
《cocos2d-x 权威指南》
《cocos2d-x 高级开发教程》
不得不说,第一本书完全是API介绍,也许适合新手入门,但是于我,只是烂书一本。
第二本书还是不错的,最后的项目有全套源码,教程的风格也很有我的风格,哈哈,就是文章中不一定贴全代码,只贴核心,后期还要自己领会补全。

言归正传,在 《高级开发教程》 中有一篇是实现海底水纹效果的文章,里面代码不全,且代码和Shader并没有对应起来,于是我决定按照自己思路来将其补全,并贴上完整源码。

先上效果图:
waveCover
动态GIF图地址: http://pan.baidu.com/share/link?shareid=1858640040&uk=3221530571

Continue reading

原本没计划使用四元数来渲染蒙皮动画的,但是由于stage3D的限制,因此考虑在AOI3D中,使用四元数来渲染吧。

由于Adobe的畏首畏尾,尽可能的向下兼容,又不肯把兼容的选择权交给开发者,因此stage3D只提供了128个常量寄存器。
在3D程式中,一般使用 4*4 矩陣來描述骨骼的旋轉-位移-縮放。 而一個常量寄存器只能存儲 4個浮點型(在DX10中已经支持整数型了,不过stage3D只有DX9级别),
因此我们只能渲染 128/4 = 32 根骨骼, 为了确定模型的位置,我们还需要上传 ModelViewProjection 矩阵, 那么我们只能使用31根骨骼了,而且还要放弃各种灯光及滤镜效果了。

使用四元数的优势,开源引擎Ogre的模型文件就是使用四元数进行蒙皮了,这也是AOI3D能支持蒙皮动画的原因。 一个四元数使用 x,y,z,w 来表示 3个轴的旋转,因此它只需要使用1个寄存器, 之后再使用一个寄存器来存储位移即可。 对于缩放,一般蒙皮动画的缩放都是 1, 因此可以忽略。 那么我们可以渲染 124 / 2 = 62 跟骨头了。

这里不讲解四元数的原理,直接说使用。
你可以通过支持四元数的动画文件直接解析出四元数的值,也可以通过 Matrix3D 来获取四元数

[cc lang=”actionscript3″]
var datas : Vector. = matrix3D.decompose(Orientation3D.QUATERNION);
[/cc]

datas 是一个数组,其实[0]是位移,[1]是四元数,[2]是缩放
有了四元数后,我们将其通过常量上传到Shader中,然后再Shader中,重新组装成一个 3 * 4 矩阵,然后其他都和之前的一样。

四元数转换回矩阵的方式(CPU模拟)
[cc lang=”actionscript3″]
var quaIndex : uint = index / 2;
var rotation : Vector3D = m_jointConstant[quaIndex];
var translate : Vector3D = m_jointConstant[quaIndex + 1];

var mat : Matrix3D = new Matrix3D();

var vt0 : Vector3D = new Vector3D();
vt0.x = 2 * rotation.x * rotation.y;
vt0.y = 2 * rotation.x * rotation.z;
vt0.z = 2 * rotation.x * rotation.w;
vt0.w = 2 * rotation.y * rotation.z;
var vt1 : Vector3D = new Vector3D();
vt1.x = 2 * rotation.y * rotation.w;
vt1.y = 2 * rotation.z * rotation.w;
vt1.z = rotation.x * rotation.x;
vt1.w = rotation.y * rotation.y;
var vt2 : Vector3D = new Vector3D();
vt2.x = rotation.z * rotation.z;
vt2.y = rotation.w * rotation.w;

var rawData : Vector. = mat.rawData;
xx – yy – zz + ww
rawData[0] = vt1.z – vt1.w – vt2.x + vt2.y;
2xy – 2zw
rawData[1] = vt0.x – vt1.y;
2xz + 2yw
rawData[2] = vt0.y + vt1.x;
0
rawData[3] = translate.x;
2xy + 2zw
rawData[4] = vt0.x + vt1.y;
-xx + yy – zz + ww
rawData[5] = vt1.w – vt1.z – vt2.x + vt2.y;
2yz + 2xw
rawData[6] = vt0.w – vt0.z;
0
rawData[7] = translate.y;
2xz + 2yw
rawData[8] = vt0.y – vt1.x;
2yz – 2xw
rawData[9] = vt0.w + vt0.z;
-xx – yy + zz + ww
rawData[10] = vt2.x – vt1.z – vt1.w + vt2.y;
0
rawData[11] = translate.z;
0
rawData[12] = 0;
0
rawData[13] = 0;
0
rawData[14] = 0;
1
rawData[15] = 1;

mat.rawData = rawData;
[/cc]

这个矩阵的解析已经被手动转置过了,如果使用CPU渲染,需要手动转置回来,又或者在创建rawData的时候就设置好其索引。