2017-09-13 6 views
2

今日私は疑似3Dとパースペクティブに関する主題を持っています。パースペクティブ・ビジョン・キャンバス

ビデオ#1 Java Classical 3D Rendering Tutorial : Creating 3D Worldをチェックしていましたが、レンダリング疑似3Dの天井と床の方法を使用しました。私はチュートリアルや彼が使用した方法の名前を見つけようとしましたが、見つけられませんでした。私はアルゴリズムを見ましたが、理解するのは明らかではありません。私は遠近法のグラフィックス(消失点、水平線...)を検索し始めましたが、私が得たユニークなものは静的な描画でした。私は、カメラを計画の中に入れて動かすという錯覚を適用したい。私が作りたい視点の床と天井の例に従ってください。

Static Perspective Image Static Perspective Image

これは単なるイメージですが、私の最初の質問は:「私は本当に回転のように、この環境では、カメラの動きを作り、Xを移動し、y軸ができますか?」。私はキャンバスに2つの消失点を作り、各度15度の線を作成しようとしましたが、私は遠近法の錯覚を得ましたが、私は回転や動きを作る方法を見つけることができませんでした。そのビデオでは、ピクセルがグリーンとブルーの色だけを使って2次元を作成するのを見ましたが、これをどのように動作させるかを理解するためにラインを使用して作成したいと考えています。

enter image description here

動きと視点を作成する方法をステップバイステップを教えているところはありません。私は見つからなかった。 Javaで3Dゲームメーカーのビデオをチェックし、Markus Personがビデオの方法で「Chamberのプレリュード」と呼ばれるゲームを作成しましたが、このレンダリングの王についての説明は見つかりませんでした。

enter image description here

私は、グリッドを使用して計画を作成する必要がありsuposeます。どのように私は行を運動を作成するために適用する必要がありますか?私は本当にこのような疑似3Dを作るためのロジックを、フレームワークやそのようなものを使わずに理解したいと思っています。助けてくれてありがとう!私はあなたの答えを待つでしょう。

私はSNESのMODE 7について何か確認しました。これは私が思うように良い方法です。私はそれがどのように動作するのか、そしてどのように回転を行うのかを理解するだけです。

enter image description here

**注:私はそれのためにレイキャスティングを使用するにはいないもの。レイキャスティング私は壁を作成するために使用します。

+0

homogenuous座標を使用してベクトルアプローチで回答を追加しました。 – Spektre

答えて

2

興味深い問題です。私は抵抗していませんでしたので、ここでいくつかの洞察力を楽しんでコード化しています...まあ、これには2つの基本的なアプローチがあります。 1つはラスタフェイク、もう1つはベクトルベースです。私はあなたがそれ以上のことをすることができるように、後者について説明します。

ベクトルアプローチ

