当前位置: 首页 > 图文教程 > Flash动画 > Flash动画制作 > Flash制作3D类动画的教程

Flash动画制作
赤手空拳下载Flash
创建一个Flash站点的十大技巧
用Flash制作Google搜索程序
枫桥夜泊下 遮罩效果的动态文本
Flash MX 2004 ActionScript图文教程(十二)
Flash实例教程 扫描文字效果
Flash MX 2004 ActionScript图文教程(十三)
快速制作您的flash图表
Flash MX 2004 ActionScript图文教程(十四)
Flash实例教程 变幻的字母
Flash MX 2004 ActionScript图文教程(十五)
Flash实例教程 相约北京 扬帆青岛
Flash教程实例 光线特效文字
Flash课件实例 画正多边形
Flash课件实例 平行四边形法则
Flash实例教程 小孔成像课件
精简Flash文件体积七法
Flash教程实例:水中浮动的文字
金鸡贺岁!Flash制作鸡年新春动画贺卡
Flash MX 2004新特性实例学习一

Flash动画制作 中的 Flash制作3D类动画的教程


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2010-01-04   浏览: 217 ::
收藏到网摘: n/a

最近对Flash3D效果产生了兴趣,下决心学习一下Sandy。一下将学习的体会的感受写下来,一来帮助大家熟悉Sandy,二来加强自己的记忆。

先从基础开始吧(基础解释转自Flash3D研究所)

原理解释:

  • 窗口:
    用户观看的窗口,简单的可以想成就是flash里面的画布大小。窗口也可以理解成渲染的尺寸,否则画面就无限大了
  • 场景:
    场景是指整个三维的场景。
  • 摄像机:
    很多人要问,为什么有了摄像机还要窗口呢?摄像机是用来拍画面的,看画面还是得电视机/窗口不是吗,^_^
    渲染器:如果没有这个东西,所有以上的东西都只是数据,渲染器就是把所有数据变成图像的东西。

下面这幅图虽然并不算准确的表述,但希望能帮助我们理解:

然后开始写代码了(目前感觉Sandy的代码还是比较简洁的):

要先将Sandy的类库下载下来哦!!(在这里要谢谢 tenzn 的提醒,呵呵。)
官方网站:http://www.flashsandy.org
下载地址:http://sandy.googlecode.com/files/Sandy3-1-1_src_rev1008.zip

先尝试创建一个立方体。

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import sandy.core.Scene3D;
    import sandy.core.scenegraph.*;
    import sandy.primitive.*;
   
    /**
     * ...
     * @author ever5u
     */
    public class fuxi extends Sprite
    {
        private var scene:Scene3D;
        private var camera:Camera3D;
        public function fuxi() {
            //创建一个摄像机
            camera = new Camera3D(300, 300);
            camera.z = -300;
            //创建一个 Group
            var root:Group = createScene();
            //创建场景
            scene = new Scene3D( "scene", this, camera, root );
            //创建实时侦听
            addEventListener( Event.ENTER_FRAME, enterFrameHandler );
        }
        var box = new Box("box", 100, 100, 100);
        public function createScene() {
            var g:Group = new Group();
            g.addChild( box );
            return g;
        }
        public function enterFrameHandler(_evt:Event) {
            box.rotateX = mouseX;
            box.rotateY = mouseY;
            scene.render();
        }
    }
   
}

成功了,效果如下:

接下来尝试给这个立方体着色。

这里需要用到 sandy.materials.attributes 类。

其中为线着色的方法 LineAttributes 有三个属性:
LineAttributes(p_nThickness:uint = 1,  p_nColor:uint = 0,  p_nAlpha:Number = 1)

  • p_nThickness:uint (default = 1) — 线的粗细
  • p_nColor:uint (default = 0) — 线的颜色
  • p_nAlpha:Number (default = 1) —  线的透明度

这里设置是否使用光,需要先设置 lightingEnable = true 。
LightAttributes(p_bBright:Boolean = false, p_nAmbient:Number = 0.3)

  • p_bBright:Boolean (default = false) — 设置是否支持光
  • p_nAmbient:Number (default = 0.3) — 设置光的亮度(数值范围是 0 - 1)

为立方体渲染用
ColorMaterial(p_nColor:uint = 0x00, p_nAlpha:Number = 1, p_oAttr:MaterialAttributes = null)

  • p_nColor:uint (default = 0x00) — 颜色
  • p_nAlpha:Number (default = 1) — 透明度
  • p_oAttr:MaterialAttributes (default = null) — 线设置

