박스 그리기 
 

        주사위를 그리기 위한 기초 작업으로 3차원 풀그림의 기본을 보기를 들어 가며 이야기를 전개하기로 한다.  먼저 보통 박스로 불리는 직6면체(cuboid)를 그려 본다.  직6면체는 8개의 꼭지점과 6개의 면이 있다.  직6면체의 바닥을 1로 잡았을 때 높이와 깊이를 각각 rh(height), rd(depth)로 표시한다.   그러면 직6면체의 한 가운데에 원점을 둔 자리표계에서 8개의 꼭지점의 자리표는  [rh,1, -rd], [rh, -1, -rd], [-rh, -1, -rd], [-rh, 1, -rd], [rh, 1, rd], [rh, -1, rd], [-rh, -1, rd], [-rh, 1, rd] 가 된다. 이것을 aCuboid 라는 배열로 만들면 aCuboid[0] = [rh,1, -rd], aCuboid[1] = [rh, -1, -d],....aCuboid[7] = [-rh, 1, rd]가 된다. 아래의 코드리스팅<표6>은 박스를 하나 만들어 그리는 CreateCuboidWire라는 클래스이다. 



1

class CreateCuboidWire{

2

        var mc:MovieClip;

3

        var size:Number;

4

        var colA:Array;

5

        var rh:Number;

6

        var rd:Number;

7

        var rotMat:Rotation3D;

8

        private var aCuboid:Array;

9

        private var aCuboidRot:Array;

10

        private var cornsIndex:Array = new Array([0, 1, 2, 3], [0, 4, 5, 1], [1, 5, 6, 2], [0, 3, 7, 4], [2, 6, 7, 3], [4, 7, 6, 5]);

11

        private var surface:Array  = new Array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]);

12

 

13

        // constructor  속성 변수를 초기화한다.

14

function CreateCuboidWire(cuboidMc:MovieClip, cuboidSize:Number, rh1:Number, rd1:Number , colorArray:Array) {

15

                mc = cuboidMc;

16

                size = cuboidSize;

17

                colA = colorArray;

18

                rh =rh1;

19

                rd = rd1;

20

                aCuboid = new Array([rh,1, -rd], [rh, -1, -rd], [-rh, -1, -rd], [-rh, 1, -rd], [rh, 1, rd], [rh, -1, rd], [-rh, -1, rd], [-rh, 1, rd]);

21

aCuboidRot =  new Array([rh,1, -rd], [rh, -1, -rd], [-rh, -1, -rd], [-rh, 1, -rd], [rh, 1, rd], [rh, -1, rd], [-rh, -1, rd], [-rh, 1, rd]);

22

                rotMat = new Rotation3D();

23

                for (var i = 0; i<8; i++) {

24

                        for (var j = 0; j<3; j++) {

25

                                aCuboid[i][j] = aCuboid[i][j]*cuboidSize/2;

26

                        }

27

                }

28

        }

29

        // function CreateCuboid

30

        function showCuboid(alp:Number , IsIso:Boolean) {

31

                for (var i = 0; i<8; i++) {

32

                        aCuboidRot[i] = rotMat.transform3D(aCuboid[i]);

33

                        if (IsIso) {

34

                                aCuboidRot[i] = Isom.mTSA(aCuboidRot[i]);

35

                        }

36

                                        }

37

                for (var i = 0; i<6; i++) {

38

                        for (var j = 0; j<4; j++) {

39

                                for (var k = 0; k<3; k++) {

40

               surface[i][j][k] = aCuboidRot[cornsIndex[i][j]][k];

41

                                }

42

                        }

43

                }

44

                mc.clear();

45

                var x01, x21, y01, y21, zz:Number;

46

                for (var i = 0; i<6; i++) {

47

                                mc.lineStyle(0, colA[i], alp);

48

                                mc.beginFill(colA[i], alp);

49

                        mc.moveTo(surface[i][0][0], surface[i][0][1]);

50

                                for (var j = 1; j<4; j++) {

51

                        mc.lineTo(surface[i][j][0], surface[i][j][1]);

52

                                }

53

                        mc.lineTo(surface[i][0][0], surface[i][0][1]);

54

                        mc.endFill();

55

                                }

56

                //for (var i = 0; i< 6; i++) draw surface

57

        }

