在Starling中创建一个条带效果

最近无聊把一堆东西移植到这个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.(detailLevel*2,true);
rawPositionsBuffer=new Vector.(detailLevel*6,true);
rawUvBuffer=new Vector.(detailLevel*4,true);
rawIndexBuffer=new Vector.((detailLevel-1)*6,true);

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 地址  

发表评论

电子邮件地址不会被公开。 必填项已用*标注