[目次へ]
UPDATE 2021.03.07

(42)3D表示ルーチン(三次元図形の作画)

概要

(1) 3点透視図法を用いて三次元図形を作画する。

(2) 三次元図形を作画する複数のサブルーチンで構成する。

(3) 陰面消去を行う(試作)。

       


(42−1) Fig3D(3D表示ルーチンの初期化)

機能:

(a)透視変換マトリックスを作成し,3D表示ルーチンを使用可能にする。

(b)3D表示ルーチンの最初に実行する。

使用法:

    CALL FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS)

引 数
入出力
内  容
XF,YF,ZF
実数型
入力
視点位置(XYZ座標)の値。
XA,YA,ZA
実数型
入力
注視点位置(XYZ座標)の値。
AN
実数型
入力
スケールファクター。値が小さい程図が拡大される。0.3〜4.5。
WS
実数型
入力
投影面の1/2サイズ。値が大きい程図が拡大される。XVIEWPのサイズに対して 0.3〜1.3 倍。

図42.1 座標系の説明

使用例:

 プログラム例1(図42.1を作画)

! ... FIG3D sample 1 ...
      data XF,YF,ZF/30.0,20.0,80.0/,XA,YA,ZA/0.0,0.0,0.0/
      data AN,WS/2.0,25.0/
      call XINT('WIN=(800,800)')
      call XVIEWP(-12.5,-12.5,12.5,12.5)
      call FRAME (-12.5,-12.5,12.5,12.5)
      call FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS)   ! First call
      call CFONT(1)
      call CLRPEN(01)
      call PLOT3D(0.0,0.0,0.0,3)
      call PLOT3D(7.0,0.0,0.0,2)
      call PLOT3D(0.0,7.0,0.0,3)
      call PLOT3D(0.0,0.0,0.0,2)
      call PLOT3D(0.0,0.0,11.5,2)
! === AXIS SYMBOL
      call CONV3D(7.5,0.0,0.0,X,Y)
      call SYMBLE(X,Y,0.6,103,0.0,-1)       ! X
      call CONV3D(0.0,7.5,0.0,X,Y)
      call SYMBLE(X-0.1,Y,0.6,104,0.0,-1)   ! Y
      call CONV3D(0.0,0.0,12.5,X,Y)
      call SYMBLE(X,Y,0.6,105,0.0,-1)       ! Z
      call CLRPEN(21)
      call PARA3D(-5.0,-5.0,5.0, 10.0,10.0,10.0,-1)
      call XEND
      stop
      end

(42−2) CONV3D,CONV3X(3D座標を2D座標に変換)

機能:

(a)透視変換マトリックスを用いて,3D座標を2D座標に変換する。

(b)2Dの図形ルーチンを使用するときに用いる。

使用法:

    CALL CONV3D(XP,YP,ZP,XW,YW)
    CALL CONV3X(XP,YP,ZP,XW,YW,DP)

引 数
入出力
内  容
XP,YP,ZP
実数型
入力
3Dの座標値(XYZ座標)。
XW,YW
実数型
出力
変換された2Dの座標値(XY座標)。
DP
実数型
出力
変換されたZ値(深度)。
作図では通常は使用しないが深度が必要なときに用いる。

使用例:

 プログラム例1を参照。


(42−3) PLOT3D(ペンの移動を3D座標で指定する)

機能:

(a)ペンを移動する座標位置を3D座標で指定する。

(b)原点移動にも用いる。

使用法:

    CALL PLOT3D(XP,YP,ZP,IPEN)

引 数
入出力
内  容
XP,YP,ZP
実数型
入力
ペンを移動する3Dの座標値(XYZ座標)。
IPEN
整数型
入力
移動するペンのUP/DOWNを指定する。
|IPEN|=2 のときペンダウンで作画する。
|IPEN|=3 のときペンアップで移動する。
 IPEN<0 のとき原点を移動する。

使用例:

 プログラム例1を参照。


(42−4) RECT3D,RECT3X(四辺形を作画する)

機能:

(a)四辺形の4頂点の3D座標を指定して四辺形を作画する。

(b)四辺形を指定したカラーで塗りつぶす。横向きの面は明度が下がる。

(c)塗りつぶしと同時に四辺形を現在ペンで作画する。又は,四辺形のみを作画する。

(d)四辺形の頂点は反時計回りに指定する。裏面は表示しない。

(e) RECT3Xルーチンは,陰面消去を行うときに使用する。後述のDISP3Xルーチンの実行時にまとめて表示される。DISP3Xを参照。

使用法:

    CALL RECT3D(A,B,C,D,IC)
    CALL RECT3X(A,B,C,D,IC)

引 数
入出力
内  容
A,B,C,D
実数型
配 列
入力
四辺形の各頂点の座標値(XYZ座標)を設定した大きさ3の配列。
必ず反時計回り(左回り)に指定する。
IC
整数型
入力
IC>0 のとき,塗りつぶす色を INT(Z'BBGGRR') で指定する。
IC<0 のとき,塗りつぶした後に現在ペンで頂点を直線で結ぶ。
ただし,IC=−1 のときは塗りつぶしをしない。