このアプローチはそれが本当に3Dある何かを偽造されていません。残りの部分は、これを使用したいレンダリングに依存します...今のところ、2D行をレンダリングすることができます。すべてのコードチャンクはC++にあります。

  1. 変換は

    あなたは再び世界とカメラ空間との間でポイントを変換するために、ベクトル数学を必要とします。 3Dグラフィックスは通常です。これには4つの均質変換行列が使用され、多くのプログラミングにはAPIがネイティブにサポートされています。使用する乗算の​​順番を決めるマトリクスレイアウトは、OpenGLです。私はそれから多くを使用したよう

    :詳細情報については、私は強くこれを読むことをお勧めします。リンクされた答えは、特に3Dグラフィックスパイプラインと完全擬似逆行列にも役立ちます。アンサー自体は、3Dのレンダリングに必要な基本的な知識です(レンダリング用のものを少しも必要とせずに低レベルです)。

    あなたがあなたの代わりに私のコードの4x4の行列と4Dベクトルをサポートしている任意の線形代数を使用することができますしたい場合GLMのように、このためのLIBSはそうもあります。

    私たちのカメラ座標系を表す1つ(camera)とその逆の2つ目(icamera)の2つの4x4行列を持つことができます。私たちは世界と画面スペースの間で変換したい場合は今、私たちは、単にこれを実行します。

    P = camera*Q 
    Q = icamera*P 
    
    P(x,y,z,1)がポイントであるカメラ座標系

    Q(x,y,z,1)をグローバルな世界で同じポイント座標系です。

  2. 視点

    これは単にそのz座標によってPを分割することによって行われます。それは(0,0)の周りのオブジェクトをスケーリングするので、より遠いオブジェクトほど小さくなります。我々はいくつかの画面解像度と軸補正を追加した場合、私たちはこれを使用することができます。

    void perspective(double *P) // apply perspective transform on P 
        { 
        // perspectve division 
        P[0]*=znear/P[2]; 
        P[1]*=znear/P[2]; 
        // screen coordinate system 
        P[0]=xs2+P[0];   // move (0,0) to screen center 
        P[1]=ys2-P[1];   // axises: x=right, y=up 
        } 
    

    ので0,0が画面の中央にある点。 xs2,ys2は画面の解像度の半分であり、znearは投影の焦点距離です。画面解像度と中心のXY平面の長方形は(0,0,znear)に正確に画面をカバーします。私たちは、レンダリングのための任意のプリミティブを使用することができ、3Dラインに

    をレンダリング

  3. 。非常にシンプルで多くを達成できるので、私はラインを選んだ。ですから、私たちが望むのは、3Dラインを使用して、2DラインレンダリングAPI(いずれかの種類のもの)を使用することです。私はVCLをベースにしていますので、私はVCL/GDICanvasを選択しました。これはあなたのCanvasとよく似ています。

    入力として、世界座標系で2つの3Dポイントが得られました。 2D行でレンダリングするには、3Dポジションを2Dに変換する必要があります。これは、matrix*vectorの乗算によって行われます。

    これから2つの3D点を取得しますが、カメラ座標系で取得します。今私たちのビューエリア(Frustrum)でラインをクリップする必要があります。我々は、x,yの軸を2Dとして無視することができます。したがって、残っているのはクリップz軸のみです。 スラストラムz軸はznearzfarで定義されます。 zfarは、カメラの焦点からの最大視界距離です。したがって、私たちの行が私たちの前にある場合は、私たちはそれを無視してレンダリングしません。z-rangeそれが内部にあれば、それをレンダリングします。 znearまたはzfarを横切る場合は、外側の部分をカットします(x,y座標の線形補間による)。

    ここでは両方の点でパースペクティブを適用し、2Dの線をx,y座標で描画します。

    このための私のコードは次のようになります。XZ平面

    をレンダリング

    void draw_line(TCanvas *can,double *pA,double *pB) // draw 3D line 
        { 
        int i; 
        double D[3],A[3],B[3],t; 
        // transform to camera coordinate system 
        matrix_mul_vector(A,icamera,pA); 
        matrix_mul_vector(B,icamera,pB); 
        // sort points so A.z<B.z 
        if (A[2]>B[2]) for (i=0;i<3;i++) { D[i]=A[i]; A[i]=B[i]; B[i]=D[i]; } 
        // D = B-A 
        for (i=0;i<3;i++) D[i]=B[i]-A[i]; 
        // ignore out of Z view lines 
        if (A[2]>zfar) return; 
        if (B[2]<znear) return; 
        // cut line to view if needed 
        if (A[2]<znear) 
         { 
         t=(znear-A[2])/D[2]; 
         A[0]+=D[0]*t; 
         A[1]+=D[1]*t; 
         A[2]=znear; 
         } 
        if (B[2]>zfar) 
         { 
         t=(zfar-B[2])/D[2]; 
         B[0]+=D[0]*t; 
         B[1]+=D[1]*t; 
         B[2]=zfar; 
         } 
        // apply perspective 
        perspective(A); 
        perspective(B); 
        // render 
        can->MoveTo(A[0],A[1]); 
        can->LineTo(B[0],B[1]); 
        } 
    
  4. 私たちは、正方形のグリッドとして私たちの3Dラインを使用して地上と空のプレーンを可視化することができます。そこで、xの軸合わせ線を描画するforループを作成し、ある起点位置Oの周りにあるsizeのいくつかの正方形をカバーするyの軸合わせ線を作成します。これらの線は、グリッドセルのサイズと同じくらいの間隔であるstepでなければなりません。

    原点位置Oは、frustrun centerに近いはずです。それが一定であれば、面の端から外に出て、全体(半分)の画面が覆われないようにします。カメラ位置を使用して0.5*(zfar+znear)*camera_z_axisを追加することができます。動きの錯覚を維持するには、Ostepのサイズに合わせる必要があります。このためにfloorroundまたは整数型を利用できます。

    た平面コードは次のようになります。

    //--------------------------------------------------------------------------- 
    #include <vcl.h> // you can ignore these lines 
    #include <math.h> 
    #pragma hdrstop 
    #include "win_main.h" 
    //--------------------------------------------------------------------------- 
    #pragma package(smart_init) 
    #pragma resource "*.dfm" // up to here. 
    TMain *Main; // this is pointer to my VCL window (you do not need it) 
    //--- Here starts the important stuff: -------------------------------------- 
    // perspective 
    double znear= 100.0; // focal length for perspective 
    double zfar = 2100.0; // visibility 
    // view 
    double xs2=0.0;   // screen half resolution 
    double ys2=0.0; 
    // camera 
    double yaw=0.0;   // euler yaw angle [rad] 
    double camera[16];  // camera direct transform matrix 
    double icamera[16];  // camera inverse transform matrix 
    // keyboard bools 
    bool _forw=false,_back=false,_right=false,_left=false; 
    //--------------------------------------------------------------------------- 
    void matrix_inv(double *a,double *b) // a[16] = Inverse(b[16]) 
        { 
        double x,y,z; 
        // transpose of rotation matrix 
        a[ 0]=b[ 0]; 
        a[ 5]=b[ 5]; 
        a[10]=b[10]; 
        x=b[1]; a[1]=b[4]; a[4]=x; 
        x=b[2]; a[2]=b[8]; a[8]=x; 
        x=b[6]; a[6]=b[9]; a[9]=x; 
        // copy projection part 
        a[ 3]=b[ 3]; 
        a[ 7]=b[ 7]; 
        a[11]=b[11]; 
        a[15]=b[15]; 
        // convert origin: new_pos = - new_rotation_matrix * old_pos 
        x=(a[ 0]*b[12])+(a[ 4]*b[13])+(a[ 8]*b[14]); 
        y=(a[ 1]*b[12])+(a[ 5]*b[13])+(a[ 9]*b[14]); 
        z=(a[ 2]*b[12])+(a[ 6]*b[13])+(a[10]*b[14]); 
        a[12]=-x; 
        a[13]=-y; 
        a[14]=-z; 
        } 
    //--------------------------------------------------------------------------- 
    void matrix_mul_vector(double *c,double *a,double *b) // c[3] = a[16]*b[3] 
        { 
        double q[3]; 
        q[0]=(a[ 0]*b[0])+(a[ 4]*b[1])+(a[ 8]*b[2])+(a[12]); 
        q[1]=(a[ 1]*b[0])+(a[ 5]*b[1])+(a[ 9]*b[2])+(a[13]); 
        q[2]=(a[ 2]*b[0])+(a[ 6]*b[1])+(a[10]*b[2])+(a[14]); 
        for(int i=0;i<3;i++) c[i]=q[i]; 
        } 
    //--------------------------------------------------------------------------- 
    void compute_matrices() // recompute camera,icamera after camera position or yaw change 
        { 
        // bound angle 
        while (yaw>2.0*M_PI) yaw-=2.0*M_PI; 
        while (yaw<0.0 ) yaw+=2.0*M_PI; 
        // X = right 
        camera[ 0]= cos(yaw); 
        camera[ 1]=  0.0 ; 
        camera[ 2]= sin(yaw); 
        // Y = up 
        camera[ 4]=  0.0 ; 
        camera[ 5]=  1.0 ; 
        camera[ 6]=  0.0 ; 
        // Z = forward 
        camera[ 8]=-sin(yaw); 
        camera[ 9]=  0.0 ; 
        camera[10]= cos(yaw); 
        // no projection 
        camera[ 3]=  0.0 ; 
        camera[ 7]=  0.0 ; 
        camera[11]=  0.0 ; 
        camera[15]=  1.0 ; 
        // compute the inverse matrix 
        matrix_inv(icamera,camera); 
        } 
    //--------------------------------------------------------------------------- 
    void perspective(double *P) // apply perspective transform 
        { 
        // perspectve division 
        P[0]*=znear/P[2]; 
        P[1]*=znear/P[2]; 
        // screen coordinate system 
        P[0]=xs2+P[0];   // move (0,0) to screen center 
        P[1]=ys2-P[1];   // axises: x=right, y=up 
        } 
    //--------------------------------------------------------------------------- 
    void draw_line(TCanvas *can,double *pA,double *pB) // draw 3D line 
        { 
        int i; 
        double D[3],A[3],B[3],t; 
        // transform to camera coordinate system 
        matrix_mul_vector(A,icamera,pA); 
        matrix_mul_vector(B,icamera,pB); 
        // sort points so A.z<B.z 
        if (A[2]>B[2]) for (i=0;i<3;i++) { D[i]=A[i]; A[i]=B[i]; B[i]=D[i]; } 
        // D = B-A 
        for (i=0;i<3;i++) D[i]=B[i]-A[i]; 
        // ignore out of Z view lines 
        if (A[2]>zfar) return; 
        if (B[2]<znear) return; 
        // cut line to view if needed 
        if (A[2]<znear) 
         { 
         t=(znear-A[2])/D[2]; 
         A[0]+=D[0]*t; 
         A[1]+=D[1]*t; 
         A[2]=znear; 
         } 
        if (B[2]>zfar) 
         { 
         t=(zfar-B[2])/D[2]; 
         B[0]+=D[0]*t; 
         B[1]+=D[1]*t; 
         B[2]=zfar; 
         } 
        // apply perspective 
        perspective(A); 
        perspective(B); 
        // render 
        can->MoveTo(A[0],A[1]); 
        can->LineTo(B[0],B[1]); 
        } 
    //--------------------------------------------------------------------------- 
    void draw_plane_xz(TCanvas *can,double y,double step) // draw 3D plane 
        { 
        int i; 
        double A[3],B[3],t,size; 
        double U[3]={1.0,0.0,0.0}; // U = X 
        double V[3]={0.0,0.0,1.0}; // V = Z 
        double O[3]={0.0,0.0,0.0}; // Origin 
        // compute origin near view center but align to step 
        i=0; O[i]=floor(camera[12+i]/step)*step; 
        i=2; O[i]=floor(camera[12+i]/step)*step; 
        O[1]=y; 
        // set size so plane safely covers whole view 
        t=xs2*zfar/znear;    size=t; // x that will convert to xs2 at zfar 
        t=0.5*(zfar+znear); if (size<t) size=t; // half of depth range 
        t+=step;        // + one grid cell beacuse O is off up to 1 grid cell 
        t*=sqrt(2);        // diagonal so no matter how are we rotate in Yaw 
        // U lines 
        for (i=0;i<3;i++) 
         { 
         A[i]=O[i]+(size*U[i])-((step+size)*V[i]); 
         B[i]=O[i]-(size*U[i])-((step+size)*V[i]); 
         } 
        for (t=-size;t<=size;t+=step) 
         { 
         for (i=0;i<3;i++) 
          { 
          A[i]+=step*V[i]; 
          B[i]+=step*V[i]; 
          } 
         draw_line(can,A,B); 
         } 
        // V lines 
        for (i=0;i<3;i++) 
         { 
         A[i]=O[i]-((step+size)*U[i])+(size*V[i]); 
         B[i]=O[i]-((step+size)*U[i])-(size*V[i]); 
         } 
        for (t=-size;t<=size;t+=step) 
         { 
         for (i=0;i<3;i++) 
          { 
          A[i]+=step*U[i]; 
          B[i]+=step*U[i]; 
          } 
         draw_line(can,A,B); 
         } 
        matrix_mul_vector(A,icamera,A); 
        } 
    //--------------------------------------------------------------------------- 
    void TMain::draw() // this is my main rendering routine 
        { 
        // clear buffer 
        bmp->Canvas->Brush->Color=clWhite; 
        bmp->Canvas->FillRect(TRect(0,0,xs,ys)); 
        // init/update variables 
        double step= 50.0;        // plane grid size 
        ::xs2=Main->xs2;        // update actual screen half resolution 
        ::ys2=Main->ys2; 
        // sky 
        bmp->Canvas->Pen->Color=clBlue; 
        draw_plane_xz(bmp->Canvas,+200.0,step); 
        // terrain 
        bmp->Canvas->Pen->Color=clGreen; 
        draw_plane_xz(bmp->Canvas,-200.0,step); 
        // render backbuffer 
        Main->Canvas->Draw(0,0,bmp); 
        _redraw=false; 
        } 
    //--------------------------------------------------------------------------- 
    __fastcall TMain::TMain(TComponent* Owner) : TForm(Owner) // this is initialization 
        { 
        bmp=new Graphics::TBitmap; 
        bmp->HandleType=bmDIB; 
        bmp->PixelFormat=pf32bit; 
        pyx=NULL; 
        _redraw=true; 
    
    
        // camera start position 
        camera[12]=0.0; 
        camera[13]=0.0; 
        camera[14]=0.0; 
        compute_matrices(); 
        } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMain::FormDestroy(TObject *Sender) // this is exit 
        { 
        if (pyx) delete[] pyx; 
        delete bmp; 
        } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMain::FormResize(TObject *Sender) // this is called on resize 
        { 
        xs=ClientWidth; xs2=xs>>1; 
        ys=ClientHeight; ys2=ys>>1; 
        bmp->Width=xs; 
        bmp->Height=ys; 
        if (pyx) delete[] pyx; 
        pyx=new int*[ys]; 
        for (int y=0;y<ys;y++) pyx[y]=(int*) bmp->ScanLine[y]; 
        _redraw=true; 
        } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMain::FormPaint(TObject *Sender) // this is called on forced repaint 
        { 
        _redraw=true; 
        } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMain::tim_redrawTimer(TObject *Sender) // this is called periodically by my timer 
        { 
        double da=5.0*M_PI/180.0; // turn speed 
        double dl=15.0;    // movement speed 
        bool _recompute=false; 
        if (_left) { _redraw=true; _recompute=true; yaw+=da; } 
        if (_right) { _redraw=true; _recompute=true; yaw-=da; } 
        if (_forw) { _redraw=true; _recompute=true; for (int i=0;i<3;i++) camera[12+i]+=dl*camera[8+i]; } 
        if (_back) { _redraw=true; _recompute=true; for (int i=0;i<3;i++) camera[12+i]-=dl*camera[8+i]; } 
        if (_recompute) compute_matrices(); 
        if (_redraw) draw(); 
        } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMain::FormKeyDown(TObject *Sender, WORD &Key,TShiftState Shift) // this is called when key is pushed 
        { 
        //Caption=Key; 
        if (Key==104) _left=true; 
        if (Key==105) _right=true; 
        if (Key==100) _forw=true; 
        if (Key== 97) _back=true; 
        } 
    //--------------------------------------------------------------------------- 
    void __fastcall TMain::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift) // this is called when key is released 
        { 
        if (Key==104) _left=false; 
        if (Key==105) _right=false; 
        if (Key==100) _forw=false; 
        if (Key== 97) _back=false; 
        } 
    //--------------------------------------------------------------------------- 
    

    :私は小さなVCL/GDI /キャンバスアプリケーションで一緒にこのすべてを置けば今

    void draw_plane_xz(TCanvas *can,double y,double step) // draw 3D plane 
        { 
        int i; 
        double A[3],B[3],t,size; 
        double U[3]={1.0,0.0,0.0}; // U = X 
        double V[3]={0.0,0.0,1.0}; // V = Z 
        double O[3]={0.0,0.0,0.0}; // Origin 
        // compute origin near view center but align to step 
        i=0; O[i]=floor(camera[12+i]/step)*step; 
        i=2; O[i]=floor(camera[12+i]/step)*step; 
        O[1]=y; 
        // set size so plane safely covers whole view 
        t=xs2*zfar/znear;    size=t; // x that will convert to xs2 at zfar 
        t=0.5*(zfar+znear); if (size<t) size=t; // half of depth range 
        t+=step;        // + one grid cell beacuse O is off up to 1 grid cell 
        t*=sqrt(2);        // diagonal so no matter how are we rotate in Yaw 
        // U lines 
        for (i=0;i<3;i++) 
         { 
         A[i]=O[i]+(size*U[i])-((step+size)*V[i]); 
         B[i]=O[i]-(size*U[i])-((step+size)*V[i]); 
         } 
        for (t=-size;t<=size;t+=step) 
         { 
         for (i=0;i<3;i++) 
          { 
          A[i]+=step*V[i]; 
          B[i]+=step*V[i]; 
          } 
         draw_line(can,A,B); 
         } 
        // V lines 
        for (i=0;i<3;i++) 
         { 
         A[i]=O[i]-((step+size)*U[i])+(size*V[i]); 
         B[i]=O[i]-((step+size)*U[i])-(size*V[i]); 
         } 
        for (t=-size;t<=size;t+=step) 
         { 
         for (i=0;i<3;i++) 
          { 
          A[i]+=step*U[i]; 
          B[i]+=step*U[i]; 
          } 
         draw_line(can,A,B); 
         } 
        matrix_mul_vector(A,icamera,A); 
        } 
    

