Kayns Lab.

プログラミング、魚釣り、MUGEN、たまにゲーム  淫夢要素はありません
Information
あまり活動してませんが自分のニコニコミュニティです
Elecbyte様が403エラーで
入れない間の救済措置

私のワンドラで
Winmugen~MUGEN 1.1beta1
までを公開中です。

本体のダウンロード
クリエイトチーム
A.G.Factory
@AGFactory_info

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
[ --/--/-- --:-- ] スポンサー広告 | TB(-) | CM(-)

【DirectX11】FBXファイルから剛体メッシュのロード.mp12【FBX SDK 2016】

頂点整合・データ作成・マテリアル情報読み込み

//------------------------------------------------------------------------------------------------------
//頂点整合・データ作成
//------------------------------------------------------------------------------------------------------

auto MeshNode = Mesh->GetNode(); //ノードを取得
int MatCount = MeshNode->GetMaterialCount(); //メッシュのマテリアル数を取得
int MatElemCount = Mesh->GetElementMaterialCount();
MeshObj->MeshInfo.reserve(MatCount); //マテリアル数分の領域確保

//マテリアルインデックスで頂点情報を整合
if(MatCount > 1){
for(int emc = 0; emc < MatElemCount; emc++){
//マテリアル要素を取得
FbxGeometryElementMaterial* leMat = Mesh->GetElementMaterial(emc);

//マテリアル要素が存在する場合
if(leMat){

if(leMat->GetMappingMode() == FbxGeometryElement::eByPolygon && leMat->GetReferenceMode() == FbxGeometryElement::eIndexToDirect){
vector<int> MatIndexCount(MatCount);
//各ポリゴンをマテリアル別にカウント
int IndexArrayCount = leMat->GetIndexArray().GetCount();
for(int iac = 0; iac < IndexArrayCount; iac++){
MatIndexCount[leMat->GetIndexArray().GetAt(iac)]++;
}

//領域確保
for(int idx = 0; idx < MatCount; idx++){
MESH_INFO meshinfo;
meshinfo.VertexInfo.Pos.reserve(MatIndexCount[idx]);
meshinfo.VertexInfo.Normal.reserve(MatIndexCount[idx]);
meshinfo.VertexInfo.Color.reserve(MatIndexCount[idx]);
meshinfo.VertexInfo.UV.reserve(MatIndexCount[idx]);
meshinfo.VertexInfo.VertexCount = MatIndexCount[idx] * 3;
MeshObj->MeshInfo.push_back(meshinfo);
}

//マテリアル振り分け
for(int iac = 0; iac < IndexArrayCount; iac++){
int midx = leMat->GetIndexArray().GetAt(iac);
MeshObj->MeshInfo[midx].VertexInfo.Pos.push_back( {MeshPos[iac * 3].x, MeshPos[iac * 3].y, MeshPos[iac * 3].z});
MeshObj->MeshInfo[midx].VertexInfo.Normal.push_back({MeshNormal[iac * 3].x, MeshNormal[iac * 3].y, MeshNormal[iac * 3].z});
MeshObj->MeshInfo[midx].VertexInfo.Color.push_back( {MeshColor[iac * 3].r, MeshColor[iac * 3].g, MeshColor[iac * 3].b, MeshColor[iac * 3].a});
MeshObj->MeshInfo[midx].VertexInfo.UV.push_back( {MeshUV[iac * 3].u, MeshUV[iac * 3].v});

MeshObj->MeshInfo[midx].VertexInfo.Pos.push_back( {MeshPos[iac * 3 + 2].x, MeshPos[iac * 3 + 2].y, MeshPos[iac * 3 + 2].z});
MeshObj->MeshInfo[midx].VertexInfo.Normal.push_back({MeshNormal[iac * 3 + 2].x, MeshNormal[iac * 3 + 2].y, MeshNormal[iac * 3 + 2].z});
MeshObj->MeshInfo[midx].VertexInfo.Color.push_back( {MeshColor[iac * 3 + 2].r, MeshColor[iac * 3 + 2].g, MeshColor[iac * 3 + 2].b, MeshColor[iac * 3 + 2].a});
MeshObj->MeshInfo[midx].VertexInfo.UV.push_back( {MeshUV[iac * 3 + 2].u, MeshUV[iac * 3 + 2].v});

MeshObj->MeshInfo[midx].VertexInfo.Pos.push_back( {MeshPos[iac * 3 + 1].x, MeshPos[iac * 3 + 1].y, MeshPos[iac * 3 + 1].z});
MeshObj->MeshInfo[midx].VertexInfo.Normal.push_back({MeshNormal[iac * 3 + 1].x, MeshNormal[iac * 3 + 1].y, MeshNormal[iac * 3 + 1].z});
MeshObj->MeshInfo[midx].VertexInfo.Color.push_back( {MeshColor[iac * 3 + 1].r, MeshColor[iac * 3 + 1].g, MeshColor[iac * 3 + 1].b, MeshColor[iac * 3 + 1].a});
MeshObj->MeshInfo[midx].VertexInfo.UV.push_back( {MeshUV[iac * 3 + 1].u, MeshUV[iac * 3 + 1].v});
}
}
}
}
}else{
MESH_INFO meshinfo;

//領域確保
meshinfo.VertexInfo.Pos.reserve(IndexCount);
meshinfo.VertexInfo.Normal.reserve(IndexCount);
meshinfo.VertexInfo.Color.reserve(IndexCount);
meshinfo.VertexInfo.UV.reserve(IndexCount);
meshinfo.VertexInfo.VertexCount = IndexCount;

unsigned int idx = IndexCount / 3;
for(unsigned int ic = 0; ic < idx; ic++){
meshinfo.VertexInfo.Pos.push_back( {MeshPos[ic * 3].x, MeshPos[ic * 3].y, MeshPos[ic * 3].z});
meshinfo.VertexInfo.Normal.push_back({MeshNormal[ic * 3].x, MeshNormal[ic * 3].y, MeshNormal[ic * 3].z});
meshinfo.VertexInfo.Color.push_back( {MeshColor[ic * 3].r, MeshColor[ic * 3].g, MeshColor[ic * 3].b, MeshColor[ic * 3].a});
meshinfo.VertexInfo.UV.push_back( {MeshUV[ic * 3].u, MeshUV[ic * 3].v});

meshinfo.VertexInfo.Pos.push_back( {MeshPos[ic * 3 + 2].x, MeshPos[ic * 3 + 2].y, MeshPos[ic * 3 + 2].z});
meshinfo.VertexInfo.Normal.push_back({MeshNormal[ic * 3 + 2].x, MeshNormal[ic * 3 + 2].y, MeshNormal[ic * 3 + 2].z});
meshinfo.VertexInfo.Color.push_back( {MeshColor[ic * 3 + 2].r, MeshColor[ic * 3 + 2].g, MeshColor[ic * 3 + 2].b, MeshColor[ic * 3 + 2].a});
meshinfo.VertexInfo.UV.push_back( {MeshUV[ic * 3 + 2].u, MeshUV[ic * 3 + 2].v});

meshinfo.VertexInfo.Pos.push_back( {MeshPos[ic * 3 + 1].x, MeshPos[ic * 3 + 1].y, MeshPos[ic * 3 + 1].z});
meshinfo.VertexInfo.Normal.push_back({MeshNormal[ic * 3 + 1].x, MeshNormal[ic * 3 + 1].y, MeshNormal[ic * 3 + 1].z});
meshinfo.VertexInfo.Color.push_back( {MeshColor[ic * 3 + 1].r, MeshColor[ic * 3 + 1].g, MeshColor[ic * 3 + 1].b, MeshColor[ic * 3 + 1].a});
meshinfo.VertexInfo.UV.push_back( {MeshUV[ic * 3 + 1].u, MeshUV[ic * 3 + 1].v});
}

MeshObj->MeshInfo.push_back(meshinfo);
}