IC>0IC<−1IC=−1
図42.2 RECT3Dでの作画

使用例:

 プログラム例2

! ... RECT3D sample ...
      data XF,YF,ZF/30.0,20.0,80.0/
      data XA,YA,ZA/0.0,0.0,0.0/,AN,WS/2.0,25.0/
      call XINT('WIN=(800,800)')
      call XVIEWP(-12.5,-12.5,12.5,12.5)
      call FRAME (-12.5,-12.5,12.5,12.5)
      call FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS) ! first call
! === AXIS ====
      call PLOT3D(-5.0,-4.0,-5.0,-3)      ! move origin
      call CLRPEN(01)
      call PLOT3D(0.0,0.0,0.0,3)
      call PLOT3D(11.0,0.0,0.0,2)
      call PLOT3D(0.0,11.0,0.0,3)
      call PLOT3D(0.0,0.0,0.0,2)
      call PLOT3D(0.0,0.0,11.5,2)
! === AXIS SYMBOL
      call CFONT(1)
      call CONV3D(11.5,0.0,0.0,X,Y)
      call SYMBLE(X,Y,0.6,103,0.0,-1)     ! X
      call CONV3D(0.0,11.5,0.0,X,Y)
      call SYMBLE(X-0.1,Y,0.6,104,0.0,-1) ! Y
      call CONV3D(0.0,0.0,12.5,X,Y)
      call SYMBLE(X,Y,0.6,105,0.0,-1)     ! Z
! === Draw Globe
      call GLOBE(5.0,5.0,5.0,5.0,-INT(Z'0000FF'),12)
      call GLOBE(0.0,0.0,0.0,3.0,INT(Z'00FF00'),12)
      call CLRPEN(31)
      call GLOBE(7.0,0.0,3.0,3.0,-1,12)
      call XEND
      stop
      end
!
      Subroutine GLOBE(XP,YP,ZP,R,IC,N)
      real, allocatable :: P(:,:,:)
      allocate (P(3,N*2,N+1))
      TH = 3.1415926/FLOAT(N)
      TX = 3.1415926/FLOAT(N)
      do 10 K=1,N+1
      RD  = 1.5707963-TX*FLOAT(K-1)        ! +90 > -90
      RCO = R*COS(RD)
      RSA = R*SIN(RD)
      do 20 I=1,N*2
      P(1,I,K) = RCO*COS(TH*FLOAT(I-1))+XP ! X
      P(2,I,K) = RSA+YP                    ! Y
      P(3,I,K) = RCO*SIN(TH*FLOAT(1-I))+ZP ! Z
   20 continue
   10 continue
      do 30 K=1,N
      do 40 I=1,N*2
      J = MOD(I,N*2)+1
      K1 = K+1
      call RECT3D(P(1,I,K),P(1,I,K1),P(1,J,K1),P(1,J,K),IC)
   40 continue
   30 continue
      deallocate (P)
      return
      end

 

※RECT3Dでは,陰面(線)処理を行わないので,視点から遠い面を先に描画します。


(42−5) PARA3D,PARA3X(直方体を作画する)

機能:

(a)基準点(3D座標)を指定してXY平面に平行な直方体を作画する。

(b) RECT3D(RECT3X)ルーチンを使用して作画する。

(c)仕様は RECT3Dに準ずる。

(d) PARA3Xルーチンは,陰面消去を行うときに使用する。後述のDISP3Xルーチンの実行時にまとめて表示される。DISP3Xを参照。

使用法:

    CALL PARA3D(XP,YP,ZP,H,W,D,IC)
    CALL PARA3X(XP,YP,ZP,H,W,D,IC)

引 数
入出力
内  容
XP,YP,ZP
実数型
入力
直方体の基準点の座標値(XYZ座標)。
実数型
入力
直方体の高さ(Y方向の長さ)。
実数型
入力
直方体の幅(X方向の長さ)。
実数型
入力
直方体の奥域(-Z方向の長さ)。
IC
整数型
入力
IC>0 のとき,塗りつぶす色を INT(Z'BBGGRR') で指定する。
IC<0 のとき,塗りつぶした後に現在ペンで頂点を直線で結ぶ。
ただし,IC=−1 のときは塗りつぶしをしない。

使用例:

 プログラム例3

! ... PARA3D sample ...
      data XF,YF,ZF/30.0,20.0,80.0/
      data XA,YA,ZA/0.0,0.0,0.0/,AN,WS/1.9,26.0/
      call XINT('WIN=(800,800)')
      call XVIEWP(-12.5,-12.5,12.5,12.5)
      call FRAME (-12.5,-12.5,12.5,12.5)
      call FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS)   ! first call
      call PLOT3D(-4.5,-3.0,-5.0,-3)        ! move origin
      call HOUSE
      call XEND
      stop
      end
