最近无聊把一堆东西移植到这个2D框架上, 这次是条带效果~~ 条带代码来自 ?@朝朝姐夫 做了些修改
和之前模型一样,还是已扩展类的形式存在,并且可以参与Starling的深度排序,坐标定位,缩放等
效果预览,移动鼠标即可
首先创建一个名为 RibbonTest 类 继承自 Starling 的 DisplayObject
[cc lang=”actionscript3″]
public class RibbonTest extends DisplayObject
public function RibbonTest(speed:Number = 0.1, detailLevel:uint = 10, width:uint = 1)
{
super();
this.speed = speed;
this.touchable = false;
ribbonWidth = width;
controlPoints = new Vector.
for(var i:Number = 0;i < detailLevel; i++)
{
controlPoints.push(new Vector3D(0, 0, 0));
}
vertexList = new Vector.
rawPositionsBuffer=new Vector.
rawUvBuffer=new Vector.
rawIndexBuffer=new Vector.
createRibbon();
createProgram();
createBuffer();
}
[/cc]
构造函数中 speed 为缓动的速度,后面会用到经典的缓动公式 (end-start)/speed;
detailLevel 控制点数量,控制点越多条带在转交的效果越细致
[cc lang=”actionscript3″]
private function createRibbon():void
{
for(var i:Number = 0;i < controlPoints.length; i++)
{
var controlVertex:Vector3D = controlPoints[i];
var v1:Vector3D = new Vector3D(controlVertex.x, controlVertex.y, controlVertex.z);
var v2:Vector3D = new Vector3D(controlVertex.x, controlVertex.y, controlVertex.z);
var uvStart:Number = i * (1 / controlPoints.length);
var uvEnd:Number = (i + 1) * (1 / controlPoints.length);
vertexList[i*2]=v1;
vertexList[i*2+1]=v2;
rawUvBuffer[i*4]=i * (1 / controlPoints.length-1);
rawUvBuffer[i*4+1]=0;
rawUvBuffer[i*4+2]=i * (1 / controlPoints.length-1);
rawUvBuffer[i*4+3]=1;
if(i > 0)
{
var lastVIndex:uint = (i+1)*2 – 1;
rawIndexBuffer[(i-1)*6]=lastVIndex – 2;
rawIndexBuffer[(i-1)*6+1]=lastVIndex – 3;
rawIndexBuffer[(i-1)*6+2]=lastVIndex – 1;
rawIndexBuffer[(i-1)*6+3]=lastVIndex – 2;
rawIndexBuffer[(i-1)*6+4]=lastVIndex – 1;
rawIndexBuffer[(i-1)*6+5]=lastVIndex;
}
}
private function createProgram():void
{
var vertexShaderAssembler:AGALMiniAssembler =
new AGALMiniAssembler();
vertexShaderAssembler.assemble
(
Context3DProgramType.VERTEX,
“m44 op, va0, vc0n” +
“mov v0, va1n”
);
var fragmentShaderAssembler1:AGALMiniAssembler
= new AGALMiniAssembler();
fragmentShaderAssembler1.assemble
(
Context3DProgramType.FRAGMENT,
“tex ft0, v0, fs0 <2d,linear,repeat>n”+
“mov oc, ft0n”
);
program = Starling.current.context.createProgram();
program.upload(vertexShaderAssembler.agalcode,fragmentShaderAssembler1.agalcode);
}
private function createBuffer():void
{
var context3D : Context3D = Starling.current.context;
// 上传三角索引
indexBuffer = context3D.createIndexBuffer(rawIndexBuffer.length);
indexBuffer.uploadFromVector(
rawIndexBuffer, 0, rawIndexBuffer.length);
//顶点数据每帧都改变,所以每帧都上传
vertexPositionBuffer = context3D.createVertexBuffer(
rawPositionsBuffer.length/3, 3);
vertexUVBuffer = context3D.createVertexBuffer(
rawUvBuffer.length/2, 2);
vertexUVBuffer.uploadFromVector(rawUvBuffer, 0,
rawUvBuffer.length/2);
}
[/cc]
上面3个函数没啥好说的,分别是初始化顶点,索引,shader 和 缓冲区
最后2个函数
[cc lang=”actionscript3″]
public override function render(support:RenderSupport, parentAlpha:Number):void
{
support.finishQuadBatch();
support.raiseDrawCount();
support.applyBlendMode(false);
var context : Context3D = Starling.current.context;
continueTo(mouseX/scaleX,mouseY/scaleY,0);
context.setTextureAt(0,texture.base);
context.setProgram(program);
//每帧重新上传顶点位置
vertexPositionBuffer.uploadFromVector(rawPositionsBuffer, 0,
rawPositionsBuffer.length/3);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,support.mvpMatrix3D,true);
context.setVertexBufferAt(0,vertexPositionBuffer,0,Context3DVertexBufferFormat.FLOAT_3);
context.setVertexBufferAt(1,vertexUVBuffer,0,Context3DVertexBufferFormat.FLOAT_2);
context.drawTriangles(indexBuffer,0,rawIndexBuffer.length/3);
context.setTextureAt(0,null);
context.setVertexBufferAt(0,null);
context.setVertexBufferAt(1,null);
}
[/cc]
重写 DisplayObject 的 render 方法,获取到 RenderSupport.
support.finishQuadBatch(); //一定要写,否则我们的条带无法参与Starling的画家算法
support.raiseDrawCount();//可写,可不写,更新Starling状态栏的 DRW次数
support.applyBlendMode(false);//可写,可不写,如果我们的条带带有半透明的其他效果的话需要自定义
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,support.mvpMatrix3D,true);
使用Starling的 MVP矩阵来渲染我们的条带,可以使顶点用正交投影渲染并对齐2D坐标系
context.setTextureAt(0,null);
context.setVertexBufferAt(0,null);
context.setVertexBufferAt(1,null);
调用完draw call 后一定要清空使用过的寄存器,因为后续的draw call 可能因为状态未改变导致存储器读取错误
最后
[cc lang=”actionscript3″]
public function continueTo(xPos:Number, yPos:Number, zPos:Number):void
{
for(var i:Number = 0;i < controlPoints.length; i++)
{
var controlVertex:Vector3D = controlPoints[i];
if(i == 0)
{
controlVertex.x = xPos;
controlVertex.y = yPos;
controlVertex.z = zPos;
}
else
{
var previousVertex:Vector3D = controlPoints[i - 1];
controlVertex.x += (previousVertex.x - controlVertex.x) * speed;
controlVertex.y += (previousVertex.y - controlVertex.y) * speed;
controlVertex.z += (previousVertex.z - controlVertex.z) * speed;
}
var v1:Vector3D = vertexList[2 * i];
var v2:Vector3D = vertexList[2 * i + 1];
v1.x = controlVertex.x + ribbonWidth;
v1.y = controlVertex.y + ribbonWidth;
v1.z = controlVertex.z + ribbonWidth;
v2.x = controlVertex.x - ribbonWidth;
v2.y = controlVertex.y - ribbonWidth;
v2.z = controlVertex.z - ribbonWidth;
rawPositionsBuffer[i*6]=v1.x;
rawPositionsBuffer[i*6+1]=v1.y;
rawPositionsBuffer[i*6+2]=v1.z;
rawPositionsBuffer[i*6+3]=v2.x;
rawPositionsBuffer[i*6+4]=v2.y;
rawPositionsBuffer[i*6+5]=v2.z;
}
}
[/cc]
var previousVertex:Vector3D = controlPoints[i - 1];
controlVertex.x += (previousVertex.x - controlVertex.x) * speed;
controlVertex.y += (previousVertex.y - controlVertex.y) * speed;
controlVertex.z += (previousVertex.z - controlVertex.z) * speed;
缓动公式,前面解释过了。
这里就是时时更新顶点及UV
最后放上GitHub 地址