3D 효과에 삼각형 사용

Flash Player 10 이상, Adobe AIR 1.5 이상

ActionScript에서는 Graphics.drawTriangles() 메서드를 사용하여 비트맵 변형을 수행합니다. 공간에서 3D 모델은 삼각형의 모음으로 나타나기 때문입니다. 그러나 Flash Player와 AIR에서는 깊이 버퍼를 지원하지 않으므로 표시 객체는 여전히 본질적으로는 평면, 즉 2D입니다. 자세한 내용은 Flash Player 및 AIR 런타임에서 사용되는 3D 표시 객체 이해 를 참조하십시오. Graphics.drawTriangles() 메서드는 Graphics.drawPath() 메서드와 같이 일련의 좌표를 인수로 받아 삼각형 패스를 그립니다.

Graphics.drawPath() 의 사용 방법을 이해하려면 패스 그리기 를 참조하십시오.

Graphics.drawTriangles() 메서드는 Vector.<Number>를 사용하여 삼각형 패스의 점 위치를 지정합니다.

drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void

drawTriangles() 의 첫 번째 매개 변수는 유일한 필수 매개 변수인 vertices 매개 변수입니다. 이 매개 변수는 삼각형을 그릴 좌표를 정의하는 숫자의 벡터입니다. 세 개의 좌표 집합(여섯 개의 숫자) 모두가 하나의 삼각형 패스를 나타냅니다. 각 삼각형에는 세 개의 좌표 쌍(두 개의 x/y 값으로 구성된 집합 세 개)이 필요하므로 indices 매개 변수를 사용하지 않을 경우 벡터의 길이는 항상 6의 인수가 됩니다. 예를 들면 다음과 같습니다.

graphics.beginFill(0xFF8000); 
graphics.drawTriangles( 
    Vector.<Number>([ 
        10,10,  100,10,  10,100, 
        110,10, 110,100, 20,100]));

이러한 삼각형은 모두 어떤 점도 공유하지 않지만 삼각형의 점이 공유될 경우에는 drawTriangles() 의 두 번째 매개 변수인 indices 를 사용하여 두 개 이상의 삼각형에 vertices 벡터의 값을 다시 사용할 수 있습니다.

indices 매개 변수를 사용할 경우 indices 값은 vertices 배열 요소와 직접적으로 관련된 인덱스가 아니라 점 인덱스여야 합니다. 즉, indices 로 정의된 vertices 벡터의 인덱스는 사실상 실제 인덱스를 2로 나눈 것입니다. 예를 들어 vertices 벡터의 세 번째 점의 경우 해당 점의 첫 번째 숫자 값은 벡터 인덱스 4에서 시작하지만 indices 값으로는 2를 사용합니다.

예를 들어 다음과 같이 indices 매개 변수를 사용하여 두 개의 삼각형이 대각선 가장자리를 공유하도록 병합할 수 있습니다.

graphics.beginFill(0xFF8000); 
graphics.drawTriangles( 
    Vector.<Number>([10,10, 100,10, 10,100, 100,100]), 
    Vector.<int>([0,1,2, 1,3,2]));

지금은 두 개의 삼각형을 사용하여 사각형이 그려지지는 않았지만 vertices 벡터에 네 개의 점만 지정되었습니다. indices 를 사용하면 두 삼각형이 공유하는 두 개의 점은 각 삼각형에 대해 다시 사용됩니다. 이렇게 하면 전체 정점 수가 6개(12개의 숫자)에서 4개(8개의 숫자)로 줄어듭니다.

vertices 매개 변수를 사용하여 두 개의 삼각형으로 그려진 사각형

이 기술은 대부분의 점이 여러 삼각형에서 공유되는 큰 삼각형 메쉬에서 유용합니다.

삼각형에는 모든 채우기를 적용할 수 있습니다. 채우기는 다른 모양에서와 마찬가지로 결과 삼각형 메쉬에 적용됩니다.

비트맵 변형

비트맵 변형을 사용하면 3차원 객체에 원근 또는 "텍스처" 효과를 줄 수 있습니다. 특히 비트맵을 소실점 쪽으로 왜곡시켜 이미지가 소실점 쪽으로 이동할수록 작게 나타나도록 할 수 있습니다. 또는 2차원 비트맵을 사용하여 3차원 객체의 표면을 만들고 이를 통해 3차원 객체에 텍스처 또는 "둘러싸기" 효과를 줄 수 있습니다.

소실점을 사용한 2차원 표면과 비트맵으로 둘러싼 3차원 객체

UV 매핑

텍스처 작업을 시작한 후에는 drawTriangles() 의 uvtData 매개 변수를 사용할 수 있습니다. 이 매개 변수를 사용하면 비트맵 채우기를 위한 UV 매핑을 설정할 수 있습니다.