//------------------------------------------------------------------------------------------------------
//マテリアル情報読み込み
//------------------------------------------------------------------------------------------------------

for(int mc = 0; mc < MatCount; mc++){
//マテリアルを取得
auto Mat = MeshNode->GetMaterial(mc);
auto Prop = Mat->FindProperty(FbxSurfaceMaterial::sDiffuse);

unsigned int TexCount;

//FbxFileTextureの数を取得
TexCount = static_cast<unsigned int>(Prop.GetSrcObjectCount<FbxFileTexture>());

//FbxFileTextureが存在する場合
if(TexCount > 0){
for(unsigned int ftc = 0; ftc < TexCount; ftc++){
//テクスチャ情報を読み込む
auto FileTex = Prop.GetSrcObject<FbxFileTexture>(ftc);

if(FileTex){
//ファイル名を取得
string TexName = FileTex->GetRelativeFileName();
//相対パスを取得
wstring tp = curdir + conv(TexName);

//UV名を取得
string uvSetName = FileTex->UVSet.Get().Buffer();
//同じUV名がなければ格納する
if(find(MeshObj->UVSetName.begin(), MeshObj->UVSetName.end(), uvSetName) != MeshObj->UVSetName.end()){
MeshObj->UVSetName.push_back(uvSetName);
}

//Mapへ既に読み込まれていないか確認
MeshObj->MeshInfo[mc].MaterialInfo.Texture = TexMap.Get(tp.c_str());
//テクスチャが存在しない場合
if(!MeshObj->MeshInfo[mc].MaterialInfo.Texture){
//相対パスをセット
MeshObj->MeshInfo[mc].MaterialInfo.TexPath = tp;
//多重読み込み防止のためMapにセット
MeshObj->MeshInfo[mc].MaterialInfo.Texture = TexMap.Set(tp.c_str());
//テクスチャを読み込む
MeshObj->MeshInfo[mc].MaterialInfo.Texture->Load(MeshObj->MeshInfo[mc].MaterialInfo.TexPath);
}

MeshObj->MeshInfo[mc].MaterialInfo.TexSRV = MeshObj->MeshInfo[mc].MaterialInfo.Texture->GetShaderResourceView();

D3D11_SAMPLER_DESC samplerdesc;
samplerdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerdesc.MipLODBias = 0.0f;
samplerdesc.MaxAnisotropy = 2;
samplerdesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
samplerdesc.BorderColor[0] = 0.0f;
samplerdesc.BorderColor[1] = 0.0f;
samplerdesc.BorderColor[2] = 0.0f;
samplerdesc.BorderColor[3] = 0.0f;
samplerdesc.MinLOD = -FLT_MAX;
samplerdesc.MaxLOD = FLT_MAX;

HRESULT hr = Graphics.GetDevice()->CreateSamplerState(&samplerdesc, &MeshObj->MeshInfo[mc].MaterialInfo.SamplerState);
if(FAILED(hr)){
//サンプラステートの作成に失敗
}
}
}
}
}