58

        // functoin showCuboid()

59

}

60

// class CreateCuboid

표1 class CreateCuboid



          이 코드를 여기에 나열한 것은 이 코드가 3차원 강체를 생성하는 가장 간단한 형태로서 그 뼈대역할을 하기 때문이다. 이 코드를 이해하여야 보다 복잡한 주사위와 같은 강체를 그릴 수 있게 된다.  직6면체를 그리려면 이 8개의 꼭지점의 데이타만 알면 된다. 이 데이터에서 모서리를 그을 수 있고 모서리 4개가 한 면을 결정한다.  따라서 이 꼭지점의 배열이 직 6면체 클래스의 뼈대가 된다.  위 <표1> 에서 cornsIndex 는 6개의 면을 정의하는 배열이다.  첫째면(cornsIndex[0])은 꼭지점의 데이터에서 꼭지점, [0,1,2,3] 으로 구성된다는 의미이다. 여기서 이 꼭지점을 기술하는 순서가 매우 중요하다. 즉 이 순서는 면의 앞뒷면을 가리는 데에 쓰인다.  [0,1,2,3]->[1,2,3,0]로 돌렸을 때 나사의 진행방향이 면의 바깥쪽을 향하게 정한다.  나는 이러한 경우 모형을 만들어 작업한다.  직 6면체의 경우 다행히 꼭지가 뭉툭한 주사위가 있어서 거기에 번호를 매기고 이 인덱스를 코딩했다.



그림1) 정20면체의 인덱스 배열을 코딩하기 위해 필자가 만든 정20면체모형


       

          앞마디 (주사위4 강체와 아이소메트릭 투영법)에 삽입된 <그림1>, <그림2>, <그림3>에 보면 꼭지점에 번호가 적혀 있는 것을 볼 것이다. 그것을 참조하여 면의 인덱스를 적어 넣었다.  정20면체와 같은 것은 <그림 1>과 같은 모형을 만들어 인덱스를 코딩하였다.  12개의 꼭지점에서 3개씩 선택하여 20개의 3각형을 만들어 정20면체를 구성한다.  이 모형의 꼭지점에 번호를 적은 수틱커를 부착하여 인덱스 배열을 코딩하였다. 
  


          수학적으로는 다면체의 꼭지점으로부터 면을 구성하는 꼭지점을 구하는 공식이 있을지 모른다. 그러나 일반적인
다면체를 그리는 무른모를 만드는 경우가 아니라면 그런 거창한 수학적 지식을 동원하기 보다는 이런 모형을 만들어 보는 것도 재미가 있다. 이제는 사라졌지만 옛날 초등학교 시절, 수수깡으로 공작하던 추억을 되 삭이면서.  


           30줄의 메쏘드함수 showCuboid는 직6면체를 그리라는 명령인데 여기서 보듯, 8개의 꼭지점만 회전 행렬로 회전
시키고 그 회전된 꼭지점의 데이터를 써서 면을 그린다.  회전을 두 번 거치는데 교육적 목적으로 분리했을 뿐 아이소메트릭 투영변환을 일반 회전행렬 속에 포함 시킬 수도 있다. 


           40줄의 surface 는 직4각형이므로 4개의 3차원 점으로 구성된다. 다시 말하면  첫 번째 면, surface[0]는  surface[0][0], surface[0][1], surface[0][2], surface[0][3]이라는 4개의 꼭지점으로 구성되는데 각 꼭지점은 3차원 공간의 1점을 나타내는 3요소(x,y,z) 배열이다.  이 점들을 위에 얘기한 cornsIndex를 통해서 구한다. 이렇게 해서 6개면을 다 그리면 우리가 원하는 정6면체가 그려진다.   사실 주사위도 그 원리는 마찬가지이므로 이 직6면체를 플래시로 그릴 수 있으면 어떤 다른 다면체도 그릴 수 있다.  다만 이 직6면체는 반투명 유리상자로 상자의 안쪽면도 보인다.  앞으로 이 문제도 풀어 나갈 것이다.  
 


직교 변환 행렬


          주사위와 같은 3차원 입체의 회전을 다루기 위해서는 강체운동학의 기초를 이해할 필요가 있다. 

          아래의 플래시 무비는 직교회전행렬과 강체의 회전과의 관계를 보이기 위하여 만든 것이다.   버튼을 눌러 직6면체를 회전시키면서 실험해 보기 바란다.





플래시 무비
왼쪽 버튼들은 한번 클릭하면 X,Y,Z 축에 대해 5˚ 씩 회전하도록 풀그림됬다.
아래의 그림과 같은 직6면체의 지향을 직접 만들어 보는
 실험을 하면 강체의 운동학을 배우는데 도움이 될 것이다.




그림2) 직6면체의 초기지향과 회전행렬은 단위행렬이다. 



           <그림2>는  이 직6면체의 초기 지향(orientation, 강체의 놓임새)이다. 이 지향의 회전 직교행렬을 단위 행렬로 잡
는다. <그림 3>은 초기 지향에서 직6면체를 X축에 90° 회전시킨 후의 지향과 행렬을 나타 낸 것이다.  <그림4>는 <그림3>의 지향에서  Y축에 90° 회전시킨  후 지향과 회전 행렬을 나타낸 것이다.  <그림5>는 다시 초기 지향, <그림2>에서 먼저 Y 축에   90° 회전시킨 후의 결과를 나타 낸 것이고 <그림6>은 이어서 X축에  90° 회전시킨 후 결과를 보인다.  순서가 다른 회전의 결과 서로 다른 지향을 갖는다는 것은 유한한 각도의 회전은 비가환적이라는 사실을 말해 준다. 따라서 직교축에 대한 회전을 가지고 강체의 지향을 기술하는 방법은 적당하지 않다는 것을 알 수 있다.  즉 각 직교축에 대한 회전각 뿐만 아니라 회전을 실행한 순서도 함께 기술하지 않으면 서로 다른 행렬과 그에 해당하는 강체의 지향을 얻게 되기 때문이다. 이 것은 행렬 곱의 비가환성(noncommutability)이 바로 실세계에서 쓰이는 좋은 보기가 된다.   



그림3) X축에 90° 회전한 후 지향과  행렬





그림4) 다시 Y축에 90° 회전한 후 지향과 행렬 
 



그림5)  초기상태에서 먼저 Y축에 90° 회전한 지향과 행렬 




그림6) 이어서 X축에 90° 회전한 후 지향과 행렬

          <그림3>, <그림4>, <그림5>, <그림6>을  그리기 위하여 쓰인 행렬은  <표1>의 22줄에서 인스턴스를 만들어 쓴 Rotation3D라는 클래스 속에 들 어 있다. 이 클래스는  모든 3차원 강체의 운동을 제어하는 핵심 클래스라고  할 수 있다.  이 클래스는 매우 중요하므로 <표2>에 나열해 놓았다.         



1

class Rotation3D {

2

        var mat:Array;

3

        function Rotation3D() {

4

                mat = new Array([1, 0, 0], [0, 1, 0], [0, 0, 1]);

5

        }

6

        function unit() {

7

                mat[0] = [1, 0, 0];

8

                mat[1] = [0, 1, 0];

9

                mat[2] = [0, 0, 1];

10

        }

11

        function concat(m:Array) {

12

                var temp:Array = new Array([1, 0, 0], [0, 1, 0], [0, 0, 1]);

13

                for (var i = 0; i<3; i++) {

14

                        for (var j = 0; j<3; j++) {

15

                                temp[i][j] = mat[i][j];

16

                        }

17

                }

18

                for (var i = 0; i<3; i++) {

19

                        for (var j = 0; j<3; j++) {

20

        mat[i][j] = temp[i][0]*m[0][j]+temp[i][1]*m[1][j]+temp[i][2]*m[2][j];

21

                        }

22

                }

23

        }

24

        function rotateX(r:Number) {

25

        // r is in degrees - must convert to radians

26

        var rad = (r/180)*Math.PI;

27

        var cosA = Math.cos(rad);

28

        var sinA = Math.sin(rad);

29

        var m1:Array = new Array([1,0,0],[0,cosA,sinA],[0,-sinA,cosA]);

30

        concat(m1);

31

        }

32

        function rotateY(r:Number) {

33

        // r is in degrees - must convert to radians

34

        var rad = (r/180)*Math.PI;

35

        var cosA = Math.cos(rad);

36

        var sinA = Math.sin(rad);

37

        var m1:Array = new Array([cosA,0,-sinA], [0,1,0],[sinA,0, cosA]);

38

        concat(m1);

39

        }

40

        function rotateZ(r:Number) {

41

        // r is in degrees - must convert to radians

42

          var rad = (r/180)*Math.PI;

43

          var cosA = Math.cos(rad);

44

          var sinA = Math.sin(rad);

45

          var m1:Array = new Array([cosA,sinA,0],[-sinA,cosA,0],[0,0,1]);

46

             concat(m1);

47

        }

48

        function eulerAngles(phi, theta, psi) {

49

                var ph = (phi/180)*Math.PI;

50

                var th = (theta/180)*Math.PI;

51

                var ps = (psi/180)*Math.PI;

52

                var sinph = Math.sin(ph);

53

                var cosph = Math.cos(ph);

54

                var sinth = Math.sin(th);

55

                var costh = Math.cos(th);

56

                var sinps = Math.sin(ps);

57

                var cosps = Math.cos(ps);

58

                mat[0][0] = cosps*cosph-costh*sinph*sinps;

59

                mat[0][1] = -sinps*cosph-costh*sinph*cosps;

60

                mat[0][2] = sinth*sinph;

61

                mat[1][0] = cosps*sinph+costh*cosph*sinps;

62

                mat[1][1] = -sinps*sinph+costh*cosph*cosps;

63

                mat[1][2] = -sinth*cosph;

64

                mat[2][0] = sinth*sinps;

65

                mat[2][1] = sinth*cosps;

66

                mat[2][2] = costh;

67

        }

68

        function transform3D(pt3D:Array):Array {

69

                var result:Array = [0.0, 0.0, 0.0];

70

                for (var i = 0; i<3; i++) {

71

                        result[i] = mat[0][i]*pt3D[0]+mat[1][i]*pt3D[1]+mat[2][i]*pt3D[2];

72

                }

73

                return result;

74

        }

75

        function transform3DBody(pt3D:Array):Array {

76

                var result:Array = [0.0, 0.0, 0.0];

77

                for (var i = 0; i<3; i++) {

78

                        result[i] = mat[i][0]*pt3D[0]+mat[i][1]*pt3D[1]+mat[i][2]*pt3D[2];

79

                }

80

                return result;

81

        }

82

}


표2 Rotation3D 클래스 코드리스팅




          이 클래스의 속성인 줄2의 mat가 바로 직교 변환행렬로 이 클래스의 메쏘드 함수들은 모두 이 mat를 조작하거나

이 mat를 써서 원하는 효과를 얻는다.  줄3은 생성자 함수로 이 mat를 단위 행렬로 초기화한다.  줄6의 메쏘드함수
unit는 이 행렬을 단위행렬로 reset 하는 함수이고 줄11의 concat함수는 인수로 받은 행렬 m을 mat 행렬에 오른 쪽에
서 곱하는 함수이다. 즉



를 나타낸다. 

 

           줄24, 32, 40 은 기존 행렬 mat에 인수로 받은 각도 r(° 로)만큼 X, Y, Z 축에  대해 회전 시키는 행렬을 오른쪽에
서 곱하라는 메쏘드 함수를 말한다. 

            줄75는 이 회전 행렬을 써서 3차원 공간의 한 점 pt3D (3요소 배열)를 회전시키라는 명령이다.  이 때 회전축은
강체의 몸통에 붙어 있는 자리표 축이다. 반면 줄68은 공간 자리표 축에 대한 회전을 뜻하는데 이 경우에는 같은 행렬
을 쓰되 그 실제는  -r(°) 회전하는 결과를 가져온다.  공간 자리표와 몸통 자리표의 구분은 지구가 태양 주위를 공전할
때 지구의 몸통과는 상관 없는 공간의 관성자리표에 대한 회전이고 지구가 자전하는 경우 지구의 회전은 몸통에 붙어
있는 자리표, 남북극을 꿰뚫는 회전축이다. 몸통자리표축 회전이란  몸통에 불어 있는 자리표를 축으로 삼아서 돌린
회전을 말한다.  
 
           줄 75의 변환 메쏘드함수는 인수를 받은 3차원 벡터 pt3D(3요소 배열)에 변환행렬 mat를 오른쪽
에서 곱해 준다.  즉,   


  를 코딩한 것이다.
 


 

Posted by 샛솔 :
지난 토요일 (14일) 강남구와  자전거 잡지 THE BIKE 가 주최하는 Bike Festival 이 열렀다. 

참가할가 말가 망서리다 등록 마감일인 9일날 한사람당 참가비 만원씩 내고 등록을 했다.  내 배번은 3번이고 코니는 5번을 배당
받았다. 누군가 번호는 생산년도 순이라고 했다.  그렇다면 나보다 연장자 두사람이 더 있었다는 얘기다.  

행사장은 3호선 학여울역에 있는 SETEC(서울무역전시관)인지라 우리집에서는 2 Km 도 안된다. 늘 걸어 다니거나 자전거로 지나다니는 길옆이다.   우리 "나와바리" 행사인데 빠져서야 하고 등록을 했다.

전날 비가 왔지만 다행히 토요일은 기온은 약간 떨어졌지만 비는 그쳤다.   아침 8시까지 모여야 한다기에  8시 조금전에 도착했다.  그러나 행진은 9시에 출발이라 한시간 넘게 추운 곳에서 기다려야 했다.  그 덕에 코니는 감기가 걸려 아직도 몸상태가 좋지 않다.  

행진 코스는 행사장에서 나와 남부 순환도로를 따라 서진하다 매봉역을 지나 양재전화국에서 역삼역방향으로 우회전하여 역삼역에서 다시 오른쪽으로 꺾어 테헤란로를 달렸다.   테헤란로와 영동대로교차로에서 우회전하여 학여울역 행사장으로 돌아 오는10 Km 정도 되는 네모꼴의 코스였다.

역삼역에서 선름역까지는 내리막길로 통제 요원들이 보호해 주는 차선을 달리는 경험은 이런 행사가 아니고는 흔히 경험할 수 없는 일일거다.

행사후 함께한 벤트라이더회원과 "신마고"에서 점심을 했다.  


Festival 행사장


이른 아침은 제법 쌀쌀하다.


우리 자전거가 가장 호사한 것 같다.


벤트라이더 회원들 아콩님 같다.


신마고에서 "after"


카메라맨은 원래 3륜행진을 찍으려 했는데
Slyway가 쏜살같이 추월해와 앞장 서는 바람에..
 
Posted by 샛솔 :


                           
          물리에서는 움직여도 물체의 모양이 변형하지 않는 입체를 강체(rigid body) 라 부른다.  위의 프라톤 입체도 강체로 볼 수 있다.  강체를 그리려면 어떻게 할 것인가?  여기에는 수학과 물리를 피해 갈 도리가 없다.  강체 운동학 그리고 강체동력학이 들어오게 된다.  더욱이 3차원 시늉내기를 자연스럽게 하자면 물리 모델을 불러 쓸 수밖에 없고 따라서  수학과 물리로 이어질 수밖에 없다.  

          앞서 언급한 Digipen 대학의 교과과정을 보면 게임프로그래머를 양성하는 RTIS(실시간 대화형 시뮤레이션)학과의 교과 과정은 전산과학 25과목, 수학과 물리 21과목, 드로잉기초, 미술 감상, 신화, 창작법등은 단 5~6 과목에 불과했다.  그만큼 수학과 물리가  중요하다는 것이다. 

          나는 수학이나 물리도 가르치기에 따라 수학이나 물리에 소양이 없는 사람이라 할지라도 상당히 고급 내용을 소화하고 사용할 수 있게 가르칠 수 있다고 본다. 그것은 앞으로 수학자 물리학자, 수학교육학자, 물리교육학자가 도전해야  할 과제라고 본다.



아이소메트릭 투영법


          컴퓨터 스크린과 같이 2차원 평면에 3차원 영상을 투영한다는 것은 하나의 눈속임이다.   결코 두눈이 보는 입체감을 스크린위에 재현할 수는 없다.  다만 여러 가지 기법을 동원하여 조금 더 시각적 정보를 늘리려는 트릭이라 할 수 있다.




그림 1 주사위를 정면에서


그림 2 주사위를 45˚ 돌아서


그림3 다시 37˚ 올라서서



          <그림1>은  주사위 한 면을 정면에서 본 것으로 주사위의 입체적 정보는 전혀 없다.  오직 한면만 보고 있기 때문이다.  두 째 그림, <그림2>는  45° 도 돌아선 각도에서 본 경우로 두면이 보이고 이 물체가 최소한 구조를 가지고 있다는 정보를 준다.  <그림3>은  다시 약 37° 올라서서   본 것으로  주사위의 3면이 모두 보이고 주사위의 입체감은 최고조에 달한다.   이러한 시각이 아이소메트릭 투영법(Isometric projection)이다.  즉 직각을 이루는 입체의 3면이 모두 같은 비율로 보인다는 뜻이다.  

          이와 같은 투영법은 요지음 게임프로그램에  아주 많이 쓰인다.  아래의 <그림4>는 이러한 투영법을 사용한 게임의 스크린 셧을 몇 컷 옮겨 놓은 것이다.  
 

그림4  게임프로그램의 스크린셧 2개



           아이소메트릭 투영법은 한국화에도 아주 많이 나타나는데 한국화 중에서도 일반 회화가 아닌 경우가 그렇다.  주로 삽화 또는 기록화로 정보를 전달하려는 목적이 강한  경우에 이러한 기법이 자주 쓰인다.  <그림5>는  김홍도의 오륜행실도인데 이는 문자를 모르는 백성들에게 도덕을 가르치려고 편찬된 일종의 그림책이기 때문에 가장 정보를 잘 전 전달할 수 있는 아이소메트릭 투영법이 사용된 것이다.  