UV 매핑은 객체에 텍스처를 적용하기 위한 방법으로, U 가로(x) 값과 V 세로(y) 값을 사용합니다. 이 두 값은 픽셀 값이 아니라 백분율을 기준으로 합니다. 0U 및 0V는 이미지의 왼쪽 위 모서리이고 1U 및 1V는 오른쪽 아래 모서리입니다.

비트맵 이미지상의 UV 0 및 1 위치

삼각형의 벡터에 UV 좌표를 지정하면 벡터를 이미지 상의 각 위치와 연결할 수 있습니다.

비트맵 이미지에 있는 삼각형 영역의 UV 좌표

UV 값은 삼각형의 점과 일관되게 유지됩니다.

삼각형의 정점이 이동하면서 개별 점의 UV 값이 동일하도록 비트맵이 왜곡된 모양

비트맵과 연결된 삼각형에 ActionScript 3D 변형이 적용될 때 비트맵 이미지는 UV 값을 기준으로 삼각형에 적용됩니다. 따라서 행렬 계산을 사용하는 대신 UV 값을 설정하거나 조정하여 3차원 효과를 만듭니다.

Graphics.drawTriangles() 메서드는 3차원 변형을 위해 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라는 이미지를 BitmapData 객체에 할당할 수 있도록 ocean.jpg 이미지와 "도우미" 클래스인 ImageLoader를 사용하여 해당 이미지를 로드합니다.

다음은 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); 
    } 
    } 
}

다음은 삼각형, UV 매핑 및 T 값을 사용하여 이미지가 소실점 쪽으로 점점 작아지고 회전하는 것처럼 보이도록 만드는 ActionScript입니다. 이 코드를 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 공간에서 먼 곳으로 소실되고 회전하는 것처럼 보이도록 변형되는 방식을 볼 수 있습니다.

컬링

컬링은 3차원 객체의 표면 중 현재 시점에서 숨겨지기 때문에 렌더러에서 렌더링하지 않아야 하는 표면을 결정하는 프로세스입니다. 3D 공간에서 3차원 객체의 "뒤쪽"에 있는 표면은 시점에서 숨겨집니다.
3D 객체의 뒤쪽은 시점에서 숨겨집니다.
A.
시점

B.
3D 객체

C.
3차원 객체의 뒤쪽

본질적으로 모든 삼각형은 크기, 모양 또는 위치에 관계없이 항상 렌더링됩니다. 컬링은 Flash Player나 AIR에서 3D 객체를 올바르게 렌더링하도록 합니다. 또한 렌더링 주기를 줄이기 위해 필요한 경우 렌더러에서 일부 삼각형을 건너뛰도록 할 수 있습니다. 예를 들어 공간에서 회전하는 정육면체를 가정해 봅니다. 보기에 나타나지 않는 면은 정육면체 반대쪽의 다른 방향을 향하고 있는 것이므로 한 번에 볼 수 있는 정육면체의 면은 최대 세 개입니다. 이러한 면은 표시되지 않으므로 렌더러에서 해당 면을 그리지 말아야 합니다. 컬링을 사용하지 않을 경우 Flash Player나 AIR에서는 앞쪽 면과 뒤쪽 면을 모두 렌더링합니다.

현재 시점에서 보이지 않는 면이 있는 정육면체

따라서 Graphics.drawTriangles() 메서드는 네 번째 변수를 사용하여 컬링 값을 설정합니다.

public function drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void

컬링 매개 변수는 TriangleCulling 열거형 클래스의 값인 TriangleCulling.NONE , TriangleCulling.POSITIVE TriangleCulling.NEGATIVE 중 하나입니다. 이러한 값은 객체의 표면을 정의하는 삼각형 패스의 방향에 따라 달라집니다. 컬링을 결정하기 위한 ActionScript API에서는 3D 모양에서 바깥쪽을 향하는 모든 삼각형이 동일한 패스 방향으로 그려져 있다고 가정합니다. 삼각형 면을 돌리면 패스 방향도 변경됩니다. 해당 지점에서 삼각형을 컬링(렌더링에서 제거)할 수 있습니다.

따라서 TriangleCulling 값이 POSITIVE 이면 패스가 양수 방향(시계 방향)인 삼각형이 제거되고, TriangleCulling 값이 NEGATIVE 이면 패스가 음수 방향(반시계 방향)인 삼각형이 제거됩니다. 정육면체의 경우 앞쪽을 향하는 표면의 패스는 양수 방향이고 뒤쪽을 향하는 표면의 패스는 음수 방향입니다.

패스 방향을 보여 주기 위해 "펼친" 정육면체. "접힌" 상태에서는 뒤쪽 면의 패스 방향이 반대가 됩니다.

컬링의 작동 방식을 보려면 앞에 나온 UV 매핑 의 예제에서 drawTriangles() 메서드의 컬링 매개 변수를 TriangleCulling.NEGATIVE 로 설정합니다.

container.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NEGATIVE);

객체가 회전할 때 이미지의 "뒤쪽" 면은 렌더링되지 않습니다.