BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

使用Proscenium框架

| 作者 Adobe 关注 0 他的粉丝 发布于 2011年10月26日. 估计阅读时间: 36 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

目录

需求

预备知识

您应该拥有使用ActionScript编程和使用Flash Professional构建3D项目的一定经验。完成本教程不需要拥有Proscenium框架使用经验。

本教程中引用的示例文件包含在Proscenium框架中。

用户水平

中级

需要的产品

示例文件

在本教程中,您将了解一些使用Proscenium框架创建3D示例项目的不同的ActionScript类文件,该框架是一个构建于Adobe Flash Platform Stage3D API之上的ActionScript 3代码库,支持快速开发交互式3D内容。这篇快速介绍的目标是让您熟悉在Adobe Flash Professional中使用Proscenium框架控制3D元素。

开始之前,请确保从Adobe Labs下载了Proscenium框架,并将该ZIP文件解压到了您的桌面上,以便您在学习本教程的每一节时可以找到并打开相应的AS文件。您可以分析代码,查看每一步是如何在程序中实现的。

示例项目类文件位于Proscenium框架ZIP文件的code\ProsceniumTutorials\src文件夹中。设置了Proscenium项目之后,即可编译和运行这些示例。要设置项目,请确保阅读了示例文件中提供的设置说明。

以下各节介绍如何创建3D对象并将它们添加到到场景中以便显示。您还将学习如何更改3D对象的材料属性,移动对象和添加阴影。在本教程的最后一节,您将使用一个扩展Sprite类的类,查看如何构建一个Proscenium应用程序,而不是用其他各节中所使用的BasicDemo harness类。通过扩展Sprite类,您在使用3D对象和配置事件处理函数时将获得更多控制权。

理解世界坐标系统和3D照相机

在您阅读使用本示例项目的说明时,请记住世界坐标系统的方向。y轴始终指向上方。默认情况下,照相机指向-z方向,这意味着x轴指向屏幕的右侧(参见图1)。

图1. 世界坐标系统的方向。

创建简单的3D形状并将它们添加到场景中

首先,您将创建一些形状并将它们添加到场景中。如果还未这么做,请确保从Adobe Labs下载了Proscenium并将该ZIP文件解压到您的桌面。打开Flash Professional中名为Tutorial01_SimpleShapes.as的文件(位于code\ProsceniumTutorials\src文件夹中)。第一节的目标是让对象在3D场景中显示(参见图2)。

图2. 使用ActionScript构建形状并将它们放在场景中。

  1. 启动Flash Professional,打开code\ProsceniumTutorials\src文件夹中名为Tutorial01_SimpleShapes.as的文件。
  2. 花时间分析一下该类中的函数。

代码非常简单。该代码创建一个平面、一个立方体、一个球体和一个圆环,然后将这些3D形状添加到场景中。