私はこれを得ましたFormヘッダーファイル(VCLアプリケーションを再構築しない限り実際には必要ありません)

VCLアプリ3210は、その上に単一のタイマー(100ms)なしその他VCLコンポーネントを1つだけフォームです。 bmpはちょうど私のバックバッファービットマップです。ちらつきを避けるためです。キーボードイベントは、回転と移動を可能にするだけです(数字は8,9,4,1)。上記のコードのここ

プレビュー:今、あなたはまたは体積霧によって行われる白とび視界リミッターを追加したい場合は

preview

。あなたは、単にパラメータtに基づいて描画されるカラーとホワイトの間を補間:

t = (z-znear)/(zfar-znear); // t = <0,1> 
zはピクセルであるので、カメラ空間の座標

color = color*(1.0-t) + White*t; 

をしかし、ここでこれを適用するために、我々はをエンコードする必要があります2Dラインラスタライザまたは2D頂点カラー(OpenGLなど)のラインAPIを使用してください。もう1つの選択肢は、中心線の近くで完全に固体であり、上下の端で完全に透明なフォグ画像をブレンドすることによってそれを偽造することです。

+0

良い!あなたは私をたくさん助けます。私はモード7で呼ばれる別の説明を見つけました。これは、SNESがいくつかのテクスチャをマッピングするthperspectiveビューを作成するのと同じ方法です。ここに私の答えを記します。 –