그림 5  김홍도의 오륜행실도중 하나


          아래의 플래시 무비는 아이소메트릭 투영법을 얻는 방법을 데모로 보인 것이다.  풀그림을 가르치기 위해 풀그림을 사용하는 방법, 이것이 내가 주장하는 새로운 교육 방법이다.  이 무비는 스크린자리표를 모서리로 하는  정6면체를 어떻게 회전시키면  원하는 각도로 자리표를 나타 낼 수 있는지를 여러 자리표에 대해 시범을 보인 무른모이다. 원하는 투영법 자리표를 래디오 버튼으로 선택하면 정6면체가 회전하여 최종 목표의 자리표(coordinate)로 바뀐다.  

          2 차원 평면에 3차원 물체를 나타 낼 때 쓰는 자리표는 실제로 어떤 각도로 투영하여 보이게 하는가를 이해 할 수 있을 것이다.  

          초기의 스크린 자리표는 오른쪽 수평방향이  +X이고 수직 아래 방향이 +Y 축이 된다.  오른손 나사법칙에 따라 오른손 나사방향 자리표(앞으로 우리는 이 자리표계를 계속 사용한다.)는 스크린 안쪽으로 들어가는 수평방향이 +Z 축이 된다.  오른손 나사법칙방향이란 나사를 +X 축에서 +Y 축방향으로 회전시키면 오른손 나사가 진행하는 방향이 +Z 축이 된다는 뜻이다.  
 

          IsometricA 는 처음에 공간의 X축에 대해 90° 회전시키고 다음에 공간 Y축에 45° 회전시킨다. 그런 다음 다시 공간 X축에 대해 37° 회전시키면 생기는 자리표다.  독자가 직접 이 과정을 실험해 보기 바란다. 직접 해 보면 가장 잘 이해 할 수 있다.

 



플래시 무비 1
이이소메트릭 투영법은 보여 주는 데모 플래시 무비
독자가 위의 선택 버튼을 눌러 실험해 보면 이해가 빠를 것이다.  


            아이소메트릭 자리표를 사용하는 것은 간단한 변환만 하여 주면 된다.  이를 위한 변환 함수를 메쏘드 함수로 포함하고 있는 static class Isom을 만들었다.  <표1>



1

class Isom {

2

static var oneBySqrt2:Number = 1/Math.sqrt (2);

3

static var oneBySqrt6:Number  = 1/Math.sqrt (6);

4

static var oneBySqrt3:Number  = 1/Math.sqrt (3);

5

 

6

static function mTSA (pt3D:Array ):Array {

7

        var x:Number = oneBySqrt2*(pt3D[0]+pt3D[1]);

8

        var y:Number = oneBySqrt6*(pt3D[0]-pt3D[1]-2*pt3D[2]);

9

var z:Number = oneBySqrt3*(pt3D[1]-pt3D[0]-pt3D[2]);

10

        return [x, y, z];

11

};//function mTSA

12

 

13

static function mTSB (pt3D:Array):Array {

14

        var x:Number = oneBySqrt2*(-pt3D[0]+pt3D[1]);

15

        var y:Number = oneBySqrt6*(pt3D[0]+pt3D[1]-2*pt3D[2]);

16

var z:Number = oneBySqrt3*(-pt3D[1]-pt3D[0]-pt3D[2]);

17

        return [x, y, z];

18

};//function mTSB

19

}//class Isom


코드 리스팅 표 1
아이소메트릭 변환 static class


          코드 리스팅  <표1>이 바로 그것인데 여기에는 두개의 메쏘드 함수 mTSA(map to screen A)와 mTSB가 있다.    임의의 3차원 자리표를 2차원 컴퓨터 스크린에 나타내려면  3차원 자리표를 [x, y, z]와 같은 배열로 만들어 이를 이 함수의 인자로 전달하면 되돌려 받는 함수 값이 스크린 자리표이다.  이 배열 역시 3차원 자리표인데 x, y만 2차원 스크린 자리표로 쓰고 z값은 여러 물체가 겹쳐 있을 때에는 깊이 변수로 쓸 수 있다.  z값이 크면 스크린 깊게 있으므로 먼저 그려 안쪽 깊숙히 있게 하고  z값이 작으면 나중에 그려 스크린 앞쪽으로  나오게 한다.  

           아이소메트릭 자리표가 3차원 강체를 그리는데 반드시 필요한 것은 아니다. 그런데도 이 이야기를 꺼낸 것은 3차원 강체의 운동을 기술하는 방법을 설명하기 위한 것이다.  앞으로의 이 튜토리얼에서는 모두 아이소메트릭 투영법B, 즉  static 함수 Isom.mTSB( pt3D:Array)를 불러 변환을 한 다음 스크린에 나타내게 한다.
 
Posted by 샛솔 :