!
      Subroutine HOUSE
      real P(3,4)
      data IC0/Z'00a000'/,IC1/Z'e0ffff'/,IC2/Z'a0a0a0'/, &
           IC3/Z'ffd0d0'/,IC4/Z'0b2161'/,IC5/Z'ffffff'/
      call CLRPEN(1)
      call PARA3D(-2.0,-0.3,12.0, 0.0,14.0,13.0,IC0)! graund
      call PARA3D( 0.0,-0.3,9.0,0.3,10.0,9.0,IC2)  ! base
      call PARA3D( 0.0,0.0,4.5, 2.5,5.0,4.5,-IC1)  ! 1F
      call PARA3D( 0.0,0.0,9.0, 2.5,5.0,4.5,-IC1)  ! 1F
      call PARA3D( 5.0,2.4,9.0, 0.1,5.0,9.6,-IC1)  ! 1F loof
      call PARA3D( 5.0,0.0,4.5, 2.5,5.0,4.5,-IC1)  ! 1F
      call PARA3D( 5.0,0.0,9.0, 2.5,5.0,4.5,-IC1)  ! 1F
      call PARA3D(-0.6,2.4,9.6, 0.1,5.6,10.2,-IC1) ! 1F loof
      call PARA3D( 5.0,4.9,3.9, 0.1,5.0,4.5,-IC1)  ! 2F loof
      call PARA3D( 0.0,2.5,9.0, 2.5,5.0,4.5,-IC1)  ! 2F
      call PARA3D( 5.0,2.5,9.0, 2.5,5.0,9.0,-IC1)  ! 2F
      call PARA3D(-0.6,4.9,9.6, 0.1,5.6,5.7,-IC1)  ! 2F loof
      call PARA3D( 0.0,5.0,9.0, 2.4,10.0,4.5,IC1)  ! 3F
      call PARA3D(-0.6,7.4,9.6, 0.3,11.2,6.0,IC5)  ! loof
      call SETIRGB(INT(Z'b0b0b0'))
      call TESURI(10.0,2.5,0.0,1.0,0.0,-0.6)       ! 2F
      call TESURI(-0.6,2.5,-0.6,1.0,10.6,0.0)
      call TESURI(-0.6,2.5,-0.6,1.0,0.0,10.2)
      call TESURI(-0.6,2.5,9.6,1.0,5.6,0.0)
      call TESURI( 5.0,2.5,9.6,1.0,0.0,-0.6)
      call TESURI(10.0,5.0,4.5,1.0,0.0,-5.1)       ! 3F
      call TESURI( 5.0,5.0,-0.6,1.0,5.0,0.0)
      call TESURI( 5.0,5.0,-0.6,1.0,0.0,4.5)
      call TESURI( 5.0,5.0,3.9,1.0,-5.6,0.0)
      call TESURI(-0.6,5.0,3.9,1.0,0.0,5.7)
      call TESURI(-0.6,5.0,9.6,1.0,5.6,0.0)
      call TESURI( 5.0,5.0,9.6,1.0,0.0,-0.6)
      call CLRPEN(1)
      call PARA3D( 0.0,0.0,4.5, 2.5,5.0,4.5,-1)    ! 1F
      call PARA3D( 0.0,0.0,9.0, 2.5,5.0,4.5,-1)    ! 1F
      call PARA3D( 5.0,0.0,4.5, 2.5,5.0,4.5,-1)    ! 1F
      call PARA3D( 5.0,0.0,9.0, 2.5,5.0,4.5,-1)    ! 1F
      call PARA3D( 5.0,0.0,9.0, 2.5,1.5,0.3,-1)    ! 1F ent
      call PARA3D( 5.0,0.0,8.7, 2.0,1.0,0.0,-IC4)  ! 1F door
      call PARA3D(10.0,0.0,6.1, 2.0,0.0,0.6,-IC4)  ! 1F door
      call PARA3D( 0.0,1.0,8.0, 0.9,0.0,1.8,-1)    ! 1F Window
      call PARA3D( 0.0,1.0,3.0, 0.9,0.0,1.8,-1)    ! 1F Window
      call PARA3D( 2.0,1.4,9.0, 0.6,1.8,0.0,-IC3)  ! 1F Window
      call PARA3D( 1.0,0.2,0.0, 1.8,1.8,0.0,-1)    ! 1F Window
      call PARA3D( 6.0,0.2,0.0, 1.8,1.8,0.0,-1)    ! 1F Window
      call PARA3D(10.0,1.0,3.0, 0.9,0.0,1.8,-IC3)  ! 1F Window
      call PARA3D(10.0,1.0,8.5, 0.9,0.0,0.5,-IC3)  ! 1F Window
      call PARA3D(10.0,1.0,7.0, 0.9,0.0,0.5,-IC3)  ! 1F Window
      call PARA3D( 9.0,0.0,7.4, 2.5,1.0,1.3,-1)    ! 1F toilet
      call PARA3D( 7.5,0.0,9.0, 2.5,2.5,1.6,-1)    ! 1F bath
      call PARA3D( 7.5,0.0,7.4, 2.5,2.5,1.3,-1)    ! 1F bath
      call PARA3D( 9.2,0.0,9.0, 0.2,0.6,1.6,-1)    ! bath tab
      call PARA3D( 0.0,0.0,9.0, 0.9,3.9,0.75,-1)   ! kitchen
      call STEPS ( 9.2,0.0,5.5, 2.5,-3.0,1.0)      ! 1-2F steps
      P(1:3,1) = (/2.0,-0.3,11.0/)
      P(1:3,2) = (/5.0,0.0,11.0/)
      P(1:3,3) = (/5.0,0.0, 9.0/)
      P(1:3,4) = (/2.0,-0.3, 9.0/)
      call RECT3D(P(1,1),P(1,2),P(1,3),P(1,4),INT(Z'80ff20'))
      P(1:3,2) = (/5.0,-0.3,11.0/)
      P(1:3,3) = (/5.0,0.0,11.0/)
      P(1:3,4) = P(1:3,1)
      call RECT3D(P(1,1),P(1,2),P(1,3),P(1,4),IC1) ! slope
      call PARA3D( 5.0,-0.3,11.0, 0.3,2.0,2.0,IC1) ! poach
      call PARA3D( 0.0,2.5,9.0, 2.5, 5.0,4.5,-1)   ! 2F
      call PARA3D( 5.0,2.5,9.0, 2.5, 5.0,9.0,-1)   ! 2F
      call PARA3D( 0.0,3.5,8.0, 0.9, 0.0,1.8,-1)   ! 2F Window
      call PARA3D( 1.5,3.5,9.0, 0.9, 1.8,0.0,-IC3) ! 2F Window
      call PARA3D( 5.5,3.5,9.0, 0.9, 0.4,0.0,-IC3) ! 2F Window
      call PARA3D( 8.0,3.5,9.0, 0.9, 1.2,0.0,-IC3) ! 2F Window
      call PARA3D( 1.5,2.7,4.5, 1.8, 1.8,0.0,-1)   ! 2F Window
      call PARA3D( 6.0,2.7,0.0, 1.8, 1.8,0.0,-1)   ! 2F Window
      call PARA3D( 5.0,2.7,3.0, 1.8, 0.0,1.8,-1)   ! 2F Window
      call PARA3D(10.0,3.5,8.0, 0.9, 0.0,1.8,-IC3) ! 2F Window
      call PARA3D( 7.3,3.8,9.0, 0.0, 0.8,2.0,-1)   ! 2-3F step
      call STEPS ( 6.0,2.5,8.0, 1.3, 1.3,1.0)      ! 2-3F steps
      call STEPS ( 7.3,3.8,9.0, 1.2,-1.3,1.0)      ! 2-3F steps
      call PARA3D( 0.0,5.0,9.0, 2.4, 5.0,4.5,-1)   ! 3F
      call PARA3D( 5.0,5.0,9.0, 2.4, 5.0,4.5,-1)   ! 3F
      call PARA3D( 0.0,6.0,8.0, 0.9, 0.0,1.8,-1)   ! 3F Window
      call PARA3D( 1.5,6.0,9.0, 0.9, 1.8,0.0,-IC3) ! 3F Window
      call PARA3D( 5.5,6.0,9.0, 0.9, 0.4,0.0,-IC3) ! 2F Window
      call PARA3D( 8.0,6.0,9.0, 0.9, 1.2,0.0,-IC3) ! 3F Window
      call PARA3D( 1.5,5.2,4.5, 1.8, 1.8,0.0,-1)   ! 3F Window
      call PARA3D( 6.0,5.2,4.5, 1.8, 2.4,0.0,-1)   ! 3F Window
      call PARA3D(10.0,6.0,8.0, 0.9, 0.0,1.8,-IC3) ! 1F Window
      call PARA3D(-0.6,7.4,9.6, 0.3,11.2,6.0,-1)   ! loof
      return
      end

 !
      Subroutine STEPS(XP,YP,ZP,H,W,D)
      SK1 = 1.0/FLOAT(INT(H*5.0+0.001))
      SK2 = 1.0/FLOAT(INT(H*5.0-0.999))
      DH = H*SK1
      DX = W*SK2
      SW = 0.0
      SH = DH
      do I=1,15
        call PLOT3D(XP+SW,   YP+SH,   ZP-D,3)
        call PLOT3D(XP+SW,   YP+SH,   ZP,  2)
        call PLOT3D(XP+SW,   YP+SH-DH,ZP,  2)
        call PLOT3D(XP+SW,   YP+SH-DH,ZP-D,2)
        call PLOT3D(XP+SW,   YP+SH,   ZP-D,2)
        if (ABS(SH-H).le.0.001) exit
        call PLOT3D(XP+SW+DX,YP+SH,   ZP-D,2)
        call PLOT3D(XP+SW+DX,YP+SH,   ZP,  2)
        call PLOT3D(XP+SW,   YP+SH,   ZP,  2)
        SH = SH+DH
        SW = SW+DX
      end do
      return
