查看: 2842|回复: 1
打印 上一主题 下一主题

[Flash3d引擎]Everyday Stage3D(二)Triangle

[复制链接]

5472

主题

6

听众

1万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
76544
精华
23

活跃会员 荣誉管理 突出贡献 优秀版主 论坛元老

跳转到指定楼层
楼主
发表于 2012-12-14 12:02:29 |只看该作者 |倒序浏览
        上一篇中我们通过设备开启GPU,并创建了一个stage3D舞台。这一篇中我将给大家带来一个可以看得见的demo。

        从副标题中我们可以看出,这篇讲的和三角形有关系。笔者多年前接触3D的时候会经常疑问,为什么现在所有的3D技术都要从三角形开始,而非其他形状。其实仔细想想也非常简单,因为在一个3D可视化的界面中,我们能够从几何的概念上将一个画面元素分为三种,点,线,面。点是几何中最基本的单位,而两点成线则标识拥有两个点可以连接为一条直线,面则是由三个点组成的,正所谓三点成面。而我们在3D画面中所看到的所有物体都是由面来组成的,换句话说,三角形的面正式我们视图元素中的最小单位。在stage3D中我们没有直接可操作面的API,我们唯一能操作的是点,这也是大部分3D技术的绘图模式。另外还有一种绘图模式称之为“原子级别渲染”,这种技术对于硬件要求之高,通常用于医疗和科研项目中。

        那么我们要在画面中显示一个三角形需要的则是3个点的数据,我们可以将3个点的坐标值上传到GPU,并且制定他的渲染顺序,剩下的渲染工作就完全交给GPU来执行了。

        在本系列教程的前半部分,我们只会涉及到2D内容,因为2D与3D底层的渲染规则实际上是相同的,所以理解2D的渲染方法,3D的也就迎刃而解了。那么如何编写程序来让我们的GPU老老实实的工作呢。我们先来看一段代码:




?

   
        
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            
            
            
            //三角形顶点数据
            var triangleData:Vector.<Number> = Vector.<Number>([
            //  x, y, r, g, b
            0, 1, 0, 0, 1,
            1, 0, 0, 1, 0,
            0, 0, 1, 0, 0
            ]);
            this._vb = this._context3d.createVertexBuffer( triangleData.length/5, 5 );
            this._vb.uploadFromVector( triangleData,0,triangleData.length/5 );
            
            
        
   







这段代码中我们定一个数组,数组内的数据则是我们三角形三个顶点的数据,大家注意格式,由于我们需要显示出一个三角形的,所以我们在后面加上了一个RGB颜色值,一边我们看到效果。这里的_vb变量是一个VertexBuffer3D类型对象,它的作用简单而明了,就是负责顶点数据上传的,你在这个类的API文档中只能找到三个function,通过名字也可以轻易知道他们的作用。由于我们使用的是Vector数据类型的顶点数据,那么我们也就要对应的使用uploadFromVector这个API来上载数据。另外一种二进制的格式上传后面我将为大家做详细介绍。

        这里要注意的地方是,VertexBuffer3D对象并不能简单的通过new操作来实现创建,我们只能通过context3D来创建VertexBuffer3D对象。创建的方法在上面也有,请注意参数的内容,简单解释一下,

参数一:顶点的数量,我们这里有三个顶点,由于每个顶点包含5个数据,所有需要用数组长度除以5.

参数二:每个顶点数据的长度,因为我们每个顶点数据包含xyrgb五个值,所以参数为5.

       好,关于顶点的内容先说道这里,下面我们来说说顶点索引。

       当我们要渲染一个场景的时候,我们可能拥有上百万个三角形,每个三角形有三个顶点,以一百个三角形为例,最糟糕的情况是我们拥有300个顶点数据(具体为什么糟糕我将在后面的文章中讲解)。你需要告诉GPU每个顶点的渲染顺序,这就和我们每天做北京地铁一样,上车的时候大家都需要排队,如果大家不排队,那么将会酿成惨案。这里我们需要通过上载一条数据,告诉GPU哪一个顶点排在前面哪一个顶点排在后面,让大家依此接受GPU的渲染。具体操作代码如下:




?

   
        
            
            1
            2
            3
            4
            5
            6
            
            
            
            //三角形索引数据
            var indexData:Vector.<uint> = Vector.<uint>([
            0, 1, 2
            ]);
            this._ib = this._context3d.createIndexBuffer( indexData.length );
            this._ib.uploadFromVector( indexData, 0, indexData.length );
            
            
        
   







        由于顶点顺序非常的简单,是一个线形的数据,所以我们用一个数据表示即可,数组中的内容则是刚才顶点数据的下标,我们有三个顶点数据,那么他们对应的下标则是0,1,2。这里没有复杂的顺序关系,所以直接写入顺序即可。顶点索引的对象_ib为IndexBuffer3D类型,同样不可以通过new来创建,使用context3D中的createIndexBuffer函数来创建即可。参数则为顶点索引的长度。

最后通过uploadFromVector将顶点索引数据上载到GPU。

   到目前位置,我们执行程序你看不到任何效果,但是你刚才所做的操作,已经将数据全部上载到了GPU的寄存器内。换句话说,数据已经准备好了,后面的工作要告诉GPU如何去渲染我们的画面,也就是大家说的开始要编写shader了。

        在开始编写那些讨人厌的shader之前,我先来想大家说明一件事情。我曾经不停的寻找过stage3D的学习方法,当时每当我想到AGAL的时候,我发现这部分内容的需诶曲线非常之大。而且这并非一个线性的学习过程,我们需要并行学习多种知识才能将里面的内容融会贯通。所以后面的内容可能看上去并无任何关联,但是每一个都需要认真学习。当你遇到一个非常复杂而难缠的问题时,请不要忘记你可能在某一天的某一个时间,恰恰实践过一个简单的小程序,而这个原理碰巧可能帮到你。

         shader代码如下:




?

   
        
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            
            
            
            //AGAL
            var vagalcode:String = "mov op, va0
            " +
            "mov v0, va1";
            var vagal:AGALMiniAssembler = new AGALMiniAssembler();
            vagal.assemble( Context3DProgramType.VERTEX, vagalcode );
            var fagalcode:String = "mov oc, v0";
            var fagal:AGALMiniAssembler = new AGALMiniAssembler();
            fagal.assemble( Context3DProgramType.FRAGMENT, fagalcode );
            this._pm = this._context3d.createProgram();
            this._pm.upload( vagal.agalcode, fagal.agalcode );
            
            
        
   





这里的AGALMiniAssembler类是adobe为我们提供的一个工具类,可以将我们字符串形式的AGAL代码转为AGAL的二进制格式。希望大家不要重复早轮子了,这个东西没太多意义。如果为了学习,你也可以进行一个逆向工程的demo。就是将已经编译好的一个二进制格式的shader程序还原为AGAL。

        上载AGAL的操作工作完全归功于Program3D这个类。他的API也非常的简单,甚至比VertexBuffer3D还要简单。大家可以自行参考API文档。这里要说明的是我不在此对这段AGAL进行讲解,因为内容扩展出来非常的多,下一篇内容中我将详细讲解。

        到此位置,我们所需要的所有数据都已经完成,并且当你程序运行的时候这些内容已经存在与GPU当中。后面我们要做的是将数据取出来,供AGAL计算使用。具体代码如下:




?

   
        
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            
            
            
            private function draw():void
            {
            this._context3d.clear( 0, 0, 0);
            this._context3d.setVertexBufferAt( 0, this._vb, 2, Context3DVertexBufferFormat.FLOAT_2 );
            this._context3d.setVertexBufferAt( 1, this._vb, 2, Context3DVertexBufferFormat.FLOAT_3 );
            this._context3d.setProgram( this._pm );
            this._context3d.drawTriangles( this._ib );
            this._context3d.present();
            }
            
            
        
   





这段代码目前我讲解了你可能也很难理解,后面学习过AGAL之后你就会明白为什么这些API参数是这个样子的了。

其实这段代码简单的可以分为四部。

一、清除画面内容

二、设置数据供AGAL使用

三、执行渲染

四、将渲染后结果打印到我们的画面当中。

         编写好代码之后我们来debug一下,如果你的代码正确那么你应该看到的是下面这幅图片。










