3Dの描画

みんなが作った便利な関数やサンプルを共有するコミュニティです。
[url]http://www.activebasic.com/forum/viewforum.php?f=2]ActiveBasicの「実践コードモジュール」[/url]的な感じでやりましょう。
フォーラム(掲示板)ルール
・投稿するコードはできるだけ一つ、もしくは一つの関数を補助する複数の関数の形式にするか、
それだけをコンパイルして動くソースコード一式の形にしてください。
記事には説明だけを書き、コードは添付ファイルにしてもかまいません。
・使い方などの説明も書いてください。
環境に依存するコードの場合は、対象の環境も書いてください。
・使用条件(ライセンスなど)も書いていただけるとありがたいです。
・C言語、もしくはC++推奨ですが、他の言語でもかまいません。
・コードは正しくcodeタグで囲みましょう。
・一つのスレッドで一つのサンプルが基本です。
関連するサンプルの場合はまとめてもかまいません。
・投稿したサンプルを修正する場合には、スレッドの返信の形で投稿してください。
(新しいスレッドにしないでください。記事の編集でもかまいません)
返信
アバター
みけCAT
記事: 6067
登録日時: 8年前
住所: 千葉県
連絡を取る:

3Dの描画

#1

投稿記事 by みけCAT » 8年前

softya(ソフト屋)さんに
http://dixq.net/forum/viewtopic.php?f=3&t=7611で作っていただいた
3Dの座標を2Dに変換するプログラムです。
描画はWin32 APIなので、DXライブラリなどを使う際は描画関数(draw3dlineとdraw3dtext)を書きなおしてください。
3d.h

コード:

#include <windows.h>

#if 0
#define ENABLE_INFO
#endif

/*
x,y,z:座標
cx:縦の首振り(正=上)
cy:横の首振り(正=右) 
cz:回転(正=反時計回り) 
genkai:視野(ピクセル)
genkaiangle:視野(角度) 
centerx,centery:中心の座標(二次元) 
*/
typedef struct {
	double x,y,z;
	double cx,cy,cz;
	double genkai,genkaiangle;
	double centerx,centery;
} camera_t;

extern int henkan3dzahyou(double* ox,double* oy,
	double x,double y,double z,const camera_t* camera);
#ifdef ENABLE_INFO
extern int draw3dline(HDC hdc,double sx,double sy,double sz,
	double dx,double dy,double dz,const camera_t* camera,char *info);
#else
extern int draw3dline(HDC hdc,double sx,double sy,double sz,
	double dx,double dy,double dz,const camera_t* camera);
#endif
extern int draw3dtext(HDC hdc,double x,double y,double z,
	const char* text,const camera_t* camera);

#define dec2rad(a) ((a)*3.141592653589/180.0)
3d.c

コード:

#include <math.h>
#include "3d.h"
 
//  マトリクスの設定
static void setMatrix( double matrix[][4],
                double mat00,   double mat01,   double mat02,   double mat03,
                double mat10,   double mat11,   double mat12,   double mat13,
                double mat20,   double mat21,   double mat22,   double mat23,
                double mat30,   double mat31,   double mat32,   double mat33 )
{
    matrix[0][0]=mat00; matrix[0][1]=mat01; matrix[0][2]=mat02; matrix[0][3]=mat03;
    matrix[1][0]=mat10; matrix[1][1]=mat11; matrix[1][2]=mat12; matrix[1][3]=mat13;
    matrix[2][0]=mat20; matrix[2][1]=mat21; matrix[2][2]=mat22; matrix[2][3]=mat23;
    matrix[3][0]=mat30; matrix[3][1]=mat31; matrix[3][2]=mat32; matrix[3][3]=mat33;
}
 
//  マトリックス・ポイント計算
static void calcMatrixPoint( double matrix[][4],double out[],double in[])
{
    int  i,j;
    //  行列の演算。
    for( i=0 ; i<4; i++ ) {
        out[i] = 0;
        for( j=0 ; j<4; j++ ) {
            out[i] += in[j] * matrix[j][i];
        }
    }
}
 
//  コピーマトリックス
static void copyMatrix( double dstMat[][4],double srcMat[][4])
{
    int  i,j;
    //  コピー
    for( i=0 ; i<4; i++ ) {
        for( j=0 ; j<4; j++ ) {
            dstMat[i][j] = srcMat[i][j];
        }
    }
}
 
//  マトリックス計算
static void calcMatrix( double dstMat[][4],double srcMat[][4])
{
    int  i,j,k;
    double matrix[4][4];
    
    //  クリア
    for( i=0 ; i<4; i++ ) {
        for( j=0 ; j<4; j++ ) {
            matrix[i][j] = 0;
        }
    }
    //  行列の演算。
    for( i=0 ; i<4; i++ ) {
        for( j=0 ; j<4; j++ ) {
            for( k=0 ; k<4; k++ ) {
                matrix[i][j] += dstMat[i][k] * srcMat[k][j];
            }
        }
    }
    //  コピー
    copyMatrix(dstMat,matrix);
}
 
int henkan3dzahyou(double* ox,double* oy,
        double x,double y,double z,const camera_t* camera)
{
    double Mmatrix[4][4];//移動変換行列
    double Pmatrix[4][4];//射影変換行列
    double point3D[4];  //変換前座標
    double Mpoint3D[4]; //移動変換後座標
    double Ppoint3D[4]; //射影変換後座標
    int i,j;
    
    //  3D座標値を設定する。
    point3D[0] = x;
    point3D[1] = y;
    point3D[2] = z;
    point3D[3] = 1;
    
    //  カメラビュー変換。
    {
        double RXmatrix[4][4];//X回転行列
        double RYmatrix[4][4];//Y回転行列
        double RZmatrix[4][4];//Z回転行列
        double MVmatrix[4][4];//平行移動行列
        double rot;
        
        //  単位マトリックスを設定
        setMatrix( Mmatrix,
                    1,          0,          0,          0,
                    0,          1,          0,          0,
                    0,          0,          1,          0,
                    0,          0,          0,          1   );
        //  X回転マトリックス
        rot = -camera->cx;
        setMatrix( RXmatrix,
                    1,          0,          0,          0,
                    0,          cos(rot),   sin(rot),   0,
                    0,          -sin(rot),  cos(rot),   0,
                    0,          0,          0,          1   );
        //  Y回転マトリックス
        rot = -camera->cy;
        setMatrix( RYmatrix,
                    cos(rot),   0,          -sin(rot),  0,
                    0,          1,          0,          0,
                    sin(rot),   0,          cos(rot),   0,
                    0,          0,          0,          1   );
        
        //  Z回転マトリックス
        rot = -camera->cz;
        setMatrix( RZmatrix,
                    cos(rot),   sin(rot),   0,          0,
                    -sin(rot),  cos(rot),   0,          0,
                    0,          0,          1,          0,
                    0,          0,          0,          1   );
        
        //  平行移動マトリックス
        setMatrix( MVmatrix,
                    1,          0,          0,          0,
                    0,          1,          0,          0,
                    0,          0,          1,          0,
                    -camera->x, -camera->y, -camera->z, 1 );
        //  マトリックスの合成
        calcMatrix(Mmatrix,MVmatrix);
        calcMatrix(Mmatrix,RXmatrix);
        calcMatrix(Mmatrix,RYmatrix);
        calcMatrix(Mmatrix,RZmatrix);
    }
    //  行列の演算。
    calcMatrixPoint(Mmatrix,Mpoint3D,point3D);
    
    //  射影変換行列を設定する。
    {
        double depth,ctan;
        double cnear,cfar,width,height;
        
        cnear = 0.1;
        cfar = 1000.0;
        ctan = tan(camera->genkaiangle*0.5);
        width = 1.0 / ctan;
        height = 1.0 / ctan;
        depth = cfar / (cfar - cnear);
        setMatrix( Pmatrix,
                        width,  0,    0,              0,
                        0,    height, 0,              0,
                        0,    0,      depth,          1,
                        0,    0,      -depth * cnear, 0 );
    }
    //  行列の演算。
    calcMatrixPoint(Pmatrix,Ppoint3D,Mpoint3D);
    
    //  投影できないかチェック
    if( Ppoint3D[2] < 0 ) {
        return 0;
    }
    
    //  スクリーン座標変換。アスペクトは1:1
    *ox = camera->centery * Ppoint3D[0] / Ppoint3D[2] + camera->centerx;
    *oy = camera->centery * Ppoint3D[1] / Ppoint3D[2] + camera->centery;
    
    return 1;
}
 
#ifdef ENABLE_INFO
int draw3dline(HDC hdc,double sx,double sy,double sz,
        double dx,double dy,double dz,const camera_t* camera,char *info) {
#else
int draw3dline(HDC hdc,double sx,double sy,double sz,
        double dx,double dy,double dz,const camera_t* camera) {
#endif
    double hx1,hy1,hx2,hy2;
    if(!henkan3dzahyou(&hx1,&hy1,sx,sy,sz,camera))return 0;
    if(!henkan3dzahyou(&hx2,&hy2,dx,dy,dz,camera))return 0;
    if(!MoveToEx(hdc,(int)hx1,(int)hy1,NULL))return 0;
    if(!LineTo(hdc,(int)hx2,(int)hy2))return 0;
#ifdef ENABLE_INFO
    if( info != NULL ) {
        wsprintf(info,"ライン座標(%d,%d)-(%d,%d)",(int)hx1,(int)hy1,(int)hx2,(int)hy2);
    }
#endif
    return 1;
}
 
int draw3dtext(HDC hdc,double x,double y,double z,
        const char* text,const camera_t* camera) {
    double hx,hy;
    if(!henkan3dzahyou(&hx,&hy,x,y,z,camera))return 0;
    if(!TextOut(hdc,(int)hx,(int)hy,text,lstrlen(text)))return 0;
    return 1;
}
サンプルを添付します。
サンプルの操作方法
矢印キー上下:y軸方向にカメラを移動
矢印キー左右:x軸方向にカメラを移動
Ctrl+矢印キー上下:z軸方向にカメラを移動
Shift+矢印キー上下:上下にカメラを回転
Shift+矢印キー左右:左右にカメラを回転
Ctrl+Shift+矢印キー上下:カメラをひねる
F1:カメラの座標をリセット
1~5:描画するものを切り替え(6~9、0を押すと何も描画されません、未実装なので)

訂正:czの回転は時計回りです。
添付ファイル
3dtest.zip
サンプルです。
(21.17 KiB) ダウンロード数: 163 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

返信

“サンプルを共有するコミュニティ” へ戻る