頂点整合処理では、2枚以上のテクスチャが存在する場合のデータ並び替えと、反転した描画順を正しくするため2番目と3番目の入れ替えを同時にやっています。
まずは、どのポリゴンにどのテクスチャが適用されているかの情報が格納されているマテリアルインデックスを利用して、1つのオブジェクトをマテリアルごとに分割します。
例えるなら頭と体は別テクスチャが適用されているがモデルとしては1セットになっているbodyというオブジェクトを頭のオブジェクトと体のオブジェクトに分割します。
データはインデックス順に並び替えられていますので、分割する際に先頭から3つずつ取り出していきますが、その時にオフセットの順番を変えて2番目と3番目を入れ替えながら格納していきます。
マテリアルが1つの場合は描画順を正しながら移し替えていく作業となります。

解説としてはこんなところです。
もう少しモチベがあれば昨年中にまとめられたと思うんですが・・・
ここにまとめたやり方は他にどこにもまとめられてなかったので、まさに実験の繰り返しでした。
以前に書いたスキンメッシュの実装が不安というのはオブジェクトを複数に分割したところがスキンメッシュに影響するんじゃないかということです。
FBXファイルをVSで開けるようにするぐらいなら読み込み実行もできるようにして欲しかったんですがね・・・
スポンサーサイト
[ 2017/01/14 22:44 ] プログラミング | TB(0) | CM(0)

【DirectX11】FBXファイルから剛体メッシュのロード.mp11【FBX SDK 2016】

法線情報・頂点カラー情報・UV情報読み込み