!
      Entry TESURI(XP,YP,ZP,H,W,D)
      SK = 1.0/FLOAT(INT(ABS(W+D)*5.0))
      DX = W*SK
      DD = D*SK
      SW = 0.0
      SD = 0.0
      call PLOT3D(XP,  YP+H,    ZP,  3)
      call PLOT3D(XP+W,YP+H,    ZP+D,2)
      call PLOT3D(XP,  YP+H*0.9,ZP,  3)
      call PLOT3D(XP+W,YP+H*0.9,ZP+D,2)
      call PLOT3D(XP,  YP+H*0.1,ZP,  3)
      call PLOT3D(XP+W,YP+H*0.1,ZP+D,2)
      do I=1,50
        if (((SW-W)**2+(SD-D)**2).le.1.0e-3) exit
        if (MOD(I,10).eq.0) then
          call PLOT3D(XP+SW,YP+H,ZP+SD,3)
          call PLOT3D(XP+SW,YP,  ZP+SD,2)
        else
          call PLOT3D(XP+SW,YP+H*0.9,ZP+SD,3)
          call PLOT3D(XP+SW,YP+H*0.1,ZP+SD,2)
        end if
        SW = SW+DX
        SD = SD+DD
      end do
      return
      end

(42−6) DISP3X(スタックした面を視点から遠い順に作画する)

機能:

(a) RECT3Xルーチン等でスタックした四辺形の平面データを視点から遠い順に作画する。

(b)視点から遠い平面は近い平面に上書きされ結果的に陰面消去されて作画される。

(c)制限事項がある。

(d)試作のため,アルゴリズムの変更により仕様変更の可能性がある。

使用法:

    CALL DISP3X

使用例:

 プログラム例4

! ... DISP3X sample ...
      data XF,YF,ZF/30.0,20.0,80.0/,XA,YA,ZA/0.0,0.0,0.0/
      data AN,WS/1.0,20.0/
      call XINT('WIN=(800,800)')
      call XVIEWP(-12.5,-12.5,12.5,12.5)
      call FRAME (-12.5,-12.5,12.5,12.5)
      call FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS)   ! First call
      call PLOT3D(-4.5,-5.0,-5.0,-3)        ! move origin
      call PARA3X( 4.0,2.0,4.0, 4.0,4.0,0.0,INT(Z'0000b0'))
      call PARA3X( 0.0,2.0,4.0, 4.0,4.0,0.0,INT(Z'0000ff'))
      call PARA3X( 4.0,2.0,7.0, 4.0,0.0,6.0,INT(Z'00ff00'))
      call PARA3X( 0.0,2.0,7.0, 4.0,0.0,6.0,INT(Z'ff0000'))
      call PARA3X( 0.0,2.0,1.0, 4.0,4.0,0.0,INT(Z'00ffff'))
      call PARA3X( 0.0,2.0,7.0, 4.0,4.0,0.0,INT(Z'ff80ff'))
      call PARA3X( 4.0,2.0,1.0, 4.0,4.0,0.0,INT(Z'ffff00'))
      call PARA3X( 8.0,2.0,7.0, 4.0,0.0,6.0,INT(Z'ff00ff'))
      call PARA3X( 1.0,3.0,7.0, 2.0,2.0,0.0,INT(Z'ffe0ff'))
      call PARA3X( 4.0,2.0,7.0, 0.0,4.0,3.0,INT(Z'ff6060'))
      call DISP3X                           ! Display data
      call XEND
      stop
      end

 プログラム例5

! ... DISP3X sample ...
      data XF,YF,ZF/30.0,40.0,80.0/,XA,YA,ZA/0.0,0.0,0.0/
      data AN,WS/1.0,22.0/
      call XINT('WIN=(800,800)')
      call XVIEWP(-12.5,-12.5,12.5,12.5)
      call FRAME (-12.5,-12.5,12.5,12.5)
      call FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS)
      call Donut(4.0,1.5,20,-INT(Z'ffff00'))
      call XEND
      stop
      end
      Subroutine Donut(R1,R2,N,IC)
      real, allocatable :: P(:,:,:)
      allocate(P(3,N,N))
      DT = 3.141593/FLOAT(N)*2.0
      do 10 J=1,N
      PY = DT*FLOAT(J-1)
      CO = COS(PY)
      SI = SIN(PY)
      do 20 I=1,N
      TH = DT*FLOAT(I-1)
      DI = COS(TH)*R2+R1
      P(1,I,J) = CO*DI
      P(2,I,J) = SIN(TH)*R2
      P(3,I,J) = SI*DI
   20 continue
   10 continue
      do 30 J=1,N
      J1 = MOD(J,N)+1
      do 40 I=1,N
      I1 = MOD(I,N)+1
      call RECT3X(P(1,I1,J),P(1,I1,J1),P(1,I,J1),P(1,I,J),IC)
   40 continue
   30 continue
      call DISP3X
      deallocate(P)
      return
      end

制限事項:

1)平面同士がクロスしてはいけない。


平面Aと平面Bがクロスしている×


平面A又は平面Bを分割する○

2)複数の平面により優先度が互いに推移するケース。


優先度が互いに推移している×


平面の一つを分割する○

3)複数の平面が平面を共有するケース。


優先度が同じ△


平面の一部を共有する平面同士は優先関係が存在しないため,表示される順序は不定となる。(多分,スタックした順に表示される。)

解説:

1.陰面消去の方法について

 陰面消去のアルゴリズムには次のような手法がある。

(1) 法線ベクトル法
ポリゴンの法線の向きを調べ,視線の方を向いている面のみを表示する方法。

(2) 塗り重ね法
ポリゴンを二次元に変換したとき深度が深い面から表示する方法。

(3) Zバッファ法
三次元座標を二次元に変換したときの深度をZバッファの値と比較し深度の浅い点の色をZバッファと共に記憶していく方法。

(4) スキャンライン法
Y軸上の走査線上でXZ平面上の画素を直線で結び,直線と各ポリゴンとの交点を調べ,視点に近い方のポリゴンの画素に色を付ける方法。

(5) レイトレーシング法
視点から対象物の各画素へ視線を延ばし,最初に当たった画素に色を付ける方法。

Zバッファ法以下は,表示デバイスがディスプレイを対象にした手法であり,図形ルーチンとしては馴染まない。(1)及び(2)の手法は,PostScript でも画面表示でも対応可能である。従って,本3D表示ルーチンでは,(1),(2)の手法を併用する。

2.法線ベクトル法による陰面消去

三次元空間に於ける四辺形の面の法線ベクトル N は,以下の式により求めることができる。

  

法線の計算は3頂点で求まるが4点で計算すると何れかの頂点が重複する場合(三角形になる場合)でも計算可能になる。

得られた法線ベクトルを二次元の投影平面に座標変換すると,得られたD値(深度)の符号により裏表の判定ができる。

3.塗り重ねによる陰面消去

塗り重ね法を用いた陰面消去では,表示する四辺形をすべて記憶領域に保存し,優先順位を決めてから表示する。

3-1 四辺形データの保存

四辺形の各頂点データは三次元のXYZ値で与えられる。表示する優先度を決めるためには,投影面の二次元座標に変換されたXY座標と深度値Dが必要となる。従って,4頂点の二次元のXY座標値とD値の他,指定したカラーの値をリスト構造を持つ記憶域を動的に確保して保存する。


head
next
next
next
⇒…⇒
null
tail
null
befor
befor
←…←
befor

last node
data 1
data 2
data 3
data n

3-2 二組の四辺形の優先判定

二組の四辺形が投影面上で交差していなければ,両者に従属関係はなく互いに優先度を決める必要がない。つまり,どちらを先に表示しても構わない。
 二組の四辺形の従属関係を調べるにあたり,できるだけ少ない計算量で済むことが望ましい。
 二組の四辺形が投影面上で交差しているかいないかの判定は次のように行う。

(1) X方向とY方向の最大値と最小値を比較する。

二組の四辺形をそれぞれ V1,V2 としたとき,V1Xmax<V2Xmin 又は,V2Xmax<V1Xminのときは,両者は交差していない。
 同様に,V2Ymax<V1Ymin 又は,V1Ymax<V2Ymin のときも,両者は交差していないので従属関係はない。
 関係が不成立のときは,両者の深度(D値)についてもMax,Minの関係を調べる。ただし,必ず交差しているとは限らないので (2) の判定に進む。

(2) どちらか一方の四辺形の少なくとも一つの頂点が他方の四辺形の内部にあるか調べる。

四辺形V1,V2の何れかの頂点が互いの四辺形の内部にあれば従属関係がある。優先度が未定のときは,その頂点の座標位置における両者の深度を比較して優先度を判定する。頂点が辺上にあって優先度が決まらない場合は他の頂点を調べる。
 各頂点の座標は既に深度(D値)が分かっているので,分かっていない方の同じ座標位置の深度を補間計算で求める。
 図の(1)および(2)が該当する。図(3)は頂点が内部に含まれないので別の判定を行う。

(3) 点Pが四辺形の内側にあるか外側にあるか調べる。

カウンターを用意して,各辺について,
辺の始点がPの下側にあり終点が上側にあるとき(図の辺CD),Pが辺の左側であれば,+1する。
辺の始点がPの上側にあり終点が下側にあるとき(図の辺AB),Pが辺の右側にあれば,−1する。
カウンターの合計が0以外のときは,Pが内部にあると判断する。

点Pと辺との位置関係は以下の式から求められる。

 S≧0 のとき,点Pは辺の左側(辺の上を含む)にある。
 S<0 のとき,点Pは辺の右側にある。

(4) 四辺形内の任意点の深度を求める。


 図はZ方向の深度をY方向に置き換えて表示した概念図を示す。
 四辺形内の点Pに於ける深度ZPの値は,四辺形の4頂点の深度から右式により補間して求められる。

(5) 両者の四辺形の辺の交差を調べる。

(2)の図(3)のように,頂点が互いに他の四辺形の内部にないときは,辺の交差の有無を判定する。


 二つの線分の交点を求める

四辺形V1の各辺がV2の各辺と交差している場合(0<r,s<1)は,優先順序が未定のときは交点を求めその交点に於ける両者の深度を(4)により求め優先順序を決める。
 辺の交差がない場合は,最終的に四辺形V1とV2には従属関係はないと判断する。

3-3 作画順序を決める

スタックした四辺形のデータは,上記の方法によりそれぞれの四辺形の組み合わせについて従属関係の有無と優先順序を調べる。
 これらの判定は,基準となる四辺形V1に対して比較する四辺形V2を引数に与え,結果を−1(V1>V2),0(従属関係なし),+1(V1<V2)を返す関数を用意して行う。

(1) 比較対照表を作成し表のデータをソートする。

スタックした四辺形データを並べ替えるのは容易ではない。
 表示順序を決めるために,それぞれの四辺形の交差と前後関係を比較した対照表を作成する。対照表をルールに従ってソートし表示順序を決める。

                V1
   0  1  2  3  4  5  6  7  8  9
   1  *                        
   2  1  *                     
   3 -1  0  *                  
V2 4  0  0  0  *               
   5  0  0  0  0  *            
   6  0  0  0  0  0  *         
   7  0 -1  0  0  0  1  *      
   8  0  0  0  0  0  0  0  *   
   9  0  0  0  0  0 -1  0  0  *

                V1
   0  1  2  3  4  5  6  7  8  9
   1  * -1  1  0  0  0  0  0  0
   2  1  *  0  0  0  0  1  0  0
   3 -1  0  *  0  0  0  0  0  0
V2 4  0  0  0  *  0  0  0  0  0
   5  0  0  0  0  *  0  0  0  0
   6  0  0  0  0  0  * -1  0  1
   7  0 -1  0  0  0  1  *  0  0
   8  0  0  0  0  0  0  0  *  0
   9  0  0  0  0  0 -1  0  0  *

スタックした面の数をNとすると,(0:N,0:N)のマトリックスを用意し,0行目と0列目は0から順にNまで番号を入れる。
基準となる四辺形V1に対してV2の優先度を調べ,低い場合を−1,高い場合を1とセットする。
対角側には−1を乗じた値をセットし,対照表にする。
                V1
   0  3  1  2  4  5  6  7  8  9
   3  * -1  0  0  0  0  0  0  0
   1  1  * -1  0  0  0  0  0  0
   2  0  1  *  0  0  0  1  0  0
V2 4  0  0  0  *  0  0  0  0  0
   5  0  0  0  0  *  0  0  0  0
   6  0  0  0  0  0  * -1  0  1
   7  0  0 -1  0  0  1  *  0  0
   8  0  0  0  0  0  0  0  *  0
   9  0  0  0  0  0 -1  0  0  *

                V1
   0  3  1  9  6  7  2  4  5  8
   3  * -1  0  0  0  0  0  0  0
   1  1  *  0  0  0 -1  0  0  0
   9  0  0  * -1  0  0  0  0  0
V2 6  0  0  1  * -1  0  0  0  0
   7  0  0  0  1  * -1  0  0  0
   2  0  1  0  0  1  *  0  0  0
   4  0  0  0  0  0  0  *  0  0
   5  0  0  0  0  0  0  0  *  0
   8  0  0  0  0  0  0  0  0  *

マトリックスの1列2行目から1列N行目まで−1の値を探す。
見つかった場合はその行すべてを1行目の前に移動する。対応する列も1列目の前に移動する。列の移動により同じ位置に−1が来る場合(最大でもN−列数回)があるが,続けてN行まで繰り返す。
1列目が終わったら,2列3行目から同様の操作を行い,N−1列まで繰り返す。
最後にはマトリックスの左下半分に−1がなくなる。なくならない場合は制限事項に該当するとき。
マトリックスの0列目1行目以降の値がソートされたスタックデータの順番となる。

対照表は分かり易くするために入れ替えを行っているが,実際の処理では参照のみ行い,入れ替えは0列目のみ行う。

(2) スタックデータの表示

ソートされた比較対照表の0列目の順番どおりにスタックした四辺形データを取り出し作画する。


(42−7) サンプルプログラム

 プログラム例6:正12面体を描く

正12面体の 20 の頂点のXYZ座標値を定義します。正12面体の頂点は,対面する2つの正方形と直交する3つの長方形の頂点からなります。

HVECTR_D3 ルーチンは,平面の4頂点を与えて法線ベクトルを計算し正規透視座標系に変換する内部サブルーチンです。
 5角形以上の平面を表示するサブルーチンは用意していないので,面の裏表の判定に流用しています。 得られたZベクトル値が負の時は可視と判定できます。
 さらに,Zベクトル値を正規化し視線方向(本来は光線の方向)との角度を利用して面の明度を調整して描画します。

