(转)Away3D4.0和Starling协作教程

2014-07-29 19:44:00

前言

在新发布的Away 3D 4.0 Gold版本中,包含了一个叫做Stage3DManager的实现Stage3D结合其他ActionScript库的渲染的API。在这个教程中,我们将通过结合Away3D和Starling架构创建一个高效的渲染循环(rendering loop),自从Stage3D加入到Air和Flash Player中,出现了很多新框架,他们通过不断的升级,尝试发挥stage3D的最大性能。其中Away3D在GPU优化方面表现良好,令开发者可以创造出令人难以置信的3D交互体验,类似的,Starling是一个旨在更完全发挥Stage3D性能的2D GPU加速框架。结合这两个东西的前提条件是一些APIs方面的改动,否则这两个框架就会在各自的Stage3D实例中渲染。可惜的是此前没有引擎可以做到这些。令人庆幸的是,随着新的Away3D 4.0 Gold版本发布,提供了融合多框架到一个Stage3D实例中的功能,我们可以轻松的结合无论多少个Away3D和Starling实例。但事实上,并不是所有基于Stage3D的框架都可以被使用——详情请见页面底部。在这个教程中,底层和顶层是Starling层,中间层是Away3D层。

Away3D4.0和Starling协作教程

效果预览

原理介绍

在普通项目中,如果仅仅使用了Away3D,Stage3D内容将在实例内部处理。这虽然操作简单,但是这造成了不同实例间协作的困难。我们需要的是通过一个Stage3D实例来管理所有的Stage 3D框架的实例。这可以通过Stage3DManagerStage3Dproxy类来实现。

    // Stage manager and proxy instances
    // Stage 管理和代理实例
    private var stage3DManager : Stage3DManager;
    private var stage3DProxy : Stage3DProxy

    /**
     * Global initialise function
     *全局初始化函数
     */
    private function init():void
    {
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        initProxies();
    }

    /**
     * Initialise the Stage3D proxies
     *Stage3D代理初始化
     */
    private function initProxies():void
    {
        // Define a new Stage3DManager for the Stage3D objects
        // 为Stage3D对象定义一个新的Stage3DManager ;
        stage3DManager = Stage3DManager.getInstance(stage);

        // Create a new Stage3D proxy to contain the separate views
        //创建一个新的Stage 3D 代理来管理不同的视图。
        stage3DProxy = stage3DManager.getFreeStage3DProxy();
        stage3DProxy.addEventListener(Stage3DEvent.CONTEXT3D_CREATED, onContextCreated);
        stage3DProxy.antiAlias = 8;
        stage3DProxy.color = 0x0;
    }

我们可以通过getInstance()方法调用通过单例模式使用的Stage3DManager类,通过这个实例,我们可以调用下一个可用的Stage实例渲染。但是这不是马上执行的,我们必须侦听Stage3DEvent.CONTEXT3D_CREATED时间,等待Stage分配实例。当我们处理Stage3DProxy时,就可以设置一些参数包括全局抗锯齿,背景颜色。

建立图层

一旦我们侦听到了Stage3DEvent.CONTEXT3D_CREATED事件,我们就可以创建一些渲染用的图层。正如前面所说,我们将有一个Away3D场景以及两个Starling场景,我将详细叙述建立这些渲染图层的条件,而不是每个图层的内容。

    private function onContextCreated( event:Stage3DEvent ):void
    {
        initAway3D();
        initStarling();
        initMaterials();
        initObjects();
        initButton();
        initListeners();
        initListeners();
    }

    /**
     * Initialise the Away3D views 初始化Away3D view。
     */
    private function initAway3D():void
    {
        // Create the first Away3D view which holds the cube objects.
        // 创建第一个包含立方体的Away3D view
        away3dView = new View3D();
        away3dView.stage3DProxy = stage3DProxy;
        away3dView.shareContext = true;

        hoverController = new HoverController( away3dView.camera, null, 45, 30, 1200, 5, 89.999 );
        addChild( away3dView );
        addChild( new AwayStats( away3dView ));
    }

    /**
     * Initialise the Starling sprites
     * 初始化 Starling sprites
     */
    private function initStarling():void
    {
        // Create the Starling scene to add the background wall/fireplace.
        // This is positioned on top of the floor scene starting at the top of the screen.
        // It slightly covers the wooden floor layer to avoid any gaps appearing.
        //创建Starling 场景并且添加背景,这将会被安置在地板场景之上,但会轻微的覆盖地板层,避免缺口出现
    }