+1

@ViníciusBiavattiラスタ技法(テクスチャピクセルマッピング)は、通常[Wolfensteinレイキャスティング技術](https://stackoverflow.com/a/32733650/2521214)に基づいています...壁と床/天井の両方 – Spektre

1

古いゲームでパースビューを作成するために使用された方法が見つかりました。チュートリアルはhttp://programandocoisas.blogspot.com.br/2017/09/mode-7.htmlで確認してください。 メソッド名はMODE 7です。私はそれを実装し理解するためのチュートリアルを作成しました。テクスチャ上でモード7を作成する式は次のとおりです。

_X = X/Z 
_Y = Y/Z 

Z深度を作成するために使用することができます。この変数は、Y座標のインクリメント変数です。 _Xと_Yの新しい座標を取得したら、これらの座標を使ってマップされるテクスチャのピクセルを取得し、このピクセルをレンダリングビューのX座標に挿入します。ここ

は擬似コードである: 基本的に、擬似コードがある:ここ

//This is the pseudo-code to generate the basic mode7 

for each y in the view do 
    y' <- y/z 
    for each x in the view do 
     x' <- x/z 
     put x',y' texture pixel value in x,y view pixel 
    end for 
    z <- z + 1 
end for 

コードである:

package mode7; 

import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 

/** 
* Mode 7 - Basic Implementation 
* This code will map a texture to create a pseudo-3d perspective. 
* This is an infinite render mode. The texture will be repeated without bounds. 
* @author VINICIUS 
*/ 
public class BasicModeSeven { 

    //Sizes 
    public static final int WIDTH = 800; 
    public static final int WIDTH_CENTER = WIDTH/2; 
    public static final int HEIGHT = 600; 
    public static final int HEIGHT_CENTER = HEIGHT/2; 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) throws IOException { 

     //Create Frame 
     JFrame frame = new JFrame("Mode 7"); 
     frame.setSize(WIDTH, HEIGHT); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 

     //Create Buffered Images: 
     //image - This is the image that will be printed in the render view 
     //texture - This is the image that will be mapped to the render view 
     BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); 
     BufferedImage texture = ImageIO.read(new File("src/mode7/texture.png")); 

     //The new coords that will be used to get the pixel on the texture 
     double _x, _y; 

     //z - the incrementable variable that beggins at -300 and go to 300, because 
     //the depth will be in the center of the HEIGHT 
     double z = HEIGHT_CENTER * -1; 

     //Scales just to control de scale of the printed pixel. It is not necessary 
     double scaleX = 16.0; 
     double scaleY = 16.0; 

     //Mode 7 - loop (Left Top to Down) 
     for(int y = 0; y < HEIGHT; y++){ 

      _y = y/z; //The new _y coord generated 
      if(_y < 0)_y *= -1; //Control the _y because the z starting with a negative number 
      _y *= scaleY; //Increase the size using scale 
      _y %= texture.getHeight(); //Repeat the pixel avoiding get texture out of bounds 

      for(int x = 0; x < WIDTH; x++){ 

       _x = (WIDTH_CENTER - x)/z; //The new _x coord generated 
       if(_x < 0)_x *= -1; //Control the _x to dont be negative 
       _x *= scaleX; //Increase the size using scale 
       _x %= texture.getWidth(); //Repeat the pixel avoiding get texture out of bounds 

       //Set x,y of the view image with the _x,_y pixel in the texture 
       image.setRGB(x, y, texture.getRGB((int)_x, (int)_y)); 
      } 

      //Increment depth 
      z++; 
     } 

     //Loop to render the generated image 
     while(true){ 
      frame.getGraphics().drawImage(image, 0, 0, null); 
     } 
    } 
} 

これは結果である:

enter image description here

関連する問題