//------------------------------------------------------------------------------------------------------
//法線情報読み込み
//------------------------------------------------------------------------------------------------------
for(unsigned int nec = 0; nec < NormalElemCount; nec++){
auto Normal = Mesh->GetElementNormal(nec); //メッシュからNormal要素を取得
auto NormalMapping = Normal->GetMappingMode(); //マッピングモードを取得
auto NormalReference = Normal->GetReferenceMode(); //リファレンスモードを取得

//PolygonVertex -- Direct
//インデックスごとに格納されている場合の処理
if((NormalMapping == FbxGeometryElement::eByPolygonVertex) && (NormalReference == FbxGeometryElement::eDirect)){
for(unsigned int nc = 0; nc < IndexCount; nc++){

XMFLOAT3 convert;

convert.x = static_cast<float>(Normal->GetDirectArray().GetAt(nc)[0]);
convert.y = static_cast<float>(Normal->GetDirectArray().GetAt(nc)[1]);
convert.z = static_cast<float>(Normal->GetDirectArray().GetAt(nc)[2]);

XMStoreFloat3(&convert, XMVector3TransformNormal(XMLoadFloat3(&convert), Rot));
XMStoreFloat3(&convert, XMVector3TransformNormal(XMLoadFloat3(&convert), Scale));

MeshNormal[nc].x = convert.x;
MeshNormal[nc].y = convert.y;
MeshNormal[nc].z = convert.z;
}

continue;
}
}


//------------------------------------------------------------------------------------------------------
//頂点カラー情報読み込み
//------------------------------------------------------------------------------------------------------
for(unsigned int vcc = 0; vcc < ColorElemCount; vcc++){
auto Color = Mesh->GetElementVertexColor(vcc);
auto VColorMapping = Color->GetMappingMode();
auto VColorReference = Color->GetReferenceMode();

if(VColorMapping == FbxGeometryElement::eByPolygonVertex && VColorReference == FbxGeometryElement::eIndexToDirect){
int IndexCount = Color->GetIndexArray().GetCount();

for(int vcic = 0; vcic < IndexCount; vcic++){
int idx = Color->GetIndexArray().GetAt(vcic);
MeshColor[vcic].r = static_cast<float>(Color->GetDirectArray().GetAt(idx)[0]);
MeshColor[vcic].g = static_cast<float>(Color->GetDirectArray().GetAt(idx)[1]);
MeshColor[vcic].b = static_cast<float>(Color->GetDirectArray().GetAt(idx)[2]);
MeshColor[vcic].a = static_cast<float>(Color->GetDirectArray().GetAt(idx)[3]);
}
}
}


//------------------------------------------------------------------------------------------------------
//UV情報読み込み
//------------------------------------------------------------------------------------------------------
for(unsigned int uvec = 0; uvec < UVElemCount; uvec++){
auto UV = Mesh->GetElementUV(uvec);
auto UVMapping = UV->GetMappingMode();
auto UVReference = UV->GetReferenceMode();
MeshObj->UVSetName.push_back(UV->GetName());

//PolygonVertex -- IndexToDirect
if((UVMapping == FbxGeometryElement::eByPolygonVertex) && (UVReference == FbxGeometryElement::eIndexToDirect)){
int UVIndexCount = UV->GetIndexArray().GetCount();
for(int uvic = 0; uvic < UVIndexCount; uvic++){
int idx = UV->GetIndexArray().GetAt(uvic);
MeshUV[uvic].u = static_cast<float>(UV->GetDirectArray().GetAt(idx)[0]);
MeshUV[uvic].v = 1.0f - static_cast<float>(UV->GetDirectArray().GetAt(idx)[1]);
}

continue;
}
}

この辺は特に変更がない箇所ですが、法線情報は頂点情報と同じく回転・反転させてやります。
[ 2017/01/14 21:38 ] プログラミング | TB(0) | CM(0)

【DirectX11】FBXファイルから剛体メッシュのロード.mp10【FBX SDK 2016】

初期化

//------------------------------------------------------------------------------------------------------
//初期化
//------------------------------------------------------------------------------------------------------

unsigned int VertexCount; //頂点数
unsigned int IndexCount; //インデックス数
unsigned int NormalElemCount; //法線セット数
unsigned int ColorElemCount; //頂点色セット数
unsigned int UVElemCount; //UVセット数

//各種バッファ
vector<VERTEX_XYZ> MeshPos; //頂点情報バッファ
vector<int> MeshIndex; //インデックス情報バッファ
vector<VERTEX_XYZ> MeshNormal; //法線情報バッファ
vector<VERTEX_RGBA> MeshColor; //頂点色情報バッファ
vector<VERTEX_UV> MeshUV; //UV情報バッファ

