UV 映射

一旦开始处理纹理,就需要使用 drawTriangles() 的 uvtData 参数。此参数用于为位图填充设置 UV 映射。

UV 映射是一种纹理化对象的方法。它依赖于两个值:U 水平 (x) 值和 V 垂直 (y) 值。这两个值不是基于像素值,而是基于百分比。0 U 和 0 V 表示图像的坐上角,1 U 和 1 V 表示右下角:

位图图像上的 UV 0 和 1 位置

可以为三角形的矢量指定 UV 坐标,从而将矢量自身关联到图像上的相应位置:

位图图像的三角形区域的 UV 坐标

UV 值与三角形的点保持一致:

三角形的顶点移动且位图发生扭曲,从而使单个点的 UV 值保持不变

由于 ActionScript 3D 转换应用于与位图关联的三角形,位图图像将根据 UV 值应用于三角形。因此,不要使用矩阵运算,而应通过设置或调整 UV 值来实现三维效果。

Graphics.drawTriangles() 方法也接受关于三维转换的一条可选信息:T 值。uvtData 中的 T 值表示 3D 透视,更具体地说,表示相关顶点的缩放系数。UVT 映射向 UV 映射加入了透视修正处理。例如,如果将对象放置在 3D 空间中远离视点的位置,使之显示为原始大小的 50%,则该对象的 T 值为 0.5。因为在 3D 空间中是通过绘制三角形来表示对象的,所以对象在 z 轴上的位置确定对象的 T 值。用于确定 T 值的等式为:

T = focalLength/(focalLength + z);
在该等式中,focalLength 表示焦距或计算得出的“屏幕”位置,它决定了视图中提供的透视大小。
焦距与 z 值

A.
视点

B.
屏幕

C.
3D 对象

D.
focalLength 值

E.
z 值

T 值用于缩放基本形状,使这些形状看起来更远。该值通常用于将 3D 点转换为 2D 点。而对于 UVT 数据,它也用于在透视三角形内的点之间缩放位图。

在定义 UVT 值时,T 值紧跟在为顶点定义的 UV 值后面。加入 T 之后,uvtData 参数(U、V 和 T)中的每三个值与 vertices 参数(x 和 y)中的每两个值相匹配。在只有 UV 值的情况下,uvtData.length == vertices.length。在加入 T 值的情况下,uvtData.length = 1.5*vertices.length。

下面的示例演示使用 UVT 数据在 3D 空间中旋转平面。本例使用了一幅名为 ocean.jpg 的图像和一个“帮助器”类 ImageLoader,该类用于加载 ocean.jpg 图像以便将其分配给 BitmapData 对象。

下面是 ImageLoader 类的源代码(请将此代码保存到命名为 ImageLoader.as 的文件中):

package { 
    import flash.display.* 
    import flash.events.*; 
    import flash.net.URLRequest; 
    public class ImageLoader extends Sprite { 
        public var url:String; 
        public var bitmap:Bitmap; 
    public function ImageLoader(loc:String = null) { 
        if (loc != null){ 
            url = loc; 
            loadImage(); 
        } 
    } 
    public function loadImage():void{ 
        if (url != null){ 
            var loader:Loader = new Loader(); 
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete); 
            loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIoError); 
             
                var req:URLRequest = new URLRequest(url); 
                loader.load(req); 
            } 
        } 
         
    private function onComplete(event:Event):void { 
            var loader:Loader = Loader(event.target.loader); 
            var info:LoaderInfo = LoaderInfo(loader.contentLoaderInfo); 
            this.bitmap = info.content as Bitmap; 
            this.dispatchEvent(new Event(Event.COMPLETE)); 
    } 
         
    private function onIoError(event:IOErrorEvent):void { 
            trace("onIoError: " + event); 
    } 
    } 
}

下面的 ActionScript 用三角形、UV 映射和 T 值使图像获得这样的显示效果:图像朝着消失点逐渐收缩并不断旋转。将此代码保存到命名为 Spinning3dOcean.as 的文件中:

package { 
    import flash.display.* 
    import flash.events.*; 
    import flash.utils.getTimer; 
     
    public class Spinning3dOcean extends Sprite { 
        // plane vertex coordinates (and t values) 
        var x1:Number = -100,    y1:Number = -100,    z1:Number = 0,    t1:Number = 0; 
        var x2:Number = 100,    y2:Number = -100,    z2:Number = 0,    t2:Number = 0; 
        var x3:Number = 100,    y3:Number = 100,    z3:Number = 0,    t3:Number = 0; 
        var x4:Number = -100,    y4:Number = 100,    z4:Number = 0,    t4:Number = 0; 
        var focalLength:Number = 200;      
        // 2 triangles for 1 plane, indices will always be the same 
        var indices:Vector.<int>; 
         
        var container:Sprite; 
         
        var bitmapData:BitmapData; // texture 
        var imageLoader:ImageLoader; 
        public function Spinning3dOcean():void { 
            indices =  new Vector.<int>(); 
            indices.push(0,1,3, 1,2,3); 
             
            container = new Sprite(); // container to draw triangles in 
            container.x = 200; 
            container.y = 200; 
            addChild(container); 
             
            imageLoader = new ImageLoader("ocean.jpg"); 
            imageLoader.addEventListener(Event.COMPLETE, onImageLoaded); 
        } 
        function onImageLoaded(event:Event):void { 
            bitmapData = imageLoader.bitmap.bitmapData; 
            // animate every frame 
            addEventListener(Event.ENTER_FRAME, rotatePlane); 
        } 
        function rotatePlane(event:Event):void { 
            // rotate vertices over time 
            var ticker = getTimer()/400; 
            z2 = z3 = -(z1 = z4 = 100*Math.sin(ticker)); 
            x2 = x3 = -(x1 = x4 = 100*Math.cos(ticker)); 
             
            // calculate t values 
            t1 = focalLength/(focalLength + z1); 
            t2 = focalLength/(focalLength + z2); 
            t3 = focalLength/(focalLength + z3); 
            t4 = focalLength/(focalLength + z4); 
             
            // determine triangle vertices based on t values 
            var vertices:Vector.<Number> = new Vector.<Number>(); 
            vertices.push(x1*t1,y1*t1, x2*t2,y2*t2, x3*t3,y3*t3, x4*t4,y4*t4); 
            // set T values allowing perspective to change 
            // as each vertex moves around in z space 
            var uvtData:Vector.<Number> = new Vector.<Number>(); 
            uvtData.push(0,0,t1, 1,0,t2, 1,1,t3, 0,1,t4); 
             
            // draw 
            container.graphics.clear(); 
            container.graphics.beginBitmapFill(bitmapData); 
            container.graphics.drawTriangles(vertices, indices, uvtData); 
        } 
    } 
}

若要测试此示例,请在名为“ocean.jpg”的图像所在的目录中保存这两个类文件。您可以看到原始位图如何转换为在 3D 空间中消失于远处并不断旋转的效果。