其中onContextCreated方法是典型的方式定义了3D场景,对象,材质,事件侦听器,以及实现Starling实例化。在initAway3D方法中,我们和往常一样为Away3D场景建立了View3D对象,另外我们还通过设置了.stage3DProxy属性共享到了Stage3DProxy实例,并且设置.shareContext=true允许共享执行。相似的,在initStarling 方法中创建了Starling场景。每个场景都需要传递一个引用到Starling sprite场景,舞台和分享的Stage3D,同样我们会传递一个定义了视口大小的长方形和一个引用到我们的Stage3D实例。最后,他们都可以通过Stage3DProxy实例的.viewPort.stage3D属性控制。

如果想重新设置Starling Sprite的视口大小,请在Starling外部修改长方体的尺寸,这样Starling.viewPort会返回一个科隆的长方形,而不是原来那个的引用。将它传递给构造器,并且修改外部的长方体,Starling就可以正确的渲染。现在Stage3D的共享实例拥有Away3D场景和Starling Spite层的引用,其他的图层用同样方式创建,正如你在下面的实例中可以看到的一样,你可以通过鼠标转动,拖拽它。 渲染的时候,首先呢,最下一层,也就是最开始渲染的一层,是可以旋转的棋盘格样式的一个Starling图层,在这之上是一个含有5个交叉放置的立方体的Away3D场景,它在一个网格之上。最上面,也是最后渲染的,是一个Starling粒子效果图层。

渲染

当Stage3D被共享时,我们在渲染过程中需要禁用几个函数。从最简单的角度来说,渲染一个场景需要三步,1:场景被清空-clear()方法,2:渲染元素,-drawTriangles();3:显示在屏幕上:present();其中第一步和第三部导致了Stage3D不能被共享。现在呢,away3D和Starling已经被结合到了一个Stage3D的实例中,接下来要考虑的就是在Stage 3DProxy中考虑清理*.clear()和显示.present()了。Stage3DProxy类提供两种渲染设置,两者很相似但是提供对清除clearing和展示presenting*不同的控制。手动控制呢我们需要精确调用Both are described here.Stage3DProxy.clear() 和 .present()方法来渲染,然而自动控制可以轻松地为我们做到这一切。

Stage3D渲染

Away3D with Starling

控制渲染-手动

    /**
     * Set up the rendering processing event listeners
     * 建立渲染进程侦听器
     */
    private function initListeners():void {
        stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }

    /**
     * The main rendering loop
     * 主渲染循环
     */
    private function onEnterFrame(event:Event):void
    {
        // Clear the Context3D object
      // 清空Context3D 对象
        stage3DProxy.clear();

        // Render the Starling animation layer
        // 渲染Starling动画图层
        starlingCheckerboard.nextFrame();

        // Render the Away3D layer
        // 渲染Away3D图层
        away3dView.render();

        // Render the Starling stars layer
        // 渲染Starling 星星图层
        starlingStars.nextFrame();

        // Present the Context3D object to Stage3D
        // 在Stage3D中呈现Context3D
        stage3DProxy.present();
    }

在上面一段代码中,我们侦听了舞台实例的ENTER_FRAME事件,接着在侦听函数中,我们调用了stage3DProxy.clear()方法,然后依次渲染了各个图层,最后调用了stage3DProxy.present()方法,这是我们可以完全地控制图层的渲染顺序和调用清除.clear和呈现.present()方法。

更加轻松的方法-自动控制

    /**
     * Set up the rendering processing event listeners
     * 建立渲染侦听器
     */
    private function initListeners():void
    {
        stage3DProxy.addEventListener( Event.ENTER_FRAME, onEnterFrame );
    }

    /**
     * The main rendering loop
     * 主渲染循环
     */
    private function onEnterFrame( event:Event ):void
    {
        // Render the Starling animation layer
        // 渲染Starling动画图层
        starlingCheckerboard.nextFrame();

        // Render the Away3D layer
        // 渲染Away3D图层
        away3dView.render();

        // Render the Starling stars layer
        // 渲染Starling星星图层
        starlingStars.nextFrame();
    }

这种方法的巧妙之处在于,它的ENTER_FRAME侦听器是加在Stage3DProxy object而不是在舞台中,它自己在内部调用了clear()present()方法,然后由你决定如何渲染。上面的例子中你可以看到在事件侦听方法中被渲染。可以在这里下载演示文件。

源代码