代码如下:

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import sandy.core.Scene3D;
    import sandy.core.scenegraph.*;
    import sandy.primitive.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;
   
    /**
     * ...
     * @author ever5u
     */
    public class fuxi extends Sprite
    {
        private var scene:Scene3D;
        private var camera:Camera3D;
        public function fuxi() {
            //创建一个摄像机
            camera = new Camera3D(300, 300);
            camera.z = -300;
            //创建一个 Group
            var root:Group = createScene();
            //创建场景
            scene = new Scene3D( "scene", this, camera, root );
            //创建实时侦听
            addEventListener( Event.ENTER_FRAME, enterFrameHandler );
        }
        var box = new Box("box", 100, 100, 100);
        public function createScene() {
            var g:Group = new Group();
            //设置立方体的颜色、线条色和环境光
            material.lightingEnable = true;
            var materialAttr:MaterialAttributes = new MaterialAttributes(
               new LineAttributes( 0.5, 0x000000, 0.4 ),
               new LightAttributes( true, 0.2)
            );
            var material:Material = new ColorMaterial( 0xCC3300, 1, materialAttr );
            var app:Appearance = new Appearance( material );
           
            box.appearance = app;
           
            g.addChild( box );
            return g;
        }
        public function enterFrameHandler(_evt:Event) {
            box.rotateX = mouseX;
            box.rotateY = mouseY;
            scene.render();
        }
    }
   
}

这是效果:

继续试试看用图片为立方体贴图。

首先导入一张位图到库里,并声明类名为 MyPalm

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import sandy.core.Scene3D;
    import sandy.core.scenegraph.*;
    import sandy.primitive.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;
   
    /**
     * ...
     * @author ever5u
     */
    public class fuxi extends Sprite
    {
        private var scene:Scene3D;
        private var camera:Camera3D;
        public function fuxi() {
            //创建一个摄像机
            camera = new Camera3D(300, 300);
            camera.z = -300;
            //创建一个 Group
            var root:Group = createScene();
            //创建场景
            scene = new Scene3D( "scene", this, camera, root );
            //创建实时侦听
            addEventListener( Event.ENTER_FRAME, enterFrameHandler );
        }
        var box = new Box("box", 100, 100, 100);
        public function createScene() {
            var g:Group = new Group();
            //设置立方体的贴图
            var bitmap:BitmapData = new MyPalm(0, 0);
            var material:Material = new BitmapMaterial( bitmap );
            var app:Appearance = new Appearance( material );
           
            box.appearance = app;
           
            g.addChild( box );
            return g;
        }
        public function enterFrameHandler(_evt:Event) {
            box.rotateX = mouseX;
            box.rotateY = mouseY;
            scene.render();
        }
    }
   
}

效果:

继续上次的学习,接下来要试试摄像机的移动了。
这里需要涉及几个概念,摄像机的坐标(x, y, z)和视觉角度(LookAt)
摄像机的位置可以使用(x, y, z)来定位;
视觉角度可以定义如何通过窗口来看场景。
lookAt(p_nX:Number, p_nY:Number, p_nZ:Number)
如:lookAt(0,0,0);//可以理解为通过摄像机的位置看场景。

摄像机的移动方式比较有意思,如果直接修改x、y、z坐标,视觉效果会与现实看到的情况相同;
而tilt、pan则是与场景平行移动;
roll是以z轴移动,通过摄像机视野看上去是摄像机的旋转效果。

额外说一下 Line3D 是在场景中绘制了线段,这里用做参考线,代码不难理解我就不过多解释了。

代码如下:

package
{
    import flash.display.Sprite;
    import flash.events.*;
    import flash.ui.*;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import sandy.core.Scene3D;
    import sandy.core.scenegraph.*;
    import sandy.primitive.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;
    import sandy.core.data.*;
    
    /**
     * ...
     * @author ever5u
     */
    public class fuxi extends Sprite
    {
        private var scene:Scene3D;
        private var camera:Camera3D;
        public function fuxi() {
            //创建一个摄像机
            camera = new Camera3D(300, 300);
            camera.x = 100;
            camera.y = 100;
            camera.z = -300;
            camera.lookAt(0,0,0);
            //创建一个 Group
            var root:Group = createScene();
            //创建场景
            scene = new Scene3D( "scene", this, camera, root );
            //创建实时侦听
            addEventListener( Event.ENTER_FRAME, enterFrameHandler );
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
        }
        var box = new Box("box", 100, 100, 100);
        var Plane:Plane3D;
        public function createScene() {
            var g:Group = new Group();
            
            //在场景画一个坐标定位点
            Plane = new Plane3D("Texture", 300, 300);
            var myXLine:Line3D = new Line3D( "x-coord", new Point3D( -20, 0, 0), new Point3D( 20, 0, 0 ));
            var myYLine:Line3D = new Line3D( "y-coord", new Point3D(0, -20, 0), new Point3D( 0, 20, 0 ));
            var myZLine:Line3D = new Line3D( "z-coord", new Point3D(0, 0, -20), new Point3D( 0, 0, 20 ));
            
            g.addChild(myXLine);
            g.addChild(myYLine);
            g.addChild(myZLine);
            g.addChild( box );
            return g;
        }
        public function enterFrameHandler(_evt:Event) {
            box.rotateX = mouseX;
            box.rotateY = mouseY;
            scene.render();
        }
        public function keyPressed(_evt:KeyboardEvent):void {
            switch(_evt.keyCode) {
                case Keyboard.UP:
                    camera.tilt += 2;
                    //camera.y -= 2;
                    break;
                case Keyboard.DOWN:    
                    camera.tilt -= 2;
                    //camera.y += 2;
                    break;
                case Keyboard.RIGHT:
                    camera.pan -= 2;
                    //camera.x += 2;
                    break;
                case Keyboard.LEFT:
                    camera.pan += 2;
                    //camera.x -= 2;
                    break;
                case Keyboard.CONTROL:
                    camera.roll += 2;
                    break;    
                case Keyboard.PAGE_DOWN:
                    camera.z -= 5;
                    break;
                case Keyboard.PAGE_UP:
                    camera.z += 5;
                    break;    
            }
        }
    }
    
}

效果:

还有场景自适应的问题,需要说明一下。

摄像机的镜头可视角度使用 fov(vertical field of view angle)来定义。

换算公式:

var fl:Numer = (viewport.height / 2) / Math.tan (camera.fov / 2 * (Math.PI / 180));

代码:

package
{
    import flash.display.Sprite;
    import flash.events.*;
    import flash.ui.*;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.display.Stage;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import sandy.core.Scene3D;
    import sandy.core.scenegraph.*;
    import sandy.primitive.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;
    import sandy.core.data.*;
   
    /**
     * ...
     * @author ever5u
     */
    public class fuxi extends Sprite
    {
        private var scene:Scene3D;
        private var camera:Camera3D;
        public function fuxi() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            //创建一个摄像机
            camera = new Camera3D(300, 300);
            camera.x = 100;
            camera.y = 100;
            camera.z = -300;
            camera.lookAt(0,0,0);
            //创建一个 Group
            var root:Group = createScene();
            //创建场景
            scene = new Scene3D( "scene", this, camera, root );
            //创建实时侦听
            addEventListener( Event.ENTER_FRAME, enterFrameHandler );
            stage.addEventListener (Event.RESIZE, onResize);
        }
        var box = new Box("box", 100, 100, 100);
        var Plane:Plane3D;
        public function createScene() {
            var g:Group = new Group();
           
            //在场景画一个坐标定位点
            Plane = new Plane3D("Texture", 300, 300);
            var myXLine:Line3D = new Line3D( "x-coord", new Point3D( -20, 0, 0), new Point3D( 20, 0, 0 ));
            var myYLine:Line3D = new Line3D( "y-coord", new Point3D(0, -20, 0), new Point3D( 0, 20, 0 ));
            var myZLine:Line3D = new Line3D( "z-coord", new Point3D(0, 0, -20), new Point3D( 0, 0, 20 ));
           
            g.addChild(myXLine);
            g.addChild(myYLine);
            g.addChild(myZLine);
            g.addChild( box );
            return g;
        }
        public function enterFrameHandler(_evt:Event) {
            box.rotateX = mouseX;
            box.rotateY = mouseY;
            scene.render();
        }
        function onResize (e:Event):void{
            // 获取场景宽高
            var w:Number = stage.stageWidth;
            var h:Number = stage.stageHeight;
            // 设置视野宽高
            scene.camera.viewport.width = w;
            scene.camera.viewport.height = h;
            // 获取物体box与摄像机间的距离
            var d:Number = box.getPosition ("camera").getNorm ();
            // 保持摄像机观看比例
            scene.camera.fov = 2 * Math.atan2 (h / 2, d) * (180 / Math.PI);
            // 执行渲染
            scene.render();
        }
    }
   
}

效果: