`
madfroghe
  • 浏览: 122098 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Flash/Flex学习笔记(49):背面剔除与 3D 灯光

阅读更多

今天继续:上一回Flash/Flex学习笔记(50):3D线条与填充 里,我们知道任何一个3D多面体上的某一个面,都可以分解为多个三角形的组合。比立方体为例,每个面都由二个三角形组成,但在那一篇的示例中明显有一个问题:不管立方体的某一个面是不是应该被人眼看见(比如转到背面的部分,应该是看不见的),这一面都被绘制出来了。

 

在这一篇的学习中,我将带大家一起学习如何将背面(即看不见的面)删除掉,即所谓的“背面剔除”。

 

先做一些预备知识的铺垫:立方体中每个面都有一个"外面"和"里面"。外面即正对观察者向外的这一面,里面指朝向立方体内部的这一面。我们在3D编程里,通常指的都是“外面”

 

 

如上图:这是立方体的前面,分解为0-1-2和0-2-3二个三角形(注意三个顶点的顺序为"顺时针"方向),当立方体的"前面"旋转到"后面"所处位置时,三角形的顶点顺序由“顺时针”改变为“逆时针”。

 

言外之意:如果我们能判断出某个三角形的顶点顺序为“逆时针”时,这个三角形肯定处于背面,这时应该将它隐藏或不绘制。

 

所以,如果我们在构建立方体每个面的三角形时,都遵守上面的“三角形顶点顺时针法则”,那么上面的解决办法应该就能满足要求了,回顾一下立方体三角形数组的构建代码:

 
 //前 
 triangles[0] = new Triangle(points[0], points[1], points[2], 0x6666cc); 
 triangles[1] = new Triangle(points[0], points[2], points[3], 0x6666cc); 
 //上 
 triangles[2] = new Triangle(points[0], points[5], points[1], 0x66cc66); 
 triangles[3] = new Triangle(points[0], points[4], points[5], 0x66cc66); 
 //后 
 triangles[4] = new Triangle(points[4], points[6], points[5], 0xcc6666); 
 triangles[5] = new Triangle(points[4], points[7], points[6], 0xcc6666); 
//底 
 triangles[6] = new Triangle(points[3], points[2], points[6], 0xcc66cc); 
 triangles[7] = new Triangle(points[3], points[6], points[7], 0xcc66cc); 
//右 
 triangles[8] = new Triangle(points[1], points[5], points[6], 0x66cccc);  
triangles[9] = new Triangle(points[1], points[6], points[2], 0x66cccc); 
//左 
triangles[10] =new Triangle(points[4], points[0], points[3], 0xcccc66); 
triangles[11] =new Triangle(points[4], points[3], points[7], 0xcccc66); 

建议大家去买一个立体魔方玩具,每个点按照上一篇里的顶点数字拿笔标记起来,对比上面的代码发现,这样的代码正好是遵守这一规则的,当然代码不必完全跟这一样,比如:

 
//前 
 triangles[0] = new Triangle(points[0], points[1], points[2], 0x6666cc); 
 triangles[1] = new Triangle(points[0], points[2], points[3], 0x6666cc); 

也可以写成:

triangles[0] = new Triangle(points[1],points[2],points[0],0x6666cc); 
triangles[1] = new Triangle(points[0],points[2],points[3],0x6666cc); 
 

triangles[0] = new Triangle(points[1],points[2],points[3],0x6666cc); 
triangles[1] = new Triangle(points[1],points[3],points[0],0x6666cc); 
 

只要满足顺时针规则即可.ok,已经成功了一半,如何判断三角形处于背面?


//判断是否在背面 
private function isBackFace():Boolean { 
     var cax:Number = pointC.screenX - pointA.screenX; 
     var cay:Number = pointC.screenY - pointA.screenY; 
     var bcx:Number = pointB.screenX - pointC.screenX; 
     var bcy:Number = pointB.screenY - pointC.screenY; 
     return cax * bcy > cay * bcx; 
 }
 

在Triangle.cs中增加这个私有方法即可(我也不知道怎么来的,反正这个函数确实管用,就当公式死记下来好了.)

最后一个小问题:在旋转的过程中,三角形的三个顶点“z轴深度”(zPos值)都在变化,有可能出现某个三角形的顶点挡住了另外一个三角形的顶点。所以我们还得解决三角形的z轴排序问题,这里有一个法则,可以把三个顶点中离观察者最近的一个顶zPos值,认为是三角形的z轴深度,所以Triangle.cs中还得增加一个z轴属性:depth,最终Triangle.cs的内容如下:


 package { 
     import flash.display.Graphics; 
     public class Triangle { 
         private var pointA:Point3D; 
         private var pointB:Point3D; 
         private var pointC:Point3D; 
         private var color:uint; 
         public function Triangle(a:Point3D,b:Point3D,c:Point3D,color:uint) { 
             pointA = a; 
             pointB = b; 
             pointC = c; 
             this.color = color; 
         } 
         public function draw(g:Graphics):void { 
             //如果是背面,则不绘制 
             if (isBackFace()) { 
                 return; 
             } 
   
             g.beginFill(color); 
             g.moveTo(pointA.screenX,pointA.screenY); 
             g.lineTo(pointB.screenX,pointB.screenY); 
             g.lineTo(pointC.screenX,pointC.screenY); 
             g.lineTo(pointA.screenX,pointA.screenY); 
             g.endFill(); 
         } 
   
         //判断是否在背面 
         private function isBackFace():Boolean { 
             // 见 http://www.jurjans.lv/flash/shape.html 
             var cax:Number = pointC.screenX - pointA.screenX; 
             var cay:Number = pointC.screenY - pointA.screenY; 
            var bcx:Number = pointB.screenX - pointC.screenX; 
             var bcy:Number = pointB.screenY - pointC.screenY; 
             return cax * bcy > cay * bcx; 
         } 
   
         //取得三角形所在的z轴深度(以三个顶点中离观察者最近的点为准) 
         public function get depth():Number { 
             var zpos:Number = Math.min(pointA.z,pointB.z); 
             zpos = Math.min(zpos,pointC.z); 
             return zpos; 
         } 
}
 
罗嗦了一堆,激动人心的时刻终于来了,原来的立方体示例代码中,只要增加一行代码:
 
 function EnterFrameHandler(e:Event):void { 
     var dx:Number = mouseX - vpX; 
     var dy:Number = mouseY - vpY; 
     var angleX:Number = dy * 0.001; 
     var angleY:Number = dx * 0.001; 
     var angleZ:Number = Math.sqrt(dx * dx + dy * dy) * 0.0005; 
     if (dx > 0) { 
         angleZ *=  -1; 
     } 
   
   
     for (var i:uint = 0; i < pointNum; i++) { 
         var point:Point3D = points[i]; 
         point.rotateX(angleX); 
         point.rotateY(angleY); 
         point.rotateZ(angleZ); 
     } 
   
     triangles.sortOn("depth", Array.DESCENDING | Array.NUMERIC);//增加三角形数组的z轴排序 
       
     graphics.clear(); 
     for (i = 0; i < triangles.length; i++) { 
         triangles[i].draw(graphics); 
     } 
 }
 

编译运行,最终将得到一个仅2.7k的swf动画,而且还带有鼠标交互的3D立方体,cool 吧!

其它示例修改后,效果如下:

 

3D光线:

这部分内容比较难理解(需要有一定的线性代数基础),先上最终的效果图(光源的位置在左顶点,z轴“-100”处--即flash动画左上顶点距离屏幕垂直向外100的地方,需要一点想象力)

 

理解原理需要线性代数中“向量的矢量积”以及“向量的数量积”、“向量夹角计算”这三个关键概念(不熟悉的童鞋们,请先下载“高等数学-07章空间解释几何与向量代数.pdf”回忆一下数学老师教给我们的东西,有点痛苦!)

如上图,对于每个三角形必须先确定其“法向”向量norm,norm即为向量ab与向量bc的叉积。然后光源light本身也是一个向量,向量light与向量norm会形成一个夹角θ,θ的取值范围在0~PI(即180度)之间,θ为180度时即为正面直射,θ为0度时即为背面照射(实际上小于等于90度时,已经照不到了),直射意味着三角形所在平面颜色应该正常显示(最明亮),背面或照不到时,应该颜色变暗,接近黑色。

关于这个结论,可以先来看下面的演示:(光源的位置我设置为动画中心,距离屏幕向外100px的位置,即正对着屏幕中心照射)

一步一步来,先定义Light向量类:
 package { 

     public class Light { 
         public var x:Number; 
         public var y:Number; 
         public var z:Number; 
         private var _brightness:Number; 
           
         public function Light(x:Number=-200,y:Number=-200,z:Number=-200,brightness:Number=1) { 
             //light向量的空间坐标 
             this.x = x; 
             this.y = y; 
             this.z = z; 
             //亮度 
             this.brightness = brightness; 
         } 
           
         public function set brightness(b:Number):void { </
分享到:
评论

相关推荐

    flex/Flash开发系列书籍:WEB3D应用研究

    flex/Flash开发系列书籍:基于FLASH的WEB3D应用研究

    Flash/Flex 框架应用 Cairngorm、Mate、PureMVC以及Swiz 的典型例子

    附件是关于 Flash/Flex 几个重要框架 Cairngorm、Mate、PureMVC以及Swiz 的典型例子,由 Tony Hillerson 提供 Homepage: http://insideria.com

    flash/flex画曲线,绘图板

    在IT行业中,Flash/Flex是一种基于ActionScript编程语言和Adobe Flex框架的开发工具,用于创建交互式的、富媒体的Web应用程序。"Flash/Flex画曲线,绘图板"这个主题涉及的是如何使用这些技术来创建一个允许用户自由...

    RE/flex lexical analyzer generator:以正则表达式为中心的快速词法分析器生成器,用于C ++-开源

    语言:C ++许可证:BSD-3代码质量:A + https://lgtm.com/projects/g/Genivia/RE-flex/context:cpp文档:https://www.genivia.com/doc/reflex/html /index.html存储库:https://github.com/Genivia/RE-flex更改日志...

    [Flash/Flex] 使用css定义文本样式

    在IT行业中,Flash和Flex是曾经非常流行的富互联网应用程序(RIA)开发框架,它们主要用于创建交互式的网页内容和应用程序。本文将重点讲解如何在Flash或Flex项目中利用CSS(层叠样式表)来定义文本样式,提升用户...

    FDT-flash/flex devtoolkit for eclipse.

    **FDT - 一款强大的Flash/Flex开发工具集** FDT(Flash Development Tool)是一款专为Adobe Flash和Flex开发者设计的集成开发环境(IDE),它基于Eclipse平台,提供了高效、专业的开发工具和服务。FDT的出现极大地...

    flash/flex 的aqua皮肤

    在IT行业中,Flash/Flex是一种广泛使用的开发工具,主要用于创建交互式、富媒体的Web应用程序。Flex是基于ActionScript和MXML的开放源代码框架,它允许开发者构建可自定义的用户界面,而Flash则是其背后的动画和...

    FLEX安装方法 集成到eclipse中

    FLEX 安装方法 集成到 eclipse 中 ...* 汉化 FLEX 尤其是 FLEX/AIR 方面的中文资料 * 原创的关于 FLEX 的博客:http://liguoliang.com/ * Adobe 公司 FLEX 主页:http://www.adobe.com/cn/products/flex/

    [转] [Flash/Flex] 使用Flare3D来实现Flash 3D的推箱子游戏原型---纹理

    这篇教程主要介绍如何使用Flare3D在Flash/Flex环境中创建一个3D推箱子游戏的原型,重点关注3D纹理的应用。Flare3D是一个强大的工具,它为Flash开发者提供了将2D内容转换为3D场景的能力,使得在Flash平台上开发复杂的...

    flex学习笔记 flex学习总结 flex学习教程

    本教程是作者精心编写的Flex学习资料,适合初学者入门,通过图文并茂的方式,帮助读者快速掌握Flex的基本概念和核心技能。 1. **Flex基础**:Flex提供了MXML和ActionScript两种编程方式。MXML是一种声明式语言,...

    Flex:登录

    标题“Flex:登录”指的是使用Adobe Flex技术实现用户登录功能的一种方法。Flex是Adobe公司推出的一款基于ActionScript的开源框架,主要用于...压缩包中的"Flex Login"可能包含示例代码或项目结构,供读者学习和参考。

    RTMP直播例子--基于FLASH/FLEX(含源代码) 下载

    RTMP(Real-Time Messaging Protocol)...通过学习和理解源代码,你可以深入了解RTMP协议的实现细节,以及FLEX如何与服务器和客户端进行交互。这对于想要从事音视频直播开发的人员来说,是一个宝贵的实践和学习资源。

    FLEX学习笔记

    《FLEX学习笔记》 FLEX,全称为Flex Builder,是由Adobe公司开发的一款基于MXML和ActionScript的开源框架,用于构建富互联网应用程序(RIA)。它允许开发者创建具有交互性、响应性和丰富用户体验的Web应用。FLEX的...

    解决flash/flex/as3 访问中文域名时的流错误示例

    在《潮汕IT男》网站的文章《解决flash/flex/as3 访问中文域名时的流错误》中,作者陈林生提供了详细的步骤和代码示例,帮助开发者理解和解决这个问题。文章地址是:[http://chenlinsheng.com/?p=990]...

    Flex学习笔记.rar

    1. **Flex概述**:介绍Flex技术的基本概念,包括它的历史、目标和应用领域,以及它与Flash Player和Adobe AIR的关系。 2. **Flex开发环境**:可能会讲解如何安装和配置Flex Builder或IntelliJ IDEA等开发工具,以及...

    flex开源项目介绍.doc

    Flex开源项目介绍 Flex是一种用于构建富互联网应用程序(RIA)的开源框架,它基于ActionScript 3(AS3)编程语言和MXML标记语言。这些开源项目为开发者提供了丰富的组件库、工具和框架,帮助他们扩展Flex的功能,...

    4个简单的Flex例子(包含custom-class-mapping)共享

    总共有4个例子: 1.http://127.0.0.1:8080/flexDemo/HelloWorld/HelloWorld.html ...如果你的数据库配置和我的不一样,请修改flexDemo\WEB-INF\classes\下的DBSetting.properties文件,数据库建表的sql语句是user.sql

    Flex与Java的交互

    Flex与Java的交互是跨平台应用开发中的常见技术组合,允许前端用户界面(UI)与后端业务逻辑进行高效沟通。在本文中,我们将深入探讨如何使用Flex 4与Java进行通信,并通过三种不同的方法实现这一目标:RemoteObject...

    flex actionscript学习笔记

    Flex ActionScript 学习笔记是关于使用Adobe Flex技术并结合ActionScript 3.0进行开发的知识总结。ActionScript 3.0是随着Flash CS3一起推出的一种强大的编程语言,相较于之前的ActionScript版本,它有着显著的提升...

    Away3D_4.1+Flex4.7学习笔记+案例

    《Away3D_4.1+Flex4.7学习笔记与案例解析》 Away3D是一个强大的开源3D引擎,专为Adobe Flash平台设计,它允许开发者创建丰富的、交互式的三维应用程序。本学习笔记结合Flex4.7框架,将深入探讨如何在Flash平台上...

Global site tag (gtag.js) - Google Analytics