?

   
        
            
            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
            76
            77
            78
            79
            80
            81
            82
            83
            84
            85
            86
            87
            88
            89
            90
            
            
            
            package
            {
            import com.adobe.utils.AGALMiniAssembler;
            import flash.display.Sprite;
            import flash.display.Stage3D;
            import flash.display3D.Context3D;
            import flash.display3D.Context3DProgramType;
            import flash.display3D.Context3DRenderMode;
            import flash.display3D.Context3DVertexBufferFormat;
            import flash.display3D.IndexBuffer3D;
            import flash.display3D.Program3D;
            import flash.display3D.VertexBuffer3D;
            import flash.events.ErrorEvent;
            import flash.events.Event;
            import flash.events.MouseEvent;
            public class stage3ddemo1 extends Sprite
            {
            private var _stage3d:Stage3D;
            private var _context3d:Context3D;
            public function stage3ddemo1()
            {
            trace( "stage3D层数量:",stage.stage3Ds.length );
            if( stage.stage3Ds.length > 0 )
            {
            this._stage3d = stage.stage3Ds[0];
            this._stage3d.addEventListener(Event.CONTEXT3D_CREATE,created_handler);
            this._stage3d.addEventListener(ErrorEvent.ERROR, created_error_handler );
            this._stage3d.requestContext3D( Context3DRenderMode.AUTO );
            }
            }
            private function created_error_handler(evt:ErrorEvent):void
            {
            trace("GPU启动失败或设备丢失!");
            }
            private function created_handler (evt:Event):void
            {
            trace( "GPU设备类型:",this._stage3d.context3D.driverInfo );
            this._context3d = this._stage3d.context3D;
            this._context3d.configureBackBuffer( 300,300,0,***e);
            //   stage.addEventListener(MouseEvent.CLICK, click_handler );
            this.addTriangle();
            this.draw();
            }
            private var _vb:VertexBuffer3D;
            private var _ib:IndexBuffer3D;
            private var _pmrogram3D;
            private function addTriangle():void
            {
            //三角形顶点数据
            var triangleData:Vector.<Number> = Vector.<Number>([
            //  x, y, r, g, b
            0, 1, 0, 0, 1,
            1, 0, 0, 1, 0,
            0, 0, 1, 0, 0
            ]);
            this._vb = this._context3d.createVertexBuffer( triangleData.length/5, 5 );
            this._vb.uploadFromVector( triangleData,0,triangleData.length/5 );
            //三角形索引数据
            var indexData:Vector.<uint> = Vector.<uint>([
            0, 1, 2
            ]);
            this._ib = this._context3d.createIndexBuffer( indexData.length );
            this._ib.uploadFromVector( indexData, 0, indexData.length );
            //AGAL
            var vagalcode:String = "mov op, va0
            " +
            "mov v0, va1";
            var vagal:AGALMiniAssembler = new AGALMiniAssembler();
            vagal.assemble( Context3DProgramType.VERTEX, vagalcode );
            var fagalcode:String = "mov oc, v0";
            var fagal:AGALMiniAssembler = new AGALMiniAssembler();
            fagal.assemble( Context3DProgramType.FRAGMENT, fagalcode );
            this._pm = this._context3d.createProgram();
            this._pm.upload( vagal.agalcode, fagal.agalcode );
            }
            private function draw():void
            {
            this._context3d.clear( 0, 0, 0);
            this._context3d.setVertexBufferAt( 0, this._vb, 2, Context3DVertexBufferFormat.FLOAT_2 );
            this._context3d.setVertexBufferAt( 1, this._vb, 2, Context3DVertexBufferFormat.FLOAT_3 );
            this._context3d.setProgram( this._pm );
            this._context3d.drawTriangles( this._ib );
            this._context3d.present();
            }
            private function click_handler(evt:MouseEvent):void
            {
            this._context3d.dispose();
            }
            }
            }
            
            
        
   



完整代码请看上表。更多Stage3D学习教程尽在web3D纳金网http://www.narkii.com/

分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

5472

主题

6

听众

1万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
76544
精华
23

活跃会员 荣誉管理 突出贡献 优秀版主 论坛元老

沙发
发表于 2012-12-14 14:02:30 |只看该作者
Flash3d引擎关联教程:



[Flash3d引擎]Everyday Stage3D(六)Texture



[Flash3d引擎]Everyday Stage3D(五)流化你的数据




[Flash3d引擎]Everyday Stage3D(四)AGAL数据操作




[Flash3d引擎]Everyday Stage3D(三)AGAL的基本概念






[Flash3d引擎]Everyday Stage3D教程(一)


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2025-1-27 22:30 , Processed in 0.142299 second(s), 32 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部