在Starling中创建一个条带效果

最近无聊把一堆东西移植到这个2D框架上, 这次是条带效果~~ 条带代码来自 ?@朝朝姐夫 做了些修改

和之前模型一样,还是已扩展类的形式存在,并且可以参与Starling的深度排序,坐标定位,缩放等

效果预览,移动鼠标即可

首先创建一个名为 RibbonTest 类 继承自 Starling 的 DisplayObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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.<Vector3D>();
            for(var i:Number = 0;i < detailLevel; i++)
            {
                controlPoints.push(new Vector3D(0, 0, 0));
            }
            vertexList = new Vector.<Vector3D>(detailLevel*2,true);
            rawPositionsBuffer=new Vector.<Number>(detailLevel*6,true);
            rawUvBuffer=new Vector.<Number>(detailLevel*4,true);
            rawIndexBuffer=new Vector.<uint>((detailLevel-1)*6,true);

            createRibbon();
            createProgram();
            createBuffer();
        }

构造函数中 speed 为缓动的速度,后面会用到经典的缓动公式 (end-start)/speed;

detailLevel 控制点数量,控制点越多条带在转交的效果越细致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
        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);
        }

上面3个函数没啥好说的,分别是初始化顶点,索引,shader 和 缓冲区

最后2个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        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);
        }

重写 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 可能因为状态未改变导致存储器读取错误

最后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        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;
            }
        }

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

 

发表评论

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.