VertexCount = Mesh->GetControlPointsCount(); //頂点セット数を取得
IndexCount = Mesh->GetPolygonVertexCount(); //インデックスセット数を取得
NormalElemCount = Mesh->GetElementNormalCount(); //法線セット数を取得 (通常:1)
ColorElemCount = Mesh->GetElementVertexColorCount(); //頂点カラーセット数を取得
UVElemCount = Mesh->GetElementUVCount(); //UVセット数を取得 TODO 現段階ではUV1つのみ対応

MeshPos.resize(IndexCount,{0.0f, 0.0f, 0.0f}); //頂点セットの領域を確保
MeshIndex.resize(IndexCount, 0); //インデックスセットの領域を確保
MeshNormal.resize(IndexCount,{0.0f, 0.0f, 0.0f}); //法線セットの領域を確保
MeshColor.resize(IndexCount, {0.0f, 0.0f, 0.0f, 0.0f}); //頂点カラーセットの領域を確保
MeshUV.resize(IndexCount, {0.0f, 0.0f}); //UVセットの領域を確保


インデックス読み込み→頂点情報読み込み

//------------------------------------------------------------------------------------------------------
//インデックス情報読み込み
//------------------------------------------------------------------------------------------------------
int* index = Mesh->GetPolygonVertices();
for(unsigned int ic = 0; ic < IndexCount; ic++){
//インデックス情報がそのまま格納されているので抽出
MeshIndex[ic] = index[ic];
}


//------------------------------------------------------------------------------------------------------
//頂点情報読み込み
//------------------------------------------------------------------------------------------------------

//DirectX限定 頂点・法線回転 TODO
XMMATRIX Rot;
Rot = XMMatrixIdentity();
Rot = XMMatrixRotationX(ToRadian(-90));

XMMATRIX Scale;
Scale = XMMatrixIdentity();
Scale = XMMatrixScaling(1.0f, 1.0f, -1.0f);

{
//頂点取得→回転→バッファに格納→インデックス順に格納

//インデックス変換用バッファ
vector<VERTEX_XYZ> pos;
pos.reserve(VertexCount);

//回転・反転させてバッファに格納
for(unsigned int vc = 0; vc < VertexCount; vc++){
auto CtrlPoint = Mesh->GetControlPointAt(vc);

XMFLOAT3 convert;

convert.x = static_cast<float>(CtrlPoint[0]);
convert.y = static_cast<float>(CtrlPoint[1]);
convert.z = static_cast<float>(CtrlPoint[2]);

XMStoreFloat3(&convert, XMVector3TransformNormal(XMLoadFloat3(&convert), Rot));
XMStoreFloat3(&convert, XMVector3TransformNormal(XMLoadFloat3(&convert), Scale));

VERTEX_XYZ buf;

buf.x = convert.x;
buf.y = convert.y;
buf.z = convert.z;

pos.push_back(buf);
}

//インデックス順に格納
for(unsigned int vc = 0; vc < IndexCount; vc++){
MeshPos[vc].x = pos[MeshIndex[vc]].x;
MeshPos[vc].y = pos[MeshIndex[vc]].y;
MeshPos[vc].z = pos[MeshIndex[vc]].z;
}
}


頂点情報読み込みの前にX-90°にする回転行列とZ反転の拡大行列を作成します。
そして回転→拡大の順に適用させてバッファに保存します。

私が学生の時は回転と拡大はどちらが先でもよいと教わった記憶がありますが、軸反転の拡大行列が入っていると拡大→回転の順では明らかに結果がおかしくなるので注意しましょう。
加えて補足すると回転→拡大→移動の順で行列を適用させます。
[ 2017/01/13 22:39 ] プログラミング | TB(0) | CM(0)

【DirectX11】FBXファイルから剛体メッシュのロード.mp9【FBX SDK 2016】

前回の予告通り解説をします。
変更した点はデータ構造の変更に伴った部分が多くあまり解説と呼べるものはないので、追加した点を重点的に説明します。


クラス図はこのようになっています。
前回の解説からの改良点は、生配列だった箇所をvectorに変更している点やテクスチャをマテリアル情報として扱っている点です。
vectorから生配列を取り出すことができることを知ったので急遽変更を加えました。マテリアル情報は今のところテクスチャのみを入れている状態ですが、今後増やしていきます。

