Re: DrawCone3Dについて ( No.1 ) |
- 名前:管理人 日時:2020/07/07 00:35
|
Re: DrawCone3Dについて ( No.2 ) |
- 名前:Alphas 日時:2020/07/09 16:29
管理人様
DrawPolygon3Dを使用して斜円錐の実現について質問なのですが、
この関数の説明ですと、3D空間に三角形ポリゴンの集合を描画するとあるのですが、
斜円錐を実現する場合、どのようにVertex等を指定すれば良いのか教授頂けますと助かります。
多量のVertexを作成して3角形を隣接するように隙間なく埋めて・・・という事ではないですよね?
|
Re: DrawCone3Dについて ( No.3 ) |
- 名前:管理人 日時:2020/07/10 00:18
> 多量のVertexを作成して3角形を隣接するように隙間なく埋めて・・・という事ではないですよね?
いえ、『多量のVertexを作成して3角形を隣接するように隙間なく埋めて』の通りです
あと、すみません、同じ頂点を複数のポリゴンで共有するので、DrawPolygon3D より DrawPolygonIndexed3D の方が適していました…
DrawPolygonIndexed3D を使って、DrawCone3D の FillFlag が TRUE の場合と同じ描画を行うプログラムを
組んでみましたので、よろしければ参考にしてください m(_ _)m
#include "DxLib.h"
#include <malloc.h>
#include <math.h>
// 3Dの円錐を描画する
extern int drawCone3D( VECTOR TopPos, VECTOR BottomPos, float r, int DivNum, unsigned int DifColor, unsigned int SpcColor )
{
VERTEX3D *Vertex, *vert1, *vert2, *vert3 ;
MATRIX Axis ;
WORD *Index, *ind ;
VECTOR SubV, xv, yv, zv ;
VECTOR bottomvec, norm ;
float Length ;
float *SinCosTable, *t ;
int CirVertNum, vertnum, indexnum ;
int dr, dg, db, sr, sg, sb, i, j, k, topind, bottomind, num ;
// 色の値をR,G,Bの要素に分解
GetColor2( DifColor, &dr, &dg, &db ) ;
GetColor2( SpcColor, &sr, &sg, &sb ) ;
// 円錐の底から円錐の先に向かうベクトルを算出
SubV = VSub( TopPos, BottomPos ) ;
// 円錐の底から円錐の先までの長さを算出
Length = VSize( SubV ) ;
// 円錐の底から円錐の先に向かうベクトルを長さで割って
// 円錐の底から円錐の先に向かう長さ1のベクトルを算出
zv = VScale( SubV, 1.0f / Length ) ;
// 外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトルを算出
// ( 外積には X軸方向の長さ1のベクトルを使用 )
xv = VGet( 1.0f, 0.0f, 0.0f ) ;
VectorOuterProduct( &yv, &xv, &zv ) ;
// 算出したベクトルに長さが無かった場合は Z軸方向の長さ1のベクトルで再度外積
if( VSquareSize( yv ) < 0.000000001f )
{
xv = VGet( 0.0f, 0.0f, 1.0f ) ;
VectorOuterProduct( &yv, &xv, &zv ) ;
}
// 『円錐の底から円錐の先に向かうベクトルに垂直なベクトル』と
// 『円錐の底から円錐の先に向かうベクトル』の外積を算出して、
// お互いが垂直な3つのベクトルを算出
xv = VNorm( VCross( yv, zv ) ) ;
yv = VNorm( yv ) ;
// お互いが垂直な3つのベクトルから
// 【任意の x, y, z の値を『お互いが垂直な3つのベクトル』を基本軸とする座標に変換する為の行列】を作成
Axis = MGetAxis1( xv, yv, zv, BottomPos ) ;
// 三角錐の側面の法線を算出
norm = VNorm( VCross( VGet( 0.0f, 0.0f, 1.0f ), VSub( VGet( r, 0.0f, 0.0f ), VGet( 0.0f, Length, 0.0f ) ) ) ) ;
// 円の頂点数を決定
CirVertNum = DivNum + 4 ;
// 円錐の頂点数を算出
vertnum = CirVertNum * 3 ;
// 円錐の先部分の頂点群の先頭番号を設定
topind = CirVertNum ;
// 円錐の底部分の頂点群の先頭番号を設定
bottomind = CirVertNum * 2 ;
// 頂点インデックスの数を算出
indexnum = CirVertNum * 3 + ( CirVertNum - 2 ) * 3 ;
// 頂点データとSin,Cosテーブルとインデックスデータを格納するメモリ領域の確保
Vertex = ( VERTEX3D * )malloc( sizeof( WORD ) * indexnum + sizeof( VERTEX3D ) * vertnum + sizeof( float ) * CirVertNum * 2 ) ;
if( Vertex == NULL )
{
// メモリの確保に失敗したらエラー終了
return -1 ;
}
// Sin,Cosテーブルを格納するメモリ領域の先頭アドレスをセット
SinCosTable = ( float * )( Vertex + vertnum ) ;
// インデックスデータを格納するメモリ領域の先頭アドレスをセット
Index = ( WORD * )( SinCosTable + CirVertNum * 2 ) ;
// DivNum の値に沿った粒度の Sin,Cosテーブルを作成
t = SinCosTable ;
for( i = 0 ; i < CirVertNum ; i ++, t += 2 )
{
t[ 0 ] = sinf( 2 * DX_PI_F / CirVertNum * i ) ;
t[ 1 ] = cosf( 2 * DX_PI_F / CirVertNum * i ) ;
}
// 頂点データを作成
vert1 = Vertex ; // 円の周囲の頂点データの先頭アドレスをセット
vert2 = Vertex + CirVertNum ; // 円錐の先の頂点データの先頭アドレスをセット
vert3 = Vertex + CirVertNum * 2 ; // 円錐の周囲の底面ようの頂点データの先頭アドレスをセット
t = SinCosTable ; // Sin,Cosテーブルの先頭アドレスをセット
bottomvec = VTransformSR( VGet( 0.0f, 0.0f, -1.0f ), Axis ) ; // 円錐の底方向のベクトルを算出
for( i = 0 ; i < CirVertNum ; i ++, vert1 ++, vert2 ++, vert3 ++, t += 2 )
{
// vert1 は円の周囲の座標をセット
vert1->pos = VTransform( VGet( t[ 0 ] * r, t[ 1 ] * r, 0.0f ), Axis ) ;
// vert2 は円錐の先の座標をセット
vert2->pos = TopPos ;
// vert3 は vert1 と同じ座標
vert3->pos = vert1->pos ;
// vert1 は円の周囲の法線をセット
vert1->norm = VTransformSR( VGet( t[ 0 ] * norm.x, t[ 1 ] * norm.x, norm.y ), Axis ) ;
// vert2 には vert1 と同じ法線
vert2->norm = vert1->norm ;
// vert3 は円の底方向を法線としてセット
vert3->norm = bottomvec ;
// 頂点の色をセット
vert1->dif.b = ( BYTE )db ; vert1->dif.g = ( BYTE )dg ; vert1->dif.r = ( BYTE )dr ; vert1->dif.a = 255 ;
vert2->dif.b = ( BYTE )db ; vert2->dif.g = ( BYTE )dg ; vert2->dif.r = ( BYTE )dr ; vert2->dif.a = 255 ;
vert3->dif.b = ( BYTE )db ; vert3->dif.g = ( BYTE )dg ; vert3->dif.r = ( BYTE )dr ; vert3->dif.a = 255 ;
vert1->spc.b = ( BYTE )sb ; vert1->spc.g = ( BYTE )sg ; vert1->spc.r = ( BYTE )sr ; vert1->spc.a = 0 ;
vert2->spc.b = ( BYTE )sb ; vert2->spc.g = ( BYTE )sg ; vert2->spc.r = ( BYTE )sr ; vert2->spc.a = 0 ;
vert3->spc.b = ( BYTE )sb ; vert3->spc.g = ( BYTE )sg ; vert3->spc.r = ( BYTE )sr ; vert3->spc.a = 0 ;
// 頂点のテクスチャ座標をセット( テクスチャは貼らないので全部 0.0f )
vert1->u = 0.0f ; vert1->v = 0.0f ;
vert2->u = 0.0f ; vert2->v = 0.0f ;
vert3->u = 0.0f ; vert3->v = 0.0f ;
vert1->su = 0.0f ; vert1->sv = 0.0f ;
vert2->su = 0.0f ; vert2->sv = 0.0f ;
vert3->su = 0.0f ; vert3->sv = 0.0f ;
}
// 頂点インデックスを準備
// 円錐の側面のポリゴンの頂点インデックスをセット
{
ind = Index ;
for( i = 0 ; i < CirVertNum - 1 ; i ++, ind += 3 )
{
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( topind + i ) ;
ind[ 2 ] = ( WORD )( i + 1 ) ;
}
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( topind + i ) ;
ind[ 2 ] = 0 ;
ind += 3 ;
}
// 円錐の底面のポリゴンの頂点インデックスをセット
{
j = bottomind + CirVertNum - 1 ;
i = bottomind ;
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )j ;
ind += 3 ;
num = CirVertNum - 2 ;
for( k = 1 ; k < num ; )
{
ind[ 0 ] = ( WORD )j ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )( i + 2 ) ;
ind += 3 ;
k ++ ;
i ++ ;
if( k >= num ) break ;
ind[ 0 ] = ( WORD )j ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )( j - 1 ) ;
ind += 3 ;
j -- ;
k ++ ;
if( k >= num ) break ;
}
}
// ポリゴンを描画
DrawPolygonIndexed3D( Vertex, vertnum, Index, indexnum / 3, DX_NONE_GRAPH, TRUE ) ;
// メモリの解放
free( Vertex ) ;
// 終了
return 0 ;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// 背景を灰色に設定
SetBackgroundColor( 64, 64, 64 ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK ) ;
// Zバッファを有効にする
SetUseZBufferFlag( TRUE ) ;
// Zバッファへの書き込みを有効にする
SetWriteZBufferFlag( TRUE ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面のクリア
ClearDrawScreen() ;
// 円錐を描画
drawCone3D( VGet( 320.0f, 400.0f, 0.0f ), VGet( 320.0f, 150.0f, 0.0f ), 150.0f, 32, GetColor( 255,255,0 ), GetColor( 0, 0, 0 ) );
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
|
Re: DrawCone3Dについて ( No.4 ) |
- 名前:Alphas 日時:2020/07/10 16:10
管理人 様
迅速かつ丁重に実装パターンまでご教授頂き有難う御座います。
DrawPolygonIndexed3Dを用いた斜円錐を来週前半に動作させてみたいと思います。
ただ、一点質問ですが、このDrawPolygonIndexed3Dを用いて上記のように直円錐を描画させる場合とDrawCone3Dで描画した場合、
どちらも同じ程度の速度で描画可能でしょうか??
DrawCone3DよりDrawPolygonIndexed3Dの方が結構遅いなどありませんでしょうか?
以上、宜しくお願い致します。
|
Re: DrawCone3Dについて ( No.5 ) |
- 名前:管理人 日時:2020/07/11 07:19
> ただ、一点質問ですが、このDrawPolygonIndexed3Dを用いて上記のように直円錐を描画させる場合とDrawCone3Dで描画した場合、
> どちらも同じ程度の速度で描画可能でしょうか??
DrawCone3D は内部で DrawPolygonIndexed3D を使用していますので、動作速度は同じです
( 厳密には少しだけ引数の異なる DrawPrimitiveIndexed3D という関数を使用していますが… )
> DrawCone3DよりDrawPolygonIndexed3Dの方が結構遅いなどありませんでしょうか?
はい、ありません
しかも、例えば DivNum を引数から外して以下のように #define DIVNUM (32) など固定値にすれば頂点数も固定になり
関数内で低速なメモリ確保( malloc, free )を使用する必要が無くなるので、サンプルプログラムの方が高速になります
#include "DxLib.h"
#include <math.h>
#define DIVNUM (32)
#define CIR_VERT_NUM (DIVNUM + 4) // 円の頂点数
#define VERT_NUM (CIR_VERT_NUM * 3) // 円錐の頂点数
#define TOP_IND (CIR_VERT_NUM) // 円錐の先部分の頂点群の先頭番号
#define BOTTOM_IND (CIR_VERT_NUM * 2) // 円錐の底部分の頂点群の先頭番号
#define INDEX_NUM (CIR_VERT_NUM * 3 + ( CIR_VERT_NUM - 2 ) * 3) // 頂点インデックスの数
// 3Dの円錐を描画する
extern int drawCone3D( VECTOR TopPos, VECTOR BottomPos, float r, unsigned int DifColor, unsigned int SpcColor )
{
VERTEX3D Vertex[ VERT_NUM ], *vert1, *vert2, *vert3 ;
MATRIX Axis ;
WORD Index[ INDEX_NUM ], *ind ;
VECTOR SubV, xv, yv, zv ;
VECTOR bottomvec, norm ;
float Length ;
float SinCosTable[ CIR_VERT_NUM * 2 ], *t ;
int dr, dg, db, sr, sg, sb, i, j, k, num ;
// 色の値をR,G,Bの要素に分解
GetColor2( DifColor, &dr, &dg, &db ) ;
GetColor2( SpcColor, &sr, &sg, &sb ) ;
// 円錐の底から円錐の先に向かうベクトルを算出
SubV = VSub( TopPos, BottomPos ) ;
// 円錐の底から円錐の先までの長さを算出
Length = VSize( SubV ) ;
// 円錐の底から円錐の先に向かうベクトルを長さで割って
// 円錐の底から円錐の先に向かう長さ1のベクトルを算出
zv = VScale( SubV, 1.0f / Length ) ;
// 外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトルを算出
// ( 外積には X軸方向の長さ1のベクトルを使用 )
xv = VGet( 1.0f, 0.0f, 0.0f ) ;
VectorOuterProduct( &yv, &xv, &zv ) ;
// 算出したベクトルに長さが無かった場合は Z軸方向の長さ1のベクトルで再度外積
if( VSquareSize( yv ) < 0.000000001f )
{
xv = VGet( 0.0f, 0.0f, 1.0f ) ;
VectorOuterProduct( &yv, &xv, &zv ) ;
}
// 『外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトル』と
// 『円錐の底から円錐の先に向かうベクトル』の外積を算出して、
// お互いが垂直な3つのベクトルを算出
xv = VNorm( VCross( yv, zv ) ) ;
yv = VNorm( yv ) ;
// お互いが垂直な3つのベクトルから
// 【任意の x, y, z の値を『お互いが垂直な3つのベクトル』を基本軸とする座標に変換する為の行列】を作成
Axis = MGetAxis1( xv, yv, zv, BottomPos ) ;
// 三角錐の側面の法線を算出
norm = VNorm( VCross( VGet( 0.0f, 0.0f, 1.0f ), VSub( VGet( r, 0.0f, 0.0f ), VGet( 0.0f, Length, 0.0f ) ) ) ) ;
// DivNum の数に沿った粒度の Sin,Cosテーブルを作成
t = SinCosTable ;
for( i = 0 ; i < CIR_VERT_NUM ; i ++, t += 2 )
{
t[ 0 ] = sinf( 2 * DX_PI_F / CIR_VERT_NUM * i ) ;
t[ 1 ] = cosf( 2 * DX_PI_F / CIR_VERT_NUM * i ) ;
}
// 頂点データを作成
vert1 = Vertex ; // 円の周囲の頂点データの先頭アドレスをセット
vert2 = Vertex + CIR_VERT_NUM ; // 円錐の先の頂点データの先頭アドレスをセット
vert3 = Vertex + CIR_VERT_NUM * 2 ; // 円錐の周囲の底面ようの頂点データの先頭アドレスをセット
t = SinCosTable ; // Sin,Cosテーブルの先頭アドレスをセット
bottomvec = VTransformSR( VGet( 0.0f, 0.0f, -1.0f ), Axis ) ; // 円錐の底方向のベクトルを算出
for( i = 0 ; i < CIR_VERT_NUM ; i ++, vert1 ++, vert2 ++, vert3 ++, t += 2 )
{
// vert1 は円の周囲の座標をセット
vert1->pos = VTransform( VGet( t[ 0 ] * r, t[ 1 ] * r, 0.0f ), Axis ) ;
// vert2 は円錐の先の座標をセット
vert2->pos = TopPos ;
// vert3 は vert1 と同じ座標
vert3->pos = vert1->pos ;
// vert1 は円の周囲の法線をセット
vert1->norm = VTransformSR( VGet( t[ 0 ] * norm.x, t[ 1 ] * norm.x, norm.y ), Axis ) ;
// vert2 には vert1 と同じ法線
vert2->norm = vert1->norm ;
// vert3 は円の底方向を法線としてセット
vert3->norm = bottomvec ;
// 頂点の色をセット
vert1->dif.b = ( BYTE )db ; vert1->dif.g = ( BYTE )dg ; vert1->dif.r = ( BYTE )dr ; vert1->dif.a = 255 ;
vert2->dif.b = ( BYTE )db ; vert2->dif.g = ( BYTE )dg ; vert2->dif.r = ( BYTE )dr ; vert2->dif.a = 255 ;
vert3->dif.b = ( BYTE )db ; vert3->dif.g = ( BYTE )dg ; vert3->dif.r = ( BYTE )dr ; vert3->dif.a = 255 ;
vert1->spc.b = ( BYTE )sb ; vert1->spc.g = ( BYTE )sg ; vert1->spc.r = ( BYTE )sr ; vert1->spc.a = 0 ;
vert2->spc.b = ( BYTE )sb ; vert2->spc.g = ( BYTE )sg ; vert2->spc.r = ( BYTE )sr ; vert2->spc.a = 0 ;
vert3->spc.b = ( BYTE )sb ; vert3->spc.g = ( BYTE )sg ; vert3->spc.r = ( BYTE )sr ; vert3->spc.a = 0 ;
// 頂点のテクスチャ座標をセット( テクスチャは貼らないので全部 0.0f )
vert1->u = 0.0f ; vert1->v = 0.0f ;
vert2->u = 0.0f ; vert2->v = 0.0f ;
vert3->u = 0.0f ; vert3->v = 0.0f ;
vert1->su = 0.0f ; vert1->sv = 0.0f ;
vert2->su = 0.0f ; vert2->sv = 0.0f ;
vert3->su = 0.0f ; vert3->sv = 0.0f ;
}
// 頂点インデックスを準備
// 円錐の側面のポリゴンの頂点インデックスをセット
{
ind = Index ;
for( i = 0 ; i < CIR_VERT_NUM - 1 ; i ++, ind += 3 )
{
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( TOP_IND + i ) ;
ind[ 2 ] = ( WORD )( i + 1 ) ;
}
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( TOP_IND + i ) ;
ind[ 2 ] = 0 ;
ind += 3 ;
}
// 円錐の底面のポリゴンの頂点インデックスをセット
{
j = BOTTOM_IND + CIR_VERT_NUM - 1 ;
i = BOTTOM_IND ;
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )j ;
ind += 3 ;
num = CIR_VERT_NUM - 2 ;
for( k = 1 ; k < num ; )
{
ind[ 0 ] = ( WORD )j ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )( i + 2 ) ;
ind += 3 ;
k ++ ;
i ++ ;
if( k >= num ) break ;
ind[ 0 ] = ( WORD )j ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )( j - 1 ) ;
ind += 3 ;
j -- ;
k ++ ;
if( k >= num ) break ;
}
}
// ポリゴンを描画
DrawPolygonIndexed3D( Vertex, VERT_NUM, Index, INDEX_NUM / 3, DX_NONE_GRAPH, TRUE ) ;
// 終了
return 0 ;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// 背景を灰色に設定
SetBackgroundColor( 64, 64, 64 ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK ) ;
// Zバッファを有効にする
SetUseZBufferFlag( TRUE ) ;
// Zバッファへの書き込みを有効にする
SetWriteZBufferFlag( TRUE ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面のクリア
ClearDrawScreen() ;
// 円錐を描画
drawCone3D( VGet( 320.0f, 400.0f, 0.0f ), VGet( 320.0f, 150.0f, 0.0f ), 150.0f, GetColor( 255,255,0 ), GetColor( 0, 0, 0 ) );
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
更に、DrawPolygonIndexed3D 自体が重い処理なので、呼ぶ回数を減らせばそれだけで速くなるという面があります
なので、頂点数やインデックス数を円錐複数個分用意して、一度の DrawPolygonIndexed3D で複数の円錐を描画すれば
DrawCone3D で一つ一つ描画するより更に高速に描画できます
#include "DxLib.h"
#include <math.h>
#define MAX_CONE_NUM (256) // 一度に描画できる円錐の最大数
#define DIVNUM 32
#define CIR_VERT_NUM (DIVNUM + 4) // 円の頂点数
#define VERT_NUM (CIR_VERT_NUM * 3) // 円錐の頂点数
#define TOP_IND (CIR_VERT_NUM) // 円錐の先部分の頂点群の先頭番号
#define BOTTOM_IND (CIR_VERT_NUM * 2) // 円錐の底部分の頂点群の先頭番号
#define INDEX_NUM (CIR_VERT_NUM * 3 + ( CIR_VERT_NUM - 2 ) * 3) // 頂点インデックスの数
// 円錐の情報
struct CONE_INFO
{
VECTOR TopPos;
VECTOR BottomPos;
float r;
unsigned int DifColor;
unsigned int SpcColor;
};
// 3Dの円錐を複数描画する
VERTEX3D Vertex[ MAX_CONE_NUM ][ VERT_NUM ];
WORD Index[ MAX_CONE_NUM ][ INDEX_NUM ];
extern int drawCone3D( CONE_INFO *ConeInfo, int ConeNum )
{
int l, AddIndex ;
AddIndex = 0 ;
for( l = 0; l < ConeNum; l++, ConeInfo++, AddIndex += VERT_NUM )
{
VERTEX3D *vert1, *vert2, *vert3 ;
MATRIX Axis ;
WORD *ind ;
VECTOR SubV, xv, yv, zv ;
VECTOR bottomvec, norm ;
float Length ;
float SinCosTable[ CIR_VERT_NUM * 2 ], *t ;
int dr, dg, db, sr, sg, sb, i, j, k, num ;
// 色の値をR,G,Bの要素に分解
GetColor2( ConeInfo->DifColor, &dr, &dg, &db ) ;
GetColor2( ConeInfo->SpcColor, &sr, &sg, &sb ) ;
// 円錐の底から円錐の先に向かうベクトルを算出
SubV = VSub( ConeInfo->TopPos, ConeInfo->BottomPos ) ;
// 円錐の底から円錐の先までの長さを算出
Length = VSize( SubV ) ;
// 円錐の底から円錐の先に向かうベクトルを長さで割って
// 円錐の底から円錐の先に向かう長さ1のベクトルを算出
zv = VScale( SubV, 1.0f / Length ) ;
// 外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトルを算出
// ( 外積には X軸方向の長さ1のベクトルを使用 )
xv = VGet( 1.0f, 0.0f, 0.0f ) ;
VectorOuterProduct( &yv, &xv, &zv ) ;
// 算出したベクトルに長さが無かった場合は Z軸方向の長さ1のベクトルで再度外積
if( VSquareSize( yv ) < 0.000000001f )
{
xv = VGet( 0.0f, 0.0f, 1.0f ) ;
VectorOuterProduct( &yv, &xv, &zv ) ;
}
// 『外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトル』と
// 『円錐の底から円錐の先に向かうベクトル』の外積を算出して、
// お互いが垂直な3つのベクトルを算出
xv = VNorm( VCross( yv, zv ) ) ;
yv = VNorm( yv ) ;
// お互いが垂直な3つのベクトルから
// 【任意の x, y, z の値を『お互いが垂直な3つのベクトル』を基本軸とする座標に変換する為の行列】を作成
Axis = MGetAxis1( xv, yv, zv, ConeInfo->BottomPos ) ;
// 三角錐の側面の法線を算出
norm = VNorm( VCross( VGet( 0.0f, 0.0f, 1.0f ), VSub( VGet( ConeInfo->r, 0.0f, 0.0f ), VGet( 0.0f, Length, 0.0f ) ) ) ) ;
// DivNum の数に沿った粒度の Sin,Cosテーブルを作成
t = SinCosTable ;
for( i = 0 ; i < CIR_VERT_NUM ; i ++, t += 2 )
{
t[ 0 ] = sinf( 2 * DX_PI_F / CIR_VERT_NUM * i ) ;
t[ 1 ] = cosf( 2 * DX_PI_F / CIR_VERT_NUM * i ) ;
}
// 頂点データを作成
vert1 = Vertex[ l ] ; // 円の周囲の頂点データの先頭アドレスをセット
vert2 = Vertex[ l ] + CIR_VERT_NUM ; // 円錐の先の頂点データの先頭アドレスをセット
vert3 = Vertex[ l ] + CIR_VERT_NUM * 2 ; // 円錐の周囲の底面ようの頂点データの先頭アドレスをセット
t = SinCosTable ; // Sin,Cosテーブルの先頭アドレスをセット
bottomvec = VTransformSR( VGet( 0.0f, 0.0f, -1.0f ), Axis ) ; // 円錐の底方向のベクトルを算出
for( i = 0 ; i < CIR_VERT_NUM ; i ++, vert1 ++, vert2 ++, vert3 ++, t += 2 )
{
// vert1 は円の周囲の座標をセット
vert1->pos = VTransform( VGet( t[ 0 ] * ConeInfo->r, t[ 1 ] * ConeInfo->r, 0.0f ), Axis ) ;
// vert2 は円錐の先の座標をセット
vert2->pos = ConeInfo->TopPos ;
// vert3 は vert1 と同じ座標
vert3->pos = vert1->pos ;
// vert1 は円の周囲の法線をセット
vert1->norm = VTransformSR( VGet( t[ 0 ] * norm.x, t[ 1 ] * norm.x, norm.y ), Axis ) ;
// vert2 には vert1 と同じ法線
vert2->norm = vert1->norm ;
// vert3 は円の底方向を法線としてセット
vert3->norm = bottomvec ;
// 頂点の色をセット
vert1->dif.b = ( BYTE )db ; vert1->dif.g = ( BYTE )dg ; vert1->dif.r = ( BYTE )dr ; vert1->dif.a = 255 ;
vert2->dif.b = ( BYTE )db ; vert2->dif.g = ( BYTE )dg ; vert2->dif.r = ( BYTE )dr ; vert2->dif.a = 255 ;
vert3->dif.b = ( BYTE )db ; vert3->dif.g = ( BYTE )dg ; vert3->dif.r = ( BYTE )dr ; vert3->dif.a = 255 ;
vert1->spc.b = ( BYTE )sb ; vert1->spc.g = ( BYTE )sg ; vert1->spc.r = ( BYTE )sr ; vert1->spc.a = 0 ;
vert2->spc.b = ( BYTE )sb ; vert2->spc.g = ( BYTE )sg ; vert2->spc.r = ( BYTE )sr ; vert2->spc.a = 0 ;
vert3->spc.b = ( BYTE )sb ; vert3->spc.g = ( BYTE )sg ; vert3->spc.r = ( BYTE )sr ; vert3->spc.a = 0 ;
// 頂点のテクスチャ座標をセット( テクスチャは貼らないので全部 0.0f )
vert1->u = 0.0f ; vert1->v = 0.0f ;
vert2->u = 0.0f ; vert2->v = 0.0f ;
vert3->u = 0.0f ; vert3->v = 0.0f ;
vert1->su = 0.0f ; vert1->sv = 0.0f ;
vert2->su = 0.0f ; vert2->sv = 0.0f ;
vert3->su = 0.0f ; vert3->sv = 0.0f ;
}
// 頂点インデックスを準備
// 円錐の側面のポリゴンの頂点インデックスをセット
{
ind = Index[ l ] ;
for( i = 0 ; i < CIR_VERT_NUM - 1 ; i ++, ind += 3 )
{
ind[ 0 ] = ( WORD )( i + AddIndex );
ind[ 1 ] = ( WORD )( TOP_IND + i + AddIndex ) ;
ind[ 2 ] = ( WORD )( i + 1 + AddIndex ) ;
}
ind[ 0 ] = ( WORD )( i + AddIndex );
ind[ 1 ] = ( WORD )( TOP_IND + i + AddIndex ) ;
ind[ 2 ] = ( WORD )AddIndex ;
ind += 3 ;
}
// 円錐の底面のポリゴンの頂点インデックスをセット
{
j = BOTTOM_IND + CIR_VERT_NUM - 1 + AddIndex ;
i = BOTTOM_IND + AddIndex ;
ind[ 0 ] = ( WORD )i ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )j ;
ind += 3 ;
num = CIR_VERT_NUM - 2 ;
for( k = 1 ; k < num ; )
{
ind[ 0 ] = ( WORD )j ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )( i + 2 ) ;
ind += 3 ;
k ++ ;
i ++ ;
if( k >= num ) break ;
ind[ 0 ] = ( WORD )j ;
ind[ 1 ] = ( WORD )( i + 1 ) ;
ind[ 2 ] = ( WORD )( j - 1 ) ;
ind += 3 ;
j -- ;
k ++ ;
if( k >= num ) break ;
}
}
}
// ポリゴンを描画
DrawPolygonIndexed3D( Vertex[ 0 ], VERT_NUM * ConeNum, Index[ 0 ], INDEX_NUM / 3 * ConeNum, DX_NONE_GRAPH, TRUE ) ;
// 終了
return 0 ;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
CONE_INFO ConeInfo[ 16 ] ;
int i ;
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// 背景を灰色に設定
SetBackgroundColor( 64, 64, 64 ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK ) ;
// Zバッファを有効にする
SetUseZBufferFlag( TRUE ) ;
// Zバッファへの書き込みを有効にする
SetWriteZBufferFlag( TRUE ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面のクリア
ClearDrawScreen() ;
// 16個の円錐を描画
for( i = 0 ; i < 16 ; i ++ )
{
ConeInfo[ i ].TopPos = VGet( 50.0f + i * 36.0f, 400.0f, 0.0f ) ;
ConeInfo[ i ].BottomPos = VGet( 50.0f + i * 36.0f, 150.0f, 0.0f ) ;
ConeInfo[ i ].r = 15.0f ;
ConeInfo[ i ].DifColor = GetColor( 255, 255, 0 ) ;
ConeInfo[ i ].SpcColor = GetColor( 0, 0, 0 ) ;
}
drawCone3D( ConeInfo, 16 );
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
|
Re: DrawCone3Dについて ( No.6 ) |
- 名前:Alphas 日時:2020/07/13 10:30
管理人様
迅速かつ丁寧に実装サンプルコードを乗せていただき頂き有難うございます。
上記コードからC#に載せ替えて、斜円錐動作を試してみたいと思います。
|
Re: DrawCone3Dについて ( No.7 ) |
- 名前:Alphas 日時:2020/07/13 14:37
管理人様
上記をC#へ載せ替えて試してみました。
CONE_INFOのTopPosとBottomPosについてご質問です。
TopPosとは、(直/斜)円錐の頂点
BottomPosとは、(直/斜)円錐の底面(円)の中心点であっておりますでしょうか?
何故か、下記のようにしても、座標が異なっており、思った描画になりません。
TopPos = DX.VGet(0.0f, 0, 0.0f);
BottomPos = DX.VGet(0.0f, 0.0f, -200.0f);
ちなみに、DX.DrawCone3Dで上記のパラメータを指定しましたが、思っていた通りの座標に描画されております。
|
Re: DrawCone3Dについて ( No.8 ) |
- 名前:管理人 日時:2020/07/14 01:32
> TopPosとは、(直/斜)円錐の頂点
> BottomPosとは、(直/斜)円錐の底面(円)の中心点であっておりますでしょうか?
はい、あっています
> 何故か、下記のようにしても、座標が異なっており、思った描画になりません。
> TopPos = DX.VGet(0.0f, 0, 0.0f);
> BottomPos = DX.VGet(0.0f, 0.0f, -200.0f);
> ちなみに、DX.DrawCone3Dで上記のパラメータを指定しましたが、思っていた通りの座標に描画されております。
手元のサンプルプログラムでは
TopPos = DX.VGet(0.0f, 0, 0.0f);
BottomPos = DX.VGet(0.0f, 0.0f, -200.0f);
でも正常に描画できていますので、C#に載せ替えられたプログラムに誤りがある可能性があります
よろしければ C#に載せ替えたプログラムを掲示板に貼り付けていただけないでしょうか?
|
Re: DrawCone3Dについて ( No.9 ) |
- 名前:Alphas 日時:2020/07/14 14:00
管理人様
移植し直円錐を描画する事は出来ました。
ただし、DrawPolygonIndexed3DのTransFlgをTRUEにしても何故か透過されていません。
また、直円錐から斜円錐に変更したいのですが、変更すべき箇所がよく分かりません。。
もし可能でしたら、下記から変更して頂けますと大変助かります。
private static DX.VERTEX3D[][] Vertexs = new DX.VERTEX3D[Databases.Define.MAX_CONE_NUM][];
private static ushort[][] Index = new ushort[Databases.Define.MAX_CONE_NUM][];
private static bool onePunDrawCone3DExtra = false;
// 円錐情報
public struct CONE_INFO
{
public CONE_INFO
(
DX.VECTOR topPos,
DX.VECTOR bottomPos,
float r,
uint difColor,
uint spcColor
)
{
this.TopPos = topPos;
this.BottomPos = bottomPos;
this.R = r;
this.DifColor = difColor;
this.SpcColor = spcColor;
}
public DX.VECTOR TopPos;
public DX.VECTOR BottomPos;
public float R;
public uint DifColor;
public uint SpcColor;
};
/// <summary>
/// 3D円錐(直円錐/斜円錐)パラメータ初期化。
/// </summary>
private void initDrawCone3DExtraParam()
{
for (int i = 0; i < Vertexs.Length; i++)
{
Vertexs[i] = new DX.VERTEX3D[Databases.Define.VERT_NUM];
}
for (int i = 0; i < Index.Length; i++)
{
Index[i] = new ushort[Databases.Define.INDEX_NUM];
}
}
/// <summary>
/// 3D 円錐(直円錐/斜円錐)を複数描画。
/// </summary>
unsafe private int drawCone3DExtra(CONE_INFO[] ConeInfo, int ConeNum, int trans)
{
int ix = 0;
int l = 0, AddIndex = 0;
DX.VERTEX3D[] vert1;
DX.VERTEX3D[] vert2 = new DX.VERTEX3D[Databases.Define.VERT_NUM - Databases.Define.CIR_VERT_NUM];
DX.VERTEX3D[] vert3 = new DX.VERTEX3D[Databases.Define.VERT_NUM - Databases.Define.CIR_VERT_NUM * 2];
if (!onePunDrawCone3DExtra)
{
onePunDrawCone3DExtra = true;
initDrawCone3DExtraParam();
}
for (l = 0; l < ConeNum; l++, AddIndex += Databases.Define.VERT_NUM)
{
DX.MATRIX Axis;
ushort[] ind = null;
DX.VECTOR SubV, xv, yv, zv;
DX.VECTOR bottomvec, norm;
float Length;
float[] SinCosTable = new float[Databases.Define.CIR_VERT_NUM * 2];
float[] t;
int dr, dg, db, sr, sg, sb, i, j, k, num;
// 色の値をR,G,Bの要素に分解
DX.GetColor2(ConeInfo[l].DifColor, out dr, out dg, out db);
DX.GetColor2(ConeInfo[l].SpcColor, out sr, out sg, out sb);
// 円錐の底から円錐の先に向かうベクトルを算出
SubV = DX.VSub(ConeInfo[l].TopPos, ConeInfo[l].BottomPos);
// 円錐の底から円錐の先までの長さを算出
Length = DX.VSize(SubV);
// 円錐の底から円錐の先に向かうベクトルを長さで割って
// 円錐の底から円錐の先に向かう長さ1のベクトルを算出
zv = DX.VScale(SubV, 1.0f / Length);
// 外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトルを算出
// ( 外積には X軸方向の長さ1のベクトルを使用 )
xv = DX.VGet(1.0f, 0.0f, 0.0f);
DX.VectorOuterProduct(out yv, out xv, out zv);
// 算出したベクトルに長さが無かった場合は Z軸方向の長さ1のベクトルで再度外積
if (DX.VSquareSize(yv) < 0.000000001f)
{
xv = DX.VGet(0.0f, 0.0f, 1.0f);
DX.VectorOuterProduct(out yv, out xv, out zv);
}
// 『外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトル』と
// 『円錐の底から円錐の先に向かうベクトル』の外積を算出して、
// お互いが垂直な3つのベクトルを算出
xv = DX.VNorm(DX.VCross(yv, zv));
yv = DX.VNorm(yv);
// お互いが垂直な3つのベクトルから
// 【任意の x, y, z の値を『お互いが垂直な3つのベクトル』を基本軸とする座標に変換する為の行列】を作成
Axis = DX.MGetAxis1(xv, yv, zv, ConeInfo[l].BottomPos);
// 三角錐の側面の法線を算出
norm = DX.VNorm(DX.VCross(DX.VGet(0.0f, 0.0f, 1.0f), DX.VSub(DX.VGet(ConeInfo[l].R, 0.0f, 0.0f), DX.VGet(0.0f, Length, 0.0f))));
// DivNum の数に沿った粒度の Sin,Cosテーブルを作成
t = SinCosTable;
int idx = 0;
for (i = 0; i < Databases.Define.CIR_VERT_NUM; i++, idx += 2)
{
t[idx] = (float)Math.Sin(2 * Math.PI / Databases.Define.CIR_VERT_NUM * i);
t[idx + 1] = (float)Math.Cos(2 * Math.PI / Databases.Define.CIR_VERT_NUM * i);
}
// 頂点データを作成
vert1 = Vertexs[l]; // 円の周囲の頂点データの先頭アドレスをセット
ix = 0;
// 円錐の先の頂点データの先頭アドレスをセット
foreach (var v in Vertexs[l])
{
if (ix++ < Databases.Define.CIR_VERT_NUM) continue;
vert2[ix - Databases.Define.CIR_VERT_NUM - 1] = v;
}
ix = 0;
// 円錐の周囲の底面用の頂点データの先頭アドレスをセット
foreach (var v in Vertexs[l])
{
if (ix++ < Databases.Define.CIR_VERT_NUM * 2) continue;
vert3[ix - Databases.Define.CIR_VERT_NUM * 2 - 1] = v;
}
t = SinCosTable; // Sin,Cosテーブルの先頭アドレスをセット
bottomvec = DX.VTransformSR(DX.VGet(0.0f, 0.0f, -1.0f), Axis); // 円錐の底方向のベクトルを算出
int idx1 = 0;
for (i = 0; i < Databases.Define.CIR_VERT_NUM; i++, idx1 += 2)
{
// vert1 は円の周囲の座標をセット
vert1[i].pos = DX.VTransform(DX.VGet(t[idx1] * ConeInfo[l].R, t[idx1 + 1] * ConeInfo[l].R, 0.0f), Axis);
// vert2 は円錐の先の座標をセット
vert2[i].pos = ConeInfo[l].TopPos;
// vert3 は vert1 と同じ座標
vert3[i].pos = vert1[i].pos;
// vert1 は円の周囲の法線をセット
vert1[i].norm = DX.VTransformSR(DX.VGet(t[idx1] * norm.x, t[idx1 + 1] * norm.x, norm.y), Axis);
// vert2 には vert1 と同じ法線
vert2[i].norm = vert1[i].norm;
// vert3 は円の底方向を法線としてセット
vert3[i].norm = bottomvec;
// 頂点の色をセット
vert1[i].dif.b = (byte)db; vert1[i].dif.g = (byte)dg; vert1[i].dif.r = (byte)dr; vert1[i].dif.a = 255;
vert2[i].dif.b = (byte)db; vert2[i].dif.g = (byte)dg; vert2[i].dif.r = (byte)dr; vert2[i].dif.a = 255;
vert3[i].dif.b = (byte)db; vert3[i].dif.g = (byte)dg; vert3[i].dif.r = (byte)dr; vert3[i].dif.a = 255;
vert1[i].spc.b = (byte)sb; vert1[i].spc.g = (byte)sg; vert1[i].spc.r = (byte)sr; vert1[i].spc.a = 0;
vert2[i].spc.b = (byte)sb; vert2[i].spc.g = (byte)sg; vert2[i].spc.r = (byte)sr; vert2[i].spc.a = 0;
vert3[i].spc.b = (byte)sb; vert3[i].spc.g = (byte)sg; vert3[i].spc.r = (byte)sr; vert3[i].spc.a = 0;
// 頂点のテクスチャ座標をセット( テクスチャは貼らないので全部 0.0f )
vert1[i].u = 0.0f; vert1[i].v = 0.0f;
vert2[i].u = 0.0f; vert2[i].v = 0.0f;
vert3[i].u = 0.0f; vert3[i].v = 0.0f;
vert1[i].su = 0.0f; vert1[i].sv = 0.0f;
vert2[i].su = 0.0f; vert2[i].sv = 0.0f;
vert3[i].su = 0.0f; vert3[i].sv = 0.0f;
}
// 頂点インデックスを準備
// 円錐の側面のポリゴンの頂点インデックスをセット
int idx2 = 0;
{
ind = Index[l];
for (i = 0; i < Databases.Define.CIR_VERT_NUM - 1; i++, idx2 += 3)
{
ind[idx2] = (ushort)(i + AddIndex);
ind[idx2 + 1] = (ushort)(Databases.Define.TOP_IND + i + AddIndex);
ind[idx2 + 2] = (ushort)(i + 1 + AddIndex);
}
ind[idx2] = (ushort)(i + AddIndex);
ind[idx2 + 1] = (ushort)(Databases.Define.TOP_IND + i + AddIndex);
ind[idx2 + 2] = (ushort)AddIndex;
idx2 += 3;
}
// 円錐の底面のポリゴンの頂点インデックスをセット
{
j = Databases.Define.BOTTOM_IND + Databases.Define.CIR_VERT_NUM - 1 + AddIndex;
i = Databases.Define.BOTTOM_IND + AddIndex;
ind[idx2] = (byte)i;
ind[idx2 + 1] = (byte)(i + 1);
ind[idx2 + 2] = (byte)j;
idx2 += 3;
num = Databases.Define.CIR_VERT_NUM - 2;
for (k = 1; k < num; )
{
ind[idx2] = (byte)j;
ind[idx2 + 1] = (byte)(i + 1);
ind[idx2 + 2] = (byte)(i + 2);
idx2 += 3;
k++;
i++;
if (k >= num) break;
ind[idx2] = (byte)j;
ind[idx2 + 1] = (byte)(i + 1);
ind[idx2 + 2] = (byte)(j - 1);
idx2 += 3;
j--;
k++;
if (k >= num) break;
}
}
}
ix = 0;
foreach (var v in vert2)
{
Vertexs[0][(ix++) + Databases.Define.CIR_VERT_NUM] = v;
}
ix = 0;
foreach (var v in vert3)
{
Vertexs[0][(ix++) + Databases.Define.CIR_VERT_NUM * 2] = v;
}
// ポリゴンを描画
DX.DrawPolygonIndexed3D(Vertexs[0], Databases.Define.VERT_NUM * ConeNum, Index[0], Databases.Define.INDEX_NUM / 3 * ConeNum, DX.DX_NONE_GRAPH, trans);
// 終了
return 0;
}
public class Databases
{
public class Define
{
public static readonly int MAX_CONE_NUM = 256;
public static readonly int DIVNUM = 32;
public static readonly int CIR_VERT_NUM = (DIVNUM + 4); // 円の頂点数
public static readonly int VERT_NUM = (CIR_VERT_NUM * 3); // 円錐の頂点数
public static readonly int TOP_IND = (CIR_VERT_NUM); // 円錐の先部分の頂点群の先頭番号
public static readonly int BOTTOM_IND = (CIR_VERT_NUM * 2); // 円錐の底部分の頂点群の先頭番号
public static readonly int INDEX_NUM = (CIR_VERT_NUM * 3 + (CIR_VERT_NUM - 2) * 3); // 頂点インデックスの数
// const
public const int CS_MAX_STRING = 256;
public const string CS_ERROR_MSG = "error!";
}
}
|
Re: DrawCone3Dについて ( No.10 ) |
- 名前:Alphas 日時:2020/07/14 16:10
管理人 様
移植し直円錐を描画する事は出来ました。
ただし、DrawPolygonIndexed3DのTransFlgをTRUEにしても何故か透過されていません。
透過されていないというのは、あくまでMakeScreenで作成した同じGraphicハンドル上での話になります。
また、直円錐から斜円錐に変更したいのですが、変更すべき箇所がよく分かりません。。
もし可能でしたら、下記から変更して頂けますと大変助かります。
private static DX.VERTEX3D[][] Vertexs = new DX.VERTEX3D[Databases.Define.MAX_CONE_NUM][];
private static ushort[][] Index = new ushort[Databases.Define.MAX_CONE_NUM][];
private static bool onePunDrawCone3DExtra = false;
// 円錐情報
public struct CONE_INFO
{
public CONE_INFO
(
DX.VECTOR topPos,
DX.VECTOR bottomPos,
float r,
uint difColor,
uint spcColor
)
{
this.TopPos = topPos;
this.BottomPos = bottomPos;
this.R = r;
this.DifColor = difColor;
this.SpcColor = spcColor;
}
public DX.VECTOR TopPos;
public DX.VECTOR BottomPos;
public float R;
public uint DifColor;
public uint SpcColor;
};
/// <summary>
/// 3D円錐(直円錐/斜円錐)パラメータ初期化。
/// </summary>
private void initDrawCone3DExtraParam()
{
for (int i = 0; i < Vertexs.Length; i++)
{
Vertexs[i] = new DX.VERTEX3D[Databases.Define.VERT_NUM];
}
for (int i = 0; i < Index.Length; i++)
{
Index[i] = new ushort[Databases.Define.INDEX_NUM];
}
}
/// <summary>
/// 3D 円錐(直円錐/斜円錐)を複数描画。
/// </summary>
unsafe private int drawCone3DExtra(CONE_INFO[] ConeInfo, int ConeNum, int trans)
{
int ix = 0;
int l = 0, AddIndex = 0;
DX.VERTEX3D[] vert1 = null;
DX.VERTEX3D[] vert2 = null;
DX.VERTEX3D[] vert3 = null;
if (!onePunDrawCone3DExtra)
{
onePunDrawCone3DExtra = true;
initDrawCone3DExtraParam();
}
for (l = 0; l < ConeNum; l++, AddIndex += Databases.Define.VERT_NUM)
{
DX.MATRIX Axis;
ushort[] ind = null;
DX.VECTOR SubV, xv, yv, zv;
DX.VECTOR bottomvec, norm;
float Length;
float[] SinCosTable = new float[Databases.Define.CIR_VERT_NUM * 2];
float[] t;
int dr, dg, db, sr, sg, sb, i, j, k, num;
// 初期化
vert1 = null;
vert2 = new DX.VERTEX3D[Databases.Define.VERT_NUM - Databases.Define.CIR_VERT_NUM];
vert3 = new DX.VERTEX3D[Databases.Define.VERT_NUM - Databases.Define.CIR_VERT_NUM * 2];
// 色の値をR,G,Bの要素に分解
DX.GetColor2(ConeInfo[l].DifColor, out dr, out dg, out db);
DX.GetColor2(ConeInfo[l].SpcColor, out sr, out sg, out sb);
// 円錐の底から円錐の先に向かうベクトルを算出
SubV = DX.VSub(ConeInfo[l].TopPos, ConeInfo[l].BottomPos);
// 円錐の底から円錐の先までの長さを算出
Length = DX.VSize(SubV);
// 円錐の底から円錐の先に向かうベクトルを長さで割って
// 円錐の底から円錐の先に向かう長さ1のベクトルを算出
zv = DX.VScale(SubV, 1.0f / Length);
// 外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトルを算出
// ( 外積には X軸方向の長さ1のベクトルを使用 )
xv = DX.VGet(1.0f, 0.0f, 0.0f);
DX.VectorOuterProduct(out yv, out xv, out zv);
// 算出したベクトルに長さが無かった場合は Z軸方向の長さ1のベクトルで再度外積
if (DX.VSquareSize(yv) < 0.000000001f)
{
xv = DX.VGet(0.0f, 0.0f, 1.0f);
DX.VectorOuterProduct(out yv, out xv, out zv);
}
// 『外積を使って円錐の底から円錐の先に向かうベクトルに垂直なベクトル』と
// 『円錐の底から円錐の先に向かうベクトル』の外積を算出して、
// お互いが垂直な3つのベクトルを算出
xv = DX.VNorm(DX.VCross(yv, zv));
yv = DX.VNorm(yv);
// お互いが垂直な3つのベクトルから
// 【任意の x, y, z の値を『お互いが垂直な3つのベクトル』を基本軸とする座標に変換する為の行列】を作成
Axis = DX.MGetAxis1(xv, yv, zv, ConeInfo[l].BottomPos);
// 三角錐の側面の法線を算出
norm = DX.VNorm(DX.VCross(DX.VGet(0.0f, 0.0f, 1.0f), DX.VSub(DX.VGet(ConeInfo[l].R, 0.0f, 0.0f), DX.VGet(0.0f, Length, 0.0f))));
// DivNum の数に沿った粒度の Sin,Cosテーブルを作成
t = SinCosTable;
int idx = 0;
for (i = 0; i < Databases.Define.CIR_VERT_NUM; i++, idx += 2)
{
t[idx] = (float)Math.Sin(2 * Math.PI / Databases.Define.CIR_VERT_NUM * i);
t[idx + 1] = (float)Math.Cos(2 * Math.PI / Databases.Define.CIR_VERT_NUM * i);
}
// 頂点データを作成
vert1 = Vertexs[l]; // 円の周囲の頂点データの先頭アドレスをセット
t = SinCosTable; // Sin,Cosテーブルの先頭アドレスをセット
bottomvec = DX.VTransformSR(DX.VGet(0.0f, 0.0f, -1.0f), Axis); // 円錐の底方向のベクトルを算出
int idx1 = 0;
for (i = 0; i < Databases.Define.CIR_VERT_NUM; i++, idx1 += 2)
{
// vert1 は円の周囲の座標をセット
vert1[i].pos = DX.VTransform(DX.VGet(t[idx1] * ConeInfo[l].R, t[idx1 + 1] * ConeInfo[l].R, 0.0f), Axis);
// vert2 は円錐の先の座標をセット
vert2[i].pos = ConeInfo[l].TopPos;
// vert3 は vert1 と同じ座標
vert3[i].pos = vert1[i].pos;
// vert1 は円の周囲の法線をセット
vert1[i].norm = DX.VTransformSR(DX.VGet(t[idx1] * norm.x, t[idx1 + 1] * norm.x, norm.y), Axis);
// vert2 には vert1 と同じ法線
vert2[i].norm = vert1[i].norm;
// vert3 は円の底方向を法線としてセット
vert3[i].norm = bottomvec;
// 頂点の色をセット
vert1[i].dif.b = (byte)db; vert1[i].dif.g = (byte)dg; vert1[i].dif.r = (byte)dr; vert1[i].dif.a = 255;
vert2[i].dif.b = (byte)db; vert2[i].dif.g = (byte)dg; vert2[i].dif.r = (byte)dr; vert2[i].dif.a = 255;
vert3[i].dif.b = (byte)db; vert3[i].dif.g = (byte)dg; vert3[i].dif.r = (byte)dr; vert3[i].dif.a = 255;
vert1[i].spc.b = (byte)sb; vert1[i].spc.g = (byte)sg; vert1[i].spc.r = (byte)sr; vert1[i].spc.a = 0;
vert2[i].spc.b = (byte)sb; vert2[i].spc.g = (byte)sg; vert2[i].spc.r = (byte)sr; vert2[i].spc.a = 0;
vert3[i].spc.b = (byte)sb; vert3[i].spc.g = (byte)sg; vert3[i].spc.r = (byte)sr; vert3[i].spc.a = 0;
// 頂点のテクスチャ座標をセット( テクスチャは貼らないので全部 0.0f )
vert1[i].u = 0.0f; vert1[i].v = 0.0f;
vert2[i].u = 0.0f; vert2[i].v = 0.0f;
vert3[i].u = 0.0f; vert3[i].v = 0.0f;
vert1[i].su = 0.0f; vert1[i].sv = 0.0f;
vert2[i].su = 0.0f; vert2[i].sv = 0.0f;
vert3[i].su = 0.0f; vert3[i].sv = 0.0f;
}
// 頂点インデックスを準備
// 円錐の側面のポリゴンの頂点インデックスをセット
int idx2 = 0;
{
ind = Index[l];
for (i = 0; i < Databases.Define.CIR_VERT_NUM - 1; i++, idx2 += 3)
{
ind[idx2] = (ushort)(i + AddIndex);
ind[idx2 + 1] = (ushort)(Databases.Define.TOP_IND + i + AddIndex);
ind[idx2 + 2] = (ushort)(i + 1 + AddIndex);
}
ind[idx2] = (ushort)(i + AddIndex);
ind[idx2 + 1] = (ushort)(Databases.Define.TOP_IND + i + AddIndex);
ind[idx2 + 2] = (ushort)AddIndex;
idx2 += 3;
}
// 円錐の底面のポリゴンの頂点インデックスをセット
{
j = Databases.Define.BOTTOM_IND + Databases.Define.CIR_VERT_NUM - 1 + AddIndex;
i = Databases.Define.BOTTOM_IND + AddIndex;
ind[idx2] = (byte)i;
ind[idx2 + 1] = (byte)(i + 1);
ind[idx2 + 2] = (byte)j;
idx2 += 3;
num = Databases.Define.CIR_VERT_NUM - 2;
for (k = 1; k < num; )
{
ind[idx2] = (byte)j;
ind[idx2 + 1] = (byte)(i + 1);
ind[idx2 + 2] = (byte)(i + 2);
idx2 += 3;
k++;
i++;
if (k >= num) break;
ind[idx2] = (byte)j;
ind[idx2 + 1] = (byte)(i + 1);
ind[idx2 + 2] = (byte)(j - 1);
idx2 += 3;
j--;
k++;
if (k >= num) break;
}
}
ix = 0;
foreach (var v in vert2)
{
Vertexs[l][(ix++) + Databases.Define.CIR_VERT_NUM] = v;
}
ix = 0;
foreach (var v in vert3)
{
Vertexs[l][(ix++) + Databases.Define.CIR_VERT_NUM * 2] = v;
}
}
// ポリゴンを描画
DX.DrawPolygonIndexed3D(Vertexs[0], Databases.Define.VERT_NUM * ConeNum, Index[0], Databases.Define.INDEX_NUM / 3 * ConeNum, DX.DX_NONE_GRAPH, trans);
// 終了
return 0;
}
public class Databases
{
public class Define
{
public static readonly int MAX_CONE_NUM = 256;
public static readonly int DIVNUM = 32;
public static readonly int CIR_VERT_NUM = (DIVNUM + 4); // 円の頂点数
public static readonly int VERT_NUM = (CIR_VERT_NUM * 3); // 円錐の頂点数
public static readonly int TOP_IND = (CIR_VERT_NUM); // 円錐の先部分の頂点群の先頭番号
public static readonly int BOTTOM_IND = (CIR_VERT_NUM * 2); // 円錐の底部分の頂点群の先頭番号
public static readonly int INDEX_NUM = (CIR_VERT_NUM * 3 + (CIR_VERT_NUM - 2) * 3); // 頂点インデックスの数
// const
public const int CS_MAX_STRING = 256;
public const string CS_ERROR_MSG = "error!";
}
}
|
Re: DrawCone3Dについて ( No.11 ) |
- 名前:管理人 日時:2020/07/15 01:23
> ただし、DrawPolygonIndexed3DのTransFlgをTRUEにしても何故か透過されていません。
DrawPolygonIndexed3D の透明度は VERTEX3D のメンバー変数 dif のメンバー変数 a で指定します
サンプルプログラムでは a に 255 を固定で代入していますが、半透明にされたい場合は
a に 128 などを入れ、ブレンドモードを DX_BLENDMODE_ALPHA に設定してください m(_ _)m
> また、直円錐から斜円錐に変更したいのですが、変更すべき箇所がよく分かりません。。
変更すべき場所は底辺の座標を設定しているこちらの行の箇所です
// vert1 は円の周囲の座標をセット
vert1[i].pos = DX.VTransform(DX.VGet(t[idx1] * ConeInfo[l].R, t[idx1 + 1] * ConeInfo[l].R, 0.0f), Axis);
こちらの vert1[i].pos に代入される座標をずらせば斜円錐になります
|
Re: DrawCone3Dについて ( No.12 ) |
- 名前:Alphas 日時:2020/07/15 11:12
管理人様
ご指摘の通りのαを変更することで半透明にすることが出来ました。有難う御座います。
残りの斜円錐についてですが、下記のようにしてみましたが、相変わらずダメです。
vert1[i].pos = DX.VTransform(DX.VGet(t[idx1] * ConeInfo[l].R, t[idx1 + 1] * ConeInfo[l].R, 0.0f), Axis);
↓
vert1[i].pos = DX.VTransform(DX.VGet(t[idx1] * ConeInfo[l].R, 0.0f, t[idx1 + 1] * ConeInfo[l].R), Axis);
一応確認なのですが、斜円錐とは下記の通りですが問題ありませんでしょうか?
h ttps://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10224048665
|
Re: DrawCone3Dについて ( No.13 ) |
- 名前:管理人 日時:2020/07/17 02:16
> 残りの斜円錐についてですが、下記のようにしてみましたが、相変わらずダメです。
vert1[i].pos = DX.VTransform(DX.VGet(t[idx1] * ConeInfo[l].R, t[idx1 + 1] * ConeInfo[l].R, 0.0f), Axis);
vert1[i].pos.x += 100.0f;
↑VTransformに渡す引数はそのままで、このように後から x に 100.0f を足せば底面部分が x方向に
100.0f ずれた円錐が描画されます
> 一応確認なのですが、斜円錐とは下記の通りですが問題ありませんでしょうか?
はい、私の想像する斜円錐のイメージと同じです
|
Re: DrawCone3Dについて ( No.14 ) |
- 名前:Alphas 日時:2020/07/17 15:38
管理人様
いつも丁寧にご教授頂き有難う御座います。
確かに上記の通りで円全体がx方向にシフトするため、斜円錐となる事を確認できました。
最終的には、ある一定の軸方向と底面が平行となるような斜円錐を表現したいため、底面を軸方向に対して回転させ平行となるように、
円周の座標を再計算したいと思います。
3Dでの表現ってなかなか難しいものですね><;
以上、宜しくお願いします。
|
|