WNSIGN サブルーチンは,バックバッファを画面表示し,マウスのクリックや移動を検知するのに使用しています。
 マウスの左クリックを押しながら左右に移動するとY軸を中心に視点が回転します。Escapeキーを押すと終了します。

!...Fig3D sample No.6  正12面体(regular dodecahedron) の描画 ...
    real, parameter :: A = 1.618034     ! A = (1.0+SQRT(5.0))*0.5
    real, parameter :: B = 2.618034     ! B = A**2
    real, parameter :: AH = 0.809017    ! AH = A*0.5
    real, parameter :: AM =-0.809017    ! AM = -A*0.5
    real, parameter :: BH = 1.309017    ! BH = B*0.5
    real, parameter :: BM =-1.309017    ! BM = -B*0.5
    real P(3,20)/AH,AH,AH, AH,AM,AH, AH,AM,AM, AH,AH,AM, & !  1- 4  T1-T4
                 AM,AH,AH, AM,AM,AH, AM,AM,AM, AM,AH,AM, & !  5- 8  T5-T8
     0.5,0.0,BH,  0.5,0.0,BM,  -0.5,0.0,BM, -0.5,0.0,BH, & !  9-12  P1-P4
     BH, 0.5,0.0, BM, 0.5,0.0, BM,-0.5,0.0, BH,-0.5,0.0, & ! 13-16  Q1-Q4
     0.0,BH, 0.5, 0.0,BM, 0.5, 0.0,BM,-0.5, 0.0,BH,-0.5/   ! 17-20  R1-R4
    integer N(5,12) &
          / 5,12,9,1,17, 17,1,13,4,20, 20,4,10,11,8, 8,11,7,15,14, &
           14,15,6,12,5, 5,17,20,8,14, 2,9,12,6,18,  18,6,15,7,19, & 
           19,7,11,10,3, 3,10,4,13,16, 16,13,1,9,2,  2,18,19,3,16/
    real XY(2,5),U(3,5)
    data XA,YA,ZA/0.0,0.0,0.0/,XF,YF,ZF/15.0,20.0,60.0/
    data AN,WS/0.6,11.0/                ! (0.3,7.6)〜(4.0,32.0)
    C  = COS(0.01745329)
    S0 = SIN(0.01745329)
    X0 = 0.0
    S  = 0.0
    call XINT('WIN=(600,600)')
    call XVIEWP(-6.0,-6.0,6.0,6.0)
    call CFONT(3)
    go to 2
  1 call WNSIGN(XX,YY,ICODE)
    if (ICODE == 27) go to 9            ! escape key ?
    if (ICODE == 513) S = S0            ! left mouse down
    if (ICODE == 514) S = 0.0           ! left mouse up
    if (S == 0.0) go to 1
!...Rotate eye point around Y axis
    if (ICODE == 512) then
      S = SIGN(S0,XX-X0)
      X0 = XX
      XW = XF
      XF = XW*C - ZF*S
      ZF = XW*S + ZF*C
    end if
!...Draw 3D figure
  2 call FIG3D(XF,YF,ZF,XA,YA,ZA,AN,WS) ! initialize Fig3D
    call SETRGB(0.0,0.2,0.4)            ! dark blue
    call FLRECT(-6.0,-6.0,6.0,6.0)      ! clear screen
    do I=1,12
      do K=1,5
        M = N(K,I)
        U(:,K) = P(:,M)
        call CONV3D(P(1,M),P(2,M),P(3,M),XY(1,K),XY(2,K))
      end do
!     Compute normal vectors & transform normal perspective coordinate
      call HVECTR_D3(U(1,1),U(1,2),U(1,3),U(1,4),AV,BV,CV,DV)
      if (CV > 0.0) cycle               ! reverse side
      G  = (-CV/SQRT(AV**2+BV**2+CV**2)+1.0)*0.5  ! 0.5 -- 1.0
      call SETRGB(0.0,G,0.0)            ! green
      if (I == 1) call SETRGB(0.0,G,G)  ! cyan
      call FLPOLY(XY,5)
      call CLRPEN(71)
      call DRPOLY(XY,5)
      do K=1,5
        call NUMBER(XY(1,K),XY(2,K),0.3,FLOAT(N(K,I)),0.0,-1)
      end do
    end do
!...Draw axis ====
    call PLOT3D(0.0,0.0,0.0,3)
    call PLOT3D(2.0,0.0,0.0,2)
    call PLOT3D(0.0,2.0,0.0,3)
    call PLOT3D(0.0,0.0,0.0,2)
    call PLOT3D(0.0,0.0,2.0,2)
    call CONV3D(2.1,0.0,0.0,X,Y)
    call SYMBLE(X,Y,0.4,(/103/),0.0,-1)       ! X
    call CONV3D(0.0,2.2,0.0,X,Y)
    call SYMBLE(X,Y,0.4,(/104/),0.0,-1)       ! Y
    call CONV3D(0.0,0.0,2.2,X,Y)
    call SYMBLE(X,Y,0.4,(/105/),0.0,-1)       ! Z
    go to 1
  9 call XEND
    stop
    end