CMesh.h

#include <vector>
#include <string>
#include <memory>
#include <functional>
#include <d3d11.h>
#include <DirectXMath.h>
#include "Texture.h"
#include "VertexType.h"
#include "ResourceData.h"


namespace KaynsLib{

//頂点情報
struct VERTEX_INFO{
std::vector<VERTEX_XYZ> Pos; //頂点座標
std::vector<VERTEX_XYZ> Normal; //法線
std::vector<VERTEX_RGBA> Color; //頂点色
std::vector<VERTEX_UV> UV; //テクスチャUV
unsigned int VertexCount; //頂点数
};


//マテリアル情報 TODO
struct MATERIAL_INFO{
std::shared_ptr<CTexture> Texture; //TODO
ID3D11ShaderResourceView* TexSRV;
std::wstring TexPath;
ID3D11SamplerState* SamplerState;
};


//メッシュ情報
struct MESH_INFO{
MESH_INFO();
~MESH_INFO();

VERTEX_INFO VertexInfo; //頂点情報
MATERIAL_INFO MaterialInfo; //マテリアル情報
ID3D11Buffer* VertexBuffer[4]; //頂点バッファ
};


struct MESH_OBJECT{
std::vector<MESH_INFO> MeshInfo; //メッシュ情報
std::string MeshName; //メッシュ名
std::vector<std::string> UVSetName; //UVセット名 TODO
};


class CMesh : public CResource{
public:
CMesh();
~CMesh();

//メッシュ読み込み
//ワイド文字列を使用するので L"TextureName" のように入力すること
bool Load(const std::wstring filename);

//解放
//リソースマネージャを使用して読み込んだ場合は自動で解放されるので必要なし
void Release();

//メッシュ描画
//あらかじめシェーダ、入力レイアウトをセットしておくこと
std::function<void()> Draw;

DirectX::XMFLOAT4X4 World; //ワールド行列

private:

bool LoadFBX(const std::wstring filename);

std::vector<MESH_OBJECT*> Meshes; //メッシュオブジェクト
unsigned int MeshCount; //メッシュオブジェクト数

};
}

関数ごとに処理を分けて実装しようかと考えましたが、引数にFBX SDKのものを使用するとCMesh.hに対して無駄なインクルードが増えて嫌だったので敢えてLoadFBX関数1つに全処理を集約しました。
プログラムを追いかける側からしたら上から下に見ていくだけで流れが分かるのである程度は見やすいと思いますが・・・作り方としては汚いですね。
剛体メッシュの読み込みとしてはある程度形になりましたが、Blender以外での出力に対応させたりライト情報を取り入れたりなど改善点はいくつもあります。
改善点をある程度潰せたらスキンメッシュの実装をしようと考えてますが、このデータ構造でうまくいくのかが心配ですね・・・
[ 2017/01/13 18:59 ] プログラミング | TB(0) | CM(0)

【DirectX11】FBXファイルから剛体メッシュのロード.mp8【FBX SDK 2016】

前回の記事の座標変換が上手くいってないという考察はオブジェクトをアシンメトリーのものにすることで確認できました。





結論から言うと、上記の画像でいうBlender座標をDirectX座標に変換する作業です。
X-90°にすることで、OpenGLでおなじみのZ軸が手前に来る右手座標に変換できます。
その後Z値をスケール等で Z = -1.0 とすることでZ軸を反転させることができます。
最後にZ反転で描画順が反時計回りになってしまった頂点情報をきちんとした描画順(時計回り)に変換することで完了します。

頂点情報はあらかじめインデックス順に並び替えているので先頭から3つずつ区切ることで三角ポリゴンを構成する情報となります。
時計回りに変換というのはその3つの情報のうち2番目と3番目を入れ替えることで時計回りに変換できます。

詳しくはBitbucketに上げたソース(Source/Mesh.cpp)を確認してもらえたら分かりやすいと思います。(今後ソースを交えた解説を上げる予定)
[ 2017/01/13 01:09 ] プログラミング | TB(0) | CM(0)
Admin Info

kayns

Author:kayns
Twitter




    


『ましろ色シンフォニー *mutsu-no-hana』応援中です!

Access Counter
Link
Site Search
Friend Request Form
QR
QR


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。