要创建基本的形状,您将使用ProceduralGeometry类,如下面提供的代码示例中所示。

  • MaterialStandard是实现各种渲染模型的material类。在本教程中,创建了一种绿色的材料,并使用它作为平面的材料。
  • SceneMesh是一个包含网格的基本的场景图形节点。(其他类型的场景图形节点包含SceneLight、SceneCamera、SceneSkyBox等。所有节点类名称都以单词Scene开头。
  • BasicDemo.scene是场景图形的根节点。BasicDemo自动创建一些SceneLight对象并包含重要的事件处理函数以实现照相机控制。

创建形状并将它们添加到场景中的代码如下所示:

package
{
   import com.adobe.scenegraph.*;
   
   import flash.display.*;
   import flash.display3D.*;
   import flash.geom.*;
   
   public class Tutorial01_SimpleShapes extends BasicDemo
   {
      public function Tutorial01_SimpleShapes()
      {
         super();
      }
      
      override protected function initModels():void
      {
         // create plane material
         var material:MaterialStandard = new MaterialStandard();
         material.diffuseColor.set( 0, .4, 0 );
         material.specularColor.set( .8, .8, .8 );
         material.ambientColor.set( .2, .2, .2 );

         // create a plane and add it to the scene
         var plane:SceneMesh = MeshUtils.createPlane( 50, 50, 20, 20, 
null, "plane" );
         plane.appendTranslation( 0, -2, 0 );
         scene.addChild( plane );
         
         // create a cube and add it to the scene
         var cube:SceneMesh = MeshUtils.createCube( 5 );
         cube.appendTranslation( 0, 6, 0 );
         scene.addChild( cube );
         
         // create a torus and add it to the scene
         var torus:SceneMesh = MeshUtils.createDonut( .25, 1.5, 50, 10, 
null, "torus" );
         torus.appendTranslation( 10, 2, 0 );
         var rotAxis:Vector3D = new Vector3D( 1,1,1 );
         rotAxis.normalize();
         torus.appendRotation( 45, rotAxis );
         scene.addChild( torus );
         
         // create a sphere and add it to the scene
         var sphere:SceneMesh = MeshUtils.createSphere( 3, 50, 50, 
null, "sphere" );
         sphere.setPosition( -10, 2, 0 );
         scene.addChild( sphere );         
      }
   }
}

创建3D对象动画并更改它们的材料属性

在本节中,您将学习如何创建立方体形状的实例。您还将看到如何使用onAnimate()函数更改它的位置,基于形状的位置更改它的材料(参见图3)。

图3. 更改场景中的形状位置。

  1. 使用Flash Professional打开code\ProsceniumTutorials\src文件夹中名为Tutorial02_AnimationAndMaterial.as的名称。
  2. 检查该类中的函数。

在检查代码时,请注意onAnimate()方法使用了时间t和自上一次调用以来已过去的时间dt来调用。onAnimate()方法支持您使用SceneMesh.appendTranslation方法更改对象的位置。

在此示例中,使用ProceduralGeometry.createCube方法创建了一个立方体。使用SceneMesh.instance()方法创建了立方体的另一个实例。使用此战略,两个立方体共享相同的顶点和索引缓冲区。

默认情况下,实例化的立方体将使用名为cubeMtrl的相同材料。此材料属性可以使用SceneMesh.materialBindings更改为使用一种不同的材料。您首先创建一种新材料并将它绑定到实例化的立方体。在这之后,您可以根据需要更改一个实例的材料属性。

override protected function initModels():void
{
   …

   // create a new standard material
   var material:MaterialStandard = new MaterialStandard( "cubeMtrl" );      material.diffuseColor.set( 0, 1, 0 );

   var cube:SceneMesh = MeshUtils.createCube( 5, material, "cube" );
   cube.appendTranslation( 0, 6, -10 );
   scene.addChild( cube );

   // create an instance of the cube (mesh data is shared)
   _cubeInstanced = cube.instance( "cube-instanced" );
   _cubeInstanced.appendTranslation( 0, 6, 0 );
   scene.addChild( _cubeInstanced );

   …         
}

// animation is performed in onAnimate
override protected function onAnimate( t:Number, dt:Number ):void
{
   _cubeInstanced.setPosition( Math.cos( t ) * 3, 6, Math.sin( t ) * 3 );

   // Since a SceneMesh can have multiple submeshes of different materials, 
   // and since the submeshes can be shared amongst multiple SceneMesh instances,
   // direct access to the material is not provided.
   // To change material, one can create a new material and add it to the binding
   // Note that the material name is used to indicate which material is remapped.
   if ( !_cubeInstanced.materialBindings[ "cubeMtrl" ] )
      _cubeInstanced.materialBindings[ "cubeMtrl" ] = new MaterialStandard( "cubeMtrl" );
         
   if ( _cubeInstanced.position.x < 0 )
      _cubeInstanced.materialBindings[ "cubeMtrl" ].diffuseColor.set( 1, 0, 0 );
   else
      _cubeInstanced.materialBindings[ "cubeMtrl" ].diffuseColor.set( 0, 1, 0 );
}

在3D场景中定义光线转换器来添加阴影

在本节中,您将探索如何向3D场景添加阴影,向光线添加转换器(参见图4)。

图4. 阴影为3D场景提供了深度。

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial03_Shadows.as的文件。
  2. 检查该类中的代码。

启用阴影的流程很简单。如果设置了属性BasicDemo.shadowMapEnabled,启用了BasicDemo类的两种默认光线来显示阴影。

下一步是定义光线的转换器。要完成此任务,您可以使用Proscenium中一个名为SceneLight.addToShadowMap的方法。一种简单的方式是添加BasicDemo.scene(它将生成光线的场景图形节点转换器)来更新本教程中的light[1]。

另一种方法是定义每种光线的具体的转换器。例如,在下面的代码中查看是如何独立控制本教中的lights[0]和lights[1]的。这通常是一个不错的注意,因为这可以确保地面将不会转变来自场景中的light[0]的阴影。

override protected function initModels():void
{

   …

   if ( lights )
   {
      lights[0].setPosition( 10, 20, 10);
      if ( lights[0].shadowMapEnabled )
         lights[0].addToShadowMap( _cubeInstanced, cube, torus, sphere );   // define casters
      if ( lights[1].shadowMapEnabled )
         lights[1].addToShadowMap( scene );   // just set every scene graph object as caster
   }
}

从外部文件加载3D模型

在本节中,您将学习如何引入在3D图形程序中创建的3D模型。您可以使用Proscenium框架从外部文件夹在3D模型。本示例演示了如何加载天空问题和一种3D模型(参见图5)。

图5. 您可以使用外部模型文件将3D模型加载到Flash项目中。

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial04_LoadingModels.as的文件。
  2. 检查类中的代码,查看如何将模型加载到场景中。

名为SceneSkyBox的对象是专为天空提供的场景图形节点对象。要了解关于雾化选项的更多信息,请参阅TestFog。

6个天空表面的纹理图像文件名称定义如下:

protected static const SKYBOX_FILENAMES:Vector.<String> = new Vector.<String>(6,true);
    SKYBOX_FILENAMES[ 0 ] = "../res/textures/skybox/px.png";
    SKYBOX_FILENAMES[ 1 ] = "../res/textures/skybox/nx.png";
    SKYBOX_FILENAMES[ 2 ] = "../res/textures/skybox/py.png";
    SKYBOX_FILENAMES[ 3 ] = "../res/textures/skybox/ny.png";
    SKYBOX_FILENAMES[ 4 ] = "../res/textures/skybox/pz.png";
    SKYBOX_FILENAMES[ 5 ] = "../res/textures/skybox/nz.png";

此外,此示例加载一个棕榈树模型。要同时加载天空纹理和棕榈树模型,代码会为每个对象启动一个加载器。当加载完成时,每个加载器发出一个事件。在这个示例项目中,两个加载任务通过以下这些步骤来管理:

  1. 加载天空纹理加载器。
  2. 当加载完成时,调用imageLoadComplete处理函数。
  3. 该处理函数创建一个SceneSkyBox对象,将它添加到场景中。
  4. 启动棕榈树模型加载器。
  5. 当完成棕榈树模型的加载时,调用loadComplete处理函数。
  6. 此处理函数包含将该树模型添加到场景中的代码。

在下面的示例中查看加载外部文件的代码:

override protected function initModels():void
{
   var plane:SceneMesh = MeshUtils.createPlane(
100,100,20,20,null, "plane" );
   plane.transform.appendTranslation( 0, -2, 0 );
   scene.addChild( plane );

   LoadTracker.loadImages( SKYBOX_FILENAMES, imageLoadComplete );
}

protected function imageLoadComplete( bitmaps:Dictionary ):void
{
   var bitmapDatas:Vector.<BitmapData> = new Vector.<BitmapData>( 6, true );
   var bitmap:Bitmap;
   for ( var i:uint = 0; i < 6; i++ )
      bitmapDatas[ i ] = bitmaps[ SKYBOX_FILENAMES[ i ] ].bitmapData;
         
   // sky
   _sky = new SceneSkyBox( bitmapDatas, false );
   scene.addChild( _sky );   // skybox must be an immediate child of scene root
   _sky.name = "Sky"
         
   _treeLoader = new OBJLoader( "../res/models/PalmTrees/PalmTrees.obj" );
   _treeLoader.addEventListener( Event.COMPLETE, loadComplete);
}

protected function loadComplete( event:Event ):void
{
   var tree:SceneNode = new SceneNode( "PalmTrees" );
   var manifest:ModelManifest = _treeLoader.model.addTo( tree );
   scene.addChild( tree );
}

扩展Sprite类以创建Proscenium应用程序

本教程中描述的所有前述示例使用BasicDemo工具改进事件处理函数并添加其他控件。在本教程的最后一节中,您将看到如何在不使用BasicDemo工具的情况下创建Proscenium应用程序,方法是直接扩展Sprite类。

public class Tutorial_SpriteBased extends Sprite

通过扩展Sprite类,您获得了对如何向舞台添加子画面的更多控制权。您在创建Stage3D上下文,配置和实现事件处理函数时也有更多选项(参见图6)。

图6. 您可以扩展Sprite类以创建Proscenium应用程序。

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial05_SpriteBased.as的文件。
  2. 检查该类中的代码,查看如何扩展Sprite类。

使用Instance3D创建Proscenium类

Instance3D是一个基本的Proscenium类,用于维护3D Molehill上下文。您将在希望使用Proscenium框架时使用Instance3D类。在本例中,以下代码创建一个新的Instance3D实例:

instance = new Instance3D( stage3D.context3D );

注意:在前面使用BasicDemo类的示例中,它自动创建了一个名为BasicDemo.instance的Instance3D对象。

设置场景图形根

在以前的教程中,根名为scene,它使用BasicDemo.scene设置。但是,因为此示例未使用BasicDemo类,所以根只是简单的Instance3D.scene,在本教程中为instance.scene。

注意:Instance3D是一个类名称,instance是一个变量。

终结应用程序

设置了场景图形根之后,创建3D模型并将它们添加到场景中的流程涉及到与前面相同的步骤。这个示例创建一种光线,使用转换器实现阴影。另请注意,该实例包含按键和鼠标事件处理函数以处理用户交互。该函数包含打开雾化效果的代码。

使用物理学使物体下落、碰撞和弹跳

在本节中,您将学习如何使物体下落、碰撞和弹跳。

图7. 使用物理学使物体下落、碰撞和弹跳

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial06_SimplePhysics.as的文件。
  2. 检查该类中的函数。

物理学将通过创建一个PelletManager对象来实现,该对象提供了用于创建启用了物理学的SceneMesh对象的方法。例如,可调用createStaticInfinitePlane创建地面,立方体可由createBox创建,球体可由createSphere创建:

    // create a plane and add it to the scene
    var plane:SceneMesh = mSim.createStaticInfinitePlane( 1000, 1000, 2, 2, material, "plane" );
    plane.appendTranslation( 0, -2, 0 );
    scene.addChild( plane );
    
    // create cubes and add it to the scene
    var cube0:SceneMesh = mSim.createBox( 5, 5, 5 );
    cube0.appendRotation( 40, Vector3D.X_AXIS );
    cube0.appendTranslation( 0, 6, 0 );
    scene.addChild( cube0 );
    
    // create a sphere and add it to the scene
    var sphere:SceneMesh = mSim.createSphere( 3, 32, 16 );
    sphere.setPosition( -10, 2, 0 );
    scene.addChild( sphere ); 

向四边形分配纹理

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial07_Texture.as的文件。
  2. 检查该类中的函数。

纹理图可通过以下代码嵌入:

[Embed( source="/../res/content/foliage022.jpg" )]
    protected static const BITMAP:Class;

使用此数据,可创建一种纹理图并用于漫反射图,如下面的代码中所示:

var textureMap:TextureMap = new TextureMap( new BITMAP().bitmapData ); 
material.diffuseMap = textureMap;

加载COLLADA动画文件

在本节中,您将看到加载COLLADA动画文件的代码(参见图8)。

图8. 加载一个COLLADA动画文件

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial08_LoadedAnimation.as的文件。
  2. 检查该类中的函数。

要加载COLLADA文件,参考此代码:

public var loader:ColladaLoader;
override protected function initModels():void {
    loader = new ColladaLoader( "../res/content/AnimatedBones.dae" );
    loader.addEventListener( Event.COMPLETE, onLoad );
    }

当加载完成时,将该模型添加到场景中并将动画绑定到场景:

public var animations:Vector.<AnimationController>, initialized:Boolean;
public function onLoad( event:Event ):void {
    var manifest:ModelManifest = loader.model.addTo( scene );
    animations = loader.model.animations;
    for each ( var anim:AnimationController in animations ) {
        anim.bind( scene );
    }
    
    initialized = true;
}

动画通过递增事件来实现:

override protected function onAnimate( t:Number, dt:Number ):void {
    if ( !initialized ) return;
    for each ( var anim:AnimationController in animations )
    {
        anim.time = ( t % anim.length ) + anim.start;
    }
}

使用过程几何学从头创建网格

  1. 打开code\ProsceniumTutorials\src文件夹中名为Tutorial_09_ProceduralGeometry.as的文件。
  2. 检查该类中的函数。

延伸阅读

我们希望本教程为向您概述了如何使用Proscenium框架为您的Flash项目创建3D元素。要了解在Flash Professional中创建3D动画和游戏的更多信息,请查阅以下在线资源:

查看原文:Working with the Proscenium framework

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT