DIrectX10 レイの交差判定の位置がずれる 操作が遅い
前提
DirectX10において簡単な3Dゲームの開発をしております。
DIrectXとC(C++)言語は独学で勉強したばかりで未熟なところが多々ありますが、大学でJavaをしっかりならっているのでプログラミングの基礎知識はあります。
「DirectX10/11プログラミング(Northbrain)」を参考書としております。
開発言語:C、C++
開発環境:VisualStudio2017
解決したいこと
「DirectX10/11プログラミング(Northbrain)」を参考書として開発をしておりますが、その中で使用している当たり判定のレイの交差判定を応用してプログラミングをしていた際に挙動がおかしくなってしまいました。
本来の動きは、操作モデル(Main.cpp内252行目:RobotB)を左右前後に動かしていく過程で静止モデル(Main.cpp内259行目:RobotB2)との当たり判定があった際に、操作モデルの動きが止まるようにしたいです。
ですが、
・静止モデルの当たり判定がモデル自体より手前にずれている
・当たり判定のある左右前後移動が、当たり判定のない左右前後移動のときより明らかに遅い動き
といった問題が出ております。
[問題と思われる箇所]
Main.cpp内822行目以降
参考書に載っていた、操作モデルと地面との当たり判定は正しい挙動をしております。(Main.cpp内855行目以降)
こちらは操作モデルが地面に向かって落下する際に地面と当たり判定があれば停止をするという動きです。
追記(2022/10/3)
どうやらもともと参考書に記載されている地面との当たり判定においても、操作キャラの落下速度が遅くなる現象があるようです。当たり判定がない場合と当たり判定がある場合とでの操作キャラの落下速度が明らかに違いました。もう少し原因を究明したいと思います。
エラーについて
エラーなし
該当するソースコード
//ヘッダーファイルのインクルード
#include <stdio.h>
#include <windows.h>
#include <d3d10.h>
#include <d3dx10.h>
//必要なライブラリファイルのロード
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"d3dx10.lib")
#pragma comment(lib,"d3d10.lib")
//警告非表示
#pragma warning(disable : 4305)
//定数定義
#define WINDOW_WIDTH 1280 //ウィンドウ幅640
#define WINDOW_HEIGHT 960 //ウィンドウ高さ480
#define APP_NAME L"レイ判定 地面で止まる D3d10"
//マクロ
#define SAFE_RELEASE(x) if(x){x->Release(); x=0;}
#define SAFE_DELETE(x) if(x){delete x; x=0;}
#define SAFE_DELETE_ARRAY(x) if(x){delete[] x; x=0;}
//頂点の構造体
struct MY_VERTEX
{
D3DXVECTOR3 vPos;
D3DXVECTOR3 vNorm;
D3DXVECTOR2 vTex;
};
//Simpleシェーダー用のコンスタントバッファーのアプリ側構造体 もちろんシェーダー内のコンスタントバッファーと一致している必要あり
struct SIMPLESHADER_CONSTANT_BUFFER0
{
D3DXMATRIX mW;//ワールド行列
D3DXMATRIX mWVP;//ワールドから射影までの変換行列
D3DXVECTOR4 vLightDir;//ライト方向
D3DXVECTOR4 vEye;//カメラ位置
};
struct SIMPLESHADER_CONSTANT_BUFFER1
{
D3DXVECTOR4 vAmbient;//アンビエント光
D3DXVECTOR4 vDiffuse;//ディフューズ色
D3DXVECTOR4 vSpecular;//鏡面反射
D3DXVECTOR4 vTexture;//テクスチャーが貼られているメッシュかどうかのフラグ
};
//オリジナル マテリアル構造体
struct MY_MATERIAL
{
CHAR szName[100];
D3DXVECTOR4 Ka;//アンビエント
D3DXVECTOR4 Kd;//ディフューズ
D3DXVECTOR4 Ks;//スペキュラー
CHAR szTextureName[100];//テクスチャーファイル名
ID3D10ShaderResourceView* pTexture;
DWORD dwNumFace;//そのマテリアルであるポリゴン数
MY_MATERIAL()
{
ZeroMemory(this, sizeof(MY_MATERIAL));
}
~MY_MATERIAL()
{
SAFE_RELEASE(pTexture);
}
};
//オリジナルメッシュ
struct MY_MESH
{
DWORD dwNumVert;
DWORD dwNumFace;
DWORD* dwNumFaceInMaterial;
ID3D10Buffer* pVertexBuffer;
D3DXVECTOR3* pvVertices;
ID3D10Buffer** ppIndexBuffer;
int** ppiVertexIndex;
DWORD m_dwNumMaterial;
MY_MATERIAL* m_pMaterial;
D3DXVECTOR3 vPos;
float r;//境界球 半径
D3DXVECTOR3 vCenter;//境界球 中心
float scale;//スケール 1.0fが実寸でデフォルト
D3DXMATRIX mRotation;
MY_MESH()
{
ZeroMemory(this, sizeof(MY_MESH));
}
};
//
//
//
class MAIN
{
public:
MAIN();
~MAIN();
HRESULT InitWindow(HINSTANCE, INT, INT, INT, INT, LPCWSTR);
LRESULT MsgProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitD3D();
HRESULT InitStaticMesh(LPCSTR FileName, MY_MESH* pMesh);
HRESULT LoadMaterialFromFile(LPSTR FileName, MY_MATERIAL** ppMaterial, DWORD* pdwNUmMaterial);
HRESULT InitShader();
void Loop();
void App();
void Render();
void Move();
void LayGround();
bool LayL(float);
bool LayR(float);
bool LayF(float);
bool LayB(float);
void RenderMesh(MY_MESH* pMesh);
void DestroyD3D();
void RenderRay(D3DXVECTOR3 vStart, D3DXVECTOR3 vDir);
bool RayHitDetection(D3DXVECTOR3 vStart, D3DXVECTOR3 vDir, MY_MESH* TargetMesh, float* fLength);
void CalcPlane(D3DXPLANE* pPlane, D3DXVECTOR3* pvA, D3DXVECTOR3* pvB, D3DXVECTOR3* pvC);
bool IsInside(D3DXVECTOR3* pvI, D3DXVECTOR3* pvA, D3DXVECTOR3* pvB, D3DXVECTOR3* pvC);
bool Intersect(D3DXPLANE p, D3DXVECTOR3 vStart, D3DXVECTOR3 vEnd, D3DXVECTOR3 v1, D3DXVECTOR3 v2, D3DXVECTOR3 v3, float* pfLen);
//↓アプリにひとつ
HWND m_hWnd;
ID3D10Device* m_pDevice;
IDXGISwapChain* m_pSwapChain;
ID3D10RenderTargetView* m_pRenderTargetView;
ID3D10DepthStencilView* m_pDepthStencilView;
ID3D10Texture2D* m_pDepthStencil;
ID3D10RasterizerState* m_pRasterizerState;
LPD3DX10FONT m_pFont;//文字表示用
ID3D10DepthStencilState* m_pDepthStencilState;
ID3D10BlendState* m_pBlendState;
D3DXVECTOR3 m_vEyePt;//視点
D3DXMATRIX mView;
D3DXMATRIX mProj;
//↓モデルの種類ごと(モデルの構造が全て同一ならアプリにひとつ)
ID3D10InputLayout* m_pVertexLayout;
ID3D10VertexShader* m_pVertexShader;
ID3D10PixelShader* m_pPixelShader;
ID3D10Buffer* m_pConstantBuffer0;
ID3D10Buffer* m_pConstantBuffer1;
//↓モデルごと
ID3D10Buffer* m_pVertexBuffer;
MY_MESH m_Mesh[4];//オブジェクト数
MY_MESH m_2DMesh;
ID3D10SamplerState* m_pSampleLinear;//テクスチャーのサンプラー
};
#include "MAIN.h"
#include "MOVE.cpp"
//グローバル変数
MAIN* g_pMain = NULL;
//フラグ
bool jflag = false;
bool Rflag = false;
//関数プロトタイプの宣言
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//
//
//アプリケーションのエントリー関数
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, INT)
{
g_pMain = new MAIN;
if (g_pMain != NULL)
{
if (SUCCEEDED(g_pMain->InitWindow(hInstance, 0, 0, WINDOW_WIDTH,
WINDOW_HEIGHT, APP_NAME)))
{
if (SUCCEEDED(g_pMain->InitD3D()))
{
g_pMain->Loop();
}
}
//アプリ終了
g_pMain->DestroyD3D();
delete g_pMain;
}
return 0;
}
//
//
//OSから見たウィンドウプロシージャー(実際の処理はMAINクラスのプロシージャーで処理)
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return g_pMain->MsgProc(hWnd, uMsg, wParam, lParam);
}
//
//
//
MAIN::MAIN()
{
ZeroMemory(this, sizeof(MAIN));
}
//
//
//
MAIN::~MAIN()
{
}
//
//
//ウィンドウ作成
HRESULT MAIN::InitWindow(HINSTANCE hInstance,
INT iX, INT iY, INT iWidth, INT iHeight, LPCWSTR WindowName)
{
// ウィンドウの定義
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wc.lpszClassName = WindowName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
//ウィンドウの作成
m_hWnd = CreateWindow(WindowName, WindowName, WS_OVERLAPPEDWINDOW,
0, 0, iWidth, iHeight, 0, 0, hInstance, 0);
if (!m_hWnd)
{
return E_FAIL;
}
//ウインドウの表示
ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);
return S_OK;
}
//
//
//ウィンドウプロシージャー
LRESULT MAIN::MsgProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
{
case WM_KEYDOWN:
switch ((char)wParam)
{
case VK_ESCAPE://ESCキーで修了
PostQuitMessage(0);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
//
//
//メッセージループとアプリケーション処理の入り口
void MAIN::Loop()
{
// メッセージループ
MSG msg = { 0 };
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //メッセージ取得したら真
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//アプリケーションの処理はここから飛ぶ。
App();
}
}
//アプリケーションの終了
}
//
//
//アプリケーション処理。アプリのメイン関数。
void MAIN::App()
{
Render();
}
//
//
//
HRESULT MAIN::InitD3D()
{
// デバイスとスワップチェーンの作成
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = WINDOW_WIDTH;
sd.BufferDesc.Height = WINDOW_HEIGHT;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = m_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
if (FAILED(D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL,
0, D3D10_SDK_VERSION, &sd, &m_pSwapChain, &m_pDevice)))
{
return FALSE;
}
//レンダーターゲットビューの作成
ID3D10Texture2D *pBackBuffer;
m_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer);
m_pDevice->CreateRenderTargetView(pBackBuffer, NULL, &m_pRenderTargetView);
SAFE_RELEASE(pBackBuffer);
//深度ステンシルビューの作成
D3D10_TEXTURE2D_DESC descDepth;
descDepth.Width = WINDOW_WIDTH;
descDepth.Height = WINDOW_HEIGHT;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D32_FLOAT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D10_USAGE_DEFAULT;
descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
m_pDevice->CreateTexture2D(&descDepth, NULL, &m_pDepthStencil);
m_pDevice->CreateDepthStencilView(m_pDepthStencil, NULL, &m_pDepthStencilView);
//レンダーターゲットビューと深度ステンシルビューをパイプラインにバインド
m_pDevice->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);
//震度ステンシルステートを作成
D3D10_DEPTH_STENCIL_DESC dc;
ZeroMemory(&dc, sizeof(dc));
dc.DepthEnable = true;
dc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
dc.DepthFunc = D3D10_COMPARISON_LESS;
dc.StencilEnable = false;
if (FAILED(m_pDevice->CreateDepthStencilState(&dc, &m_pDepthStencilState)))
{
return E_FAIL;
}
//深度ステンシルステートを適用
m_pDevice->OMSetDepthStencilState(m_pDepthStencilState, 0);
//ビューポートの設定
D3D10_VIEWPORT vp;
vp.Width = WINDOW_WIDTH;
vp.Height = WINDOW_HEIGHT;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
m_pDevice->RSSetViewports(1, &vp);
//ラスタライズ設定
D3D10_RASTERIZER_DESC rdc;
ZeroMemory(&rdc, sizeof(rdc));
rdc.CullMode = D3D10_CULL_BACK;
rdc.FillMode = D3D10_FILL_SOLID;
rdc.FrontCounterClockwise = TRUE;
m_pDevice->CreateRasterizerState(&rdc, &m_pRasterizerState);
m_pDevice->RSSetState(m_pRasterizerState);
//テクスチャー用サンプラー作成
D3D10_SAMPLER_DESC SamDesc;
ZeroMemory(&SamDesc, sizeof(D3D10_SAMPLER_DESC));
SamDesc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
SamDesc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
SamDesc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
SamDesc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
m_pDevice->CreateSamplerState(&SamDesc, &m_pSampleLinear);
//シェーダー初期化
if (FAILED(InitShader()))
{
return E_FAIL;
}
//メッシュ作成
if (FAILED(InitStaticMesh("ground.obj", &m_Mesh[0])))
{
return E_FAIL;
}
m_Mesh[0].vPos = D3DXVECTOR3(-0.2, 0, 0.5);
m_Mesh[0].scale = 1.0f;
if (FAILED(InitStaticMesh("sky.obj", &m_Mesh[1])))
{
return E_FAIL;
}
m_Mesh[1].vPos = D3DXVECTOR3(-0.2, 0, 0.5);
m_Mesh[1].scale = 1.0f;
if (FAILED(InitStaticMesh("RobotB.obj", &m_Mesh[2])))
{
return E_FAIL;
}
m_Mesh[2].vPos = D3DXVECTOR3(0, 5, 0);
m_Mesh[2].scale = 0.3f;
if (FAILED(InitStaticMesh("RobotB2.obj", &m_Mesh[3])))
{
return E_FAIL;
}
m_Mesh[3].vPos = D3DXVECTOR3(0.4, 0.22, 0.5);
m_Mesh[3].scale = 0.3f;
if (FAILED(InitStaticMesh("menu.obj", &m_2DMesh)))//問題:ちゃんと読み込めない
{
return E_FAIL;
}
m_2DMesh.vPos = D3DXVECTOR3(0.4, 2, 0.5);
m_2DMesh.scale = 1.0f;
//文字列レンダリングの初期化
if (FAILED(D3DX10CreateFont(m_pDevice, 0, 10, FW_REGULAR, NULL, false, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, L"tahoma", &m_pFont)))
{
return E_FAIL;
}
return S_OK;
}
//
//
//
void MAIN::DestroyD3D()
{
SAFE_RELEASE(m_pFont);
SAFE_RELEASE(m_pRasterizerState);
SAFE_RELEASE(m_pConstantBuffer0);
SAFE_RELEASE(m_pConstantBuffer1);
SAFE_RELEASE(m_pVertexShader);
SAFE_RELEASE(m_pPixelShader);
SAFE_RELEASE(m_pVertexBuffer);
SAFE_RELEASE(m_pVertexLayout);
SAFE_RELEASE(m_pSwapChain);
SAFE_RELEASE(m_pRenderTargetView);
SAFE_RELEASE(m_pDepthStencilView);
SAFE_RELEASE(m_pDepthStencil);
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pSampleLinear);
}
//
//
//シェーダーを作成 頂点レイアウトを定義
HRESULT MAIN::InitShader()
{
//hlslファイル読み込み ブロブ作成 ブロブとはシェーダーの塊みたいなもの。XXシェーダーとして特徴を持たない。後で各種シェーダーに成り得る。
ID3D10Blob *pCompiledShader = NULL;
ID3D10Blob *pErrors = NULL;
//ブロブからバーテックスシェーダー作成
if (FAILED(D3DX10CompileFromFile(L"Geometry_Material_Texture.hlsl", NULL, NULL, "VS", "vs_4_0", 0, 0, NULL, &pCompiledShader, &pErrors, NULL)))
{
MessageBox(0, L"hlsl読み込み失敗", NULL, MB_OK);
return E_FAIL;
}
SAFE_RELEASE(pErrors);
if (FAILED(m_pDevice->CreateVertexShader(pCompiledShader->GetBufferPointer(), pCompiledShader->GetBufferSize(), &m_pVertexShader)))
{
SAFE_RELEASE(pCompiledShader);
MessageBox(0, L"バーテックスシェーダー作成失敗", NULL, MB_OK);
return E_FAIL;
}
//頂点インプットレイアウトを定義
D3D10_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = sizeof(layout) / sizeof(layout[0]);
//頂点インプットレイアウトを作成
if (FAILED(m_pDevice->CreateInputLayout(layout, numElements, pCompiledShader->GetBufferPointer(), pCompiledShader->GetBufferSize(), &m_pVertexLayout)))
{
return FALSE;
}
//ブロブからピクセルシェーダー作成
if (FAILED(D3DX10CompileFromFile(L"Geometry_Material_Texture.hlsl", NULL, NULL, "PS", "ps_4_0", 0, 0, NULL, &pCompiledShader, &pErrors, NULL)))
{
MessageBox(0, L"hlsl読み込み失敗", NULL, MB_OK);
return E_FAIL;
}
SAFE_RELEASE(pErrors);
if (FAILED(m_pDevice->CreatePixelShader(pCompiledShader->GetBufferPointer(), pCompiledShader->GetBufferSize(), &m_pPixelShader)))
{
SAFE_RELEASE(pCompiledShader);
MessageBox(0, L"ピクセルシェーダー作成失敗", NULL, MB_OK);
return E_FAIL;
}
SAFE_RELEASE(pCompiledShader);
//コンスタントバッファー作成 変換行列渡し用
D3D10_BUFFER_DESC cb;
cb.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
cb.ByteWidth = sizeof(SIMPLESHADER_CONSTANT_BUFFER0);
cb.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
cb.MiscFlags = 0;
cb.Usage = D3D10_USAGE_DYNAMIC;
if (FAILED(m_pDevice->CreateBuffer(&cb, NULL, &m_pConstantBuffer0)))
{
return E_FAIL;
}
//コンスタントバッファー作成 マテリアル渡し用
cb.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
cb.ByteWidth = sizeof(SIMPLESHADER_CONSTANT_BUFFER1);
cb.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
cb.MiscFlags = 0;
cb.Usage = D3D10_USAGE_DYNAMIC;
if (FAILED(m_pDevice->CreateBuffer(&cb, NULL, &m_pConstantBuffer1)))
{
return E_FAIL;
}
//アルファブレンド用ブレンドステート作成
D3D10_BLEND_DESC bd;
ZeroMemory(&bd, sizeof(D3D10_BLEND_DESC));
bd.BlendEnable[0] = true;
bd.SrcBlend = D3D10_BLEND_SRC_ALPHA;
bd.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
bd.BlendOp = D3D10_BLEND_OP_ADD;
bd.SrcBlendAlpha = D3D10_BLEND_ONE;
bd.DestBlendAlpha = D3D10_BLEND_ZERO;
bd.BlendOpAlpha = D3D10_BLEND_OP_ADD;
bd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
if (FAILED(m_pDevice->CreateBlendState(&bd, &m_pBlendState)))
{
return E_FAIL;
}
UINT mask = 0xffffffff;
m_pDevice->OMSetBlendState(m_pBlendState, NULL, mask);
return S_OK;
}
//
//
//マテリアルファイルを読み込む関数
HRESULT MAIN::LoadMaterialFromFile(LPSTR FileName, MY_MATERIAL** ppMaterial, DWORD* pdwNUmMaterial)
{
//マテリアルファイルを開いて内容を読み込む
FILE* fp = NULL;
fopen_s(&fp, FileName, "rt");
char key[100] = { 0 };
D3DXVECTOR4 v(0, 0, 0, 1);
//マテリアル数を調べる
DWORD dwNumMaterial = 0;
while (!feof(fp))
{
//キーワード読み込み
fscanf_s(fp, "%s ", key, sizeof(key));
//マテリアル名
if (strcmp(key, "newmtl") == 0)
{
dwNumMaterial++;
}
}
MY_MATERIAL* pMaterial = new MY_MATERIAL[dwNumMaterial];
//本読み込み
fseek(fp, SEEK_SET, 0);
INT iMCount = -1;
while (!feof(fp))
{
//キーワード読み込み
fscanf_s(fp, "%s ", key, sizeof(key));
//マテリアル名
if (strcmp(key, "newmtl") == 0)
{
iMCount++;
fscanf_s(fp, "%s ", key, sizeof(key));
strcpy_s(pMaterial[iMCount].szName, key);
}
//Ka アンビエント
if (strcmp(key, "Ka") == 0)
{
fscanf_s(fp, "%f %f %f", &v.x, &v.y, &v.z);
pMaterial[iMCount].Ka = v;
}
//Kd ディフューズ
if (strcmp(key, "Kd") == 0)
{
fscanf_s(fp, "%f %f %f", &v.x, &v.y, &v.z);
pMaterial[iMCount].Kd = v;
}
//Ks スペキュラー
if (strcmp(key, "Ks") == 0)
{
fscanf_s(fp, "%f %f %f", &v.x, &v.y, &v.z);
pMaterial[iMCount].Ks = v;
}
//map_Kd テクスチャー
if (strcmp(key, "map_Kd") == 0)
{
fscanf_s(fp, "%s", &pMaterial[iMCount].szTextureName, sizeof(pMaterial[iMCount].szTextureName));
//テクスチャーを作成
if (FAILED(D3DX10CreateShaderResourceViewFromFileA(m_pDevice, pMaterial[iMCount].szTextureName, NULL, NULL, &pMaterial[iMCount].pTexture, NULL)))
{
return E_FAIL;
}
}
}
fclose(fp);
*ppMaterial = pMaterial;
*pdwNUmMaterial = dwNumMaterial;
return S_OK;
}
//
//
//
HRESULT MAIN::InitStaticMesh(LPCSTR FileName, MY_MESH* pMesh)
{
float x, y, z;
int v1 = 0, v2 = 0, v3 = 0;
int vn1 = 0, vn2 = 0, vn3 = 0;
int vt1 = 0, vt2 = 0, vt3 = 0;
DWORD dwVCount = 0;//読み込みカウンター
DWORD dwVNCount = 0;//読み込みカウンター
DWORD dwVTCount = 0;//読み込みカウンター
DWORD dwFCount = 0;//読み込みカウンター
char key[200] = { 0 };
//OBJファイルを開いて内容を読み込む
FILE* fp = NULL;
fopen_s(&fp, FileName, "rt");
//事前に頂点数、ポリゴン数を調べる
while (!feof(fp))
{
//キーワード読み込み
fscanf_s(fp, "%s ", key, sizeof(key));
//マテリアル読み込み
if (strcmp(key, "mtllib") == 0)
{
fscanf_s(fp, "%s ", key, sizeof(key));
LoadMaterialFromFile(key, &pMesh->m_pMaterial, &pMesh->m_dwNumMaterial);
}
//頂点
if (strcmp(key, "v") == 0)
{
pMesh->dwNumVert++;
}
//法線
if (strcmp(key, "vn") == 0)
{
dwVNCount++;
}
//テクスチャー座標
if (strcmp(key, "vt") == 0)
{
dwVTCount++;
}
//フェイス(ポリゴン)
if (strcmp(key, "f") == 0)
{
pMesh->dwNumFace++;
}
}
//一時的なメモリ確保(頂点バッファとインデックスバッファ)
MY_VERTEX* pvVertexBuffer = new MY_VERTEX[pMesh->dwNumVert];
D3DXVECTOR3* pvCoord = new D3DXVECTOR3[pMesh->dwNumVert];
pMesh->pvVertices = new D3DXVECTOR3[pMesh->dwNumVert];
D3DXVECTOR3* pvNormal = new D3DXVECTOR3[dwVNCount];
D3DXVECTOR2* pvTexture = new D3DXVECTOR2[dwVTCount];
//本読み込み
fseek(fp, SEEK_SET, 0);
dwVCount = 0;
dwVNCount = 0;
dwVTCount = 0;
dwFCount = 0;
while (!feof(fp))
{
//キーワード 読み込み
ZeroMemory(key, sizeof(key));
fscanf_s(fp, "%s ", key, sizeof(key));
//頂点 読み込み
if (strcmp(key, "v") == 0)
{
fscanf_s(fp, "%f %f %f", &x, &y, &z);
pvCoord[dwVCount].x = -x;//OBJは右手座標系なのでxあるいはzを反転
pvCoord[dwVCount].y = y;
pvCoord[dwVCount].z = z;
dwVCount++;
}
//法線 読み込み
if (strcmp(key, "vn") == 0)
{
fscanf_s(fp, "%f %f %f", &x, &y, &z);
pvNormal[dwVNCount].x = -x;//OBJは右手座標系なのでxあるいはzを反転
pvNormal[dwVNCount].y = y;
pvNormal[dwVNCount].z = z;
dwVNCount++;
}
//テクスチャー座標 読み込み
if (strcmp(key, "vt") == 0)
{
fscanf_s(fp, "%f %f", &x, &y);
pvTexture[dwVTCount].x = x;
pvTexture[dwVTCount].y = 1 - y;//OBJファイルはY成分が逆なので合わせる
dwVTCount++;
}
}
//マテリアルの数だけインデックスバッファーを作成
pMesh->ppIndexBuffer = new ID3D10Buffer*[pMesh->m_dwNumMaterial];
//フェイス 読み込み バラバラに収録されている可能性があるので、マテリアル名を頼りにつなぎ合わせる
bool boFlag = false;
int* piFaceBuffer = new int[pMesh->dwNumFace * 3];//3頂点ポリゴンなので、1フェイス=3頂点(3インデックス)
pMesh->ppiVertexIndex = new int*[pMesh->m_dwNumMaterial];
pMesh->dwNumFaceInMaterial = new DWORD[pMesh->m_dwNumMaterial];
for (DWORD i = 0; i < pMesh->m_dwNumMaterial; i++)
{
fseek(fp, SEEK_SET, 0);
dwFCount = 0;
while (!feof(fp))
{
//キーワード 読み込み
ZeroMemory(key, sizeof(key));
fscanf_s(fp, "%s ", key, sizeof(key));
//フェイス 読み込み→頂点インデックスに
if (strcmp(key, "usemtl") == 0)
{
fscanf_s(fp, "%s ", key, sizeof(key));
if (strcmp(key, pMesh->m_pMaterial[i].szName) == 0)
{
boFlag = true;
}
else
{
boFlag = false;
}
}
if (strcmp(key, "f") == 0 && boFlag == true)
{
if (pMesh->m_pMaterial[i].pTexture != NULL)//テクスチャーありサーフェイス
{
fscanf_s(fp, "%d/%d/%d %d/%d/%d %d/%d/%d", &v1, &vt1, &vn1, &v2, &vt2, &vn2, &v3, &vt3, &vn3);
}
else//テクスチャー無しサーフェイス
{
fscanf_s(fp, "%d//%d %d//%d %d//%d", &v1, &vn1, &v2, &vn2, &v3, &vn3);
}
piFaceBuffer[dwFCount * 3] = v1 - 1;
piFaceBuffer[dwFCount * 3 + 1] = v2 - 1;
piFaceBuffer[dwFCount * 3 + 2] = v3 - 1;
dwFCount++;
//頂点構造体に代入
pvVertexBuffer[v1 - 1].vPos = pvCoord[v1 - 1];
pvVertexBuffer[v1 - 1].vNorm = pvNormal[vn1 - 1];
pvVertexBuffer[v1 - 1].vTex = pvTexture[vt1 - 1];
pvVertexBuffer[v2 - 1].vPos = pvCoord[v2 - 1];
pvVertexBuffer[v2 - 1].vNorm = pvNormal[vn2 - 1];
pvVertexBuffer[v2 - 1].vTex = pvTexture[vt2 - 1];
pvVertexBuffer[v3 - 1].vPos = pvCoord[v3 - 1];
pvVertexBuffer[v3 - 1].vNorm = pvNormal[vn3 - 1];
pvVertexBuffer[v3 - 1].vTex = pvTexture[vt3 - 1];
}
}
if (dwFCount == 0)//使用されていないマテリアル対策
{
pMesh->ppIndexBuffer[i] = NULL;
pMesh->dwNumFaceInMaterial[i] = 0;
continue;
}
//インデックスバッファーを作成
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof(int) * dwFCount * 3;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = piFaceBuffer;
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;
if (FAILED(m_pDevice->CreateBuffer(&bd, &InitData, &pMesh->ppIndexBuffer[i])))
return FALSE;
pMesh->m_pMaterial[i].dwNumFace = dwFCount;
//頂点インデックスデータを保存しておく
pMesh->ppiVertexIndex[i] = new int[dwFCount * 3];
memcpy(pMesh->ppiVertexIndex[i], piFaceBuffer, sizeof(int)*dwFCount * 3);
pMesh->dwNumFaceInMaterial[i] = dwFCount;
}
delete[] piFaceBuffer;
fclose(fp);
//バーテックスバッファーを作成
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof(MY_VERTEX) *pMesh->dwNumVert;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = pvVertexBuffer;
if (FAILED(m_pDevice->CreateBuffer(&bd, &InitData, &pMesh->pVertexBuffer)))
return FALSE;
//頂点データを保存しておく
memcpy(pMesh->pvVertices, pvCoord, sizeof(D3DXVECTOR3)*pMesh->dwNumVert);
//ここでバウンディングスフィア作成
D3DXComputeBoundingSphere(pvCoord, pMesh->dwNumVert, sizeof(D3DXVECTOR3), &pMesh->vCenter, &pMesh->r);
//一時的な入れ物は、もはや不要
delete pvCoord;
delete pvNormal;
delete pvTexture;
delete[] pvVertexBuffer;
return S_OK;
}
//
//
//シーンを画面にレンダリング
void MAIN::Render()
{
//画面クリア(実際は単色で画面を塗りつぶす処理)
float ClearColor[4] = { 0,0,1,1 };// クリア色作成 RGBAの順
m_pDevice->ClearRenderTargetView(m_pRenderTargetView, ClearColor);//画面クリア
m_pDevice->ClearDepthStencilView(m_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0);//深度バッファクリア
// ビュートランスフォーム(視点座標変換)
m_vEyePt = D3DXVECTOR3(m_Mesh[2].vPos.x, m_Mesh[2].vPos.y + 0.2, m_Mesh[2].vPos.z - 2.0f); //カメラ(視点)位置
D3DXVECTOR3 vLookatPt = m_vEyePt + D3DXVECTOR3(0, 0, 1);//注視位置
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);//上方位置
D3DXMatrixLookAtLH(&mView, &m_vEyePt, &vLookatPt, &vUpVec);
// プロジェクショントランスフォーム(射影変換)
D3DXMatrixPerspectiveFovLH(&mProj, D3DX_PI / 4, (FLOAT)WINDOW_WIDTH / (FLOAT)WINDOW_HEIGHT, 0.1f, 100.0f);
//使用するシェーダーの登録
m_pDevice->VSSetShader(m_pVertexShader);
m_pDevice->PSSetShader(m_pPixelShader);
m_pDevice->GSSetShader(NULL);
//複数のメッシュをレンダリング メッシュは4
for (DWORD i = 0; i < 4; i++)
{
RenderMesh(&m_Mesh[i]);
}
RenderMesh(&m_2DMesh);
//操作キャラの動き
Move();
//画面更新(バックバッファをフロントバッファに)
m_pSwapChain->Present(0, 0);
}
//
//
//
void MAIN::RenderMesh(MY_MESH* pMesh)
{
//ワールド変換は個々のモデル単位で行う
D3DXMATRIX mWorld, mScale, mTran;
D3DXMatrixScaling(&mScale, pMesh->scale, pMesh->scale, pMesh->scale);
D3DXMatrixTranslation(&mTran, pMesh->vPos.x, pMesh->vPos.y, pMesh->vPos.z);
mWorld = mScale * mTran;
//ワールドを中心に回転ントバッファーに各種データを渡す
SIMPLESHADER_CONSTANT_BUFFER0* pcb;
if (SUCCEEDED(m_pConstantBuffer0->Map(D3D10_MAP_WRITE_DISCARD, NULL, (void**)&pcb)))
{
//ワールド行列を渡す
pcb->mW = mWorld;
D3DXMatrixTranspose(&pcb->mW, &pcb->mW);
//ワールド、カメラ、射影行列を渡す
D3DXMATRIX m = mWorld * mView*mProj;
pcb->mWVP = m;
D3DXMatrixTranspose(&pcb->mWVP, &pcb->mWVP);
//ライトの方向を渡す
D3DXVECTOR3 vLightDir(-1, 1, -1);
pcb->vLightDir = D3DXVECTOR4(vLightDir.x, vLightDir.y, vLightDir.z, 0.0f);
//視点位置を渡す
pcb->vEye = D3DXVECTOR4(m_vEyePt.x, m_vEyePt.y, m_vEyePt.z, 0);
m_pConstantBuffer0->Unmap();
}
//このコンスタントバッファーを使うシェーダーの登録
m_pDevice->VSSetConstantBuffers(0, 1, &m_pConstantBuffer0);
m_pDevice->PSSetConstantBuffers(0, 1, &m_pConstantBuffer0);
//頂点インプットレイアウトをセット
m_pDevice->IASetInputLayout(m_pVertexLayout);
//プリミティブ・トポロジーをセット
m_pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//バーテックスバッファーをセット
UINT stride = sizeof(MY_VERTEX);
UINT offset = 0;
m_pDevice->IASetVertexBuffers(0, 1, &pMesh->pVertexBuffer, &stride, &offset);
//マテリアルの数だけ、それぞれのマテリアルのインデックスバッファ-を描画
for (DWORD i = 0; i < pMesh->m_dwNumMaterial; i++)
{
//使用されていないマテリアル対策
if (pMesh->m_pMaterial[i].dwNumFace == 0)
{
continue;
}
//インデックスバッファーをセット
stride = sizeof(int);
offset = 0;
m_pDevice->IASetIndexBuffer(pMesh->ppIndexBuffer[i], DXGI_FORMAT_R32_UINT, 0);
//マテリアルの各要素をエフェクト(シェーダー)に渡す
SIMPLESHADER_CONSTANT_BUFFER1* pcb1;
if (SUCCEEDED(m_pConstantBuffer1->Map(D3D10_MAP_WRITE_DISCARD, NULL, (void**)&pcb1)))
{
//テクスチャーをシェーダーに渡す
if (pMesh->m_pMaterial[i].szTextureName[0] != NULL)
{
m_pDevice->PSSetSamplers(0, 1, &m_pSampleLinear);
m_pDevice->PSSetShaderResources(0, 1, &pMesh->m_pMaterial[i].pTexture);
pcb1->vTexture.x = 1;
}
else
{
pcb1->vTexture.x = 0;
}
pcb1->vAmbient = pMesh->m_pMaterial[i].Ka;//アンビエントををシェーダーに渡す
pcb1->vDiffuse = pMesh->m_pMaterial[i].Kd;//ディフューズカラーをシェーダーに渡す
pcb1->vSpecular = pMesh->m_pMaterial[i].Ks;//スペキュラーをシェーダーに渡す
m_pConstantBuffer1->Unmap();
}
m_pDevice->VSSetConstantBuffers(1, 1, &m_pConstantBuffer1);
m_pDevice->PSSetConstantBuffers(1, 1, &m_pConstantBuffer1);
//プリミティブをレンダリング
m_pDevice->DrawIndexed(pMesh->m_pMaterial[i].dwNumFace * 3, 0, 0);
}
}
//
//
//モデルの動き
void MAIN::Move()
{
float speed = 0;
if (GetKeyState(VK_SHIFT) & 0x80)
{
speed = 2;
}
else speed = 1;
//キーボード入力 矢印キーで操作 押キーと0x80で論理積=押している間は真
if (GetKeyState(VK_LEFT) & 0x80)//左移動
{
if (LayL(speed))
{
m_Mesh[2].vPos.x += 0.01;
}
else m_Mesh[2].vPos.x -= 0.001 * speed;
//当たり判定なし左移動
//m_Mesh[2].vPos.x -= 0.001 * speed;
}
if (GetKeyState(VK_RIGHT) & 0x80)//右移動
{
if (LayR(speed))
{
m_Mesh[2].vPos.x -= 0.01;
}
else m_Mesh[2].vPos.x += 0.001 * speed;
//当たり判定なし右移動
//m_Mesh[2].vPos.x += 0.001 * speed;
}
if (GetKeyState(VK_UP) & 0x80)//前移動
{
if (LayF(speed))
{
m_Mesh[2].vPos.z -= 0.01;
}
else m_Mesh[2].vPos.z += 0.001 * speed;
//当たり判定なし前移動
//m_Mesh[2].vPos.z += 0.001 * speed;
}
if (GetKeyState(VK_DOWN) & 0x80)//後移動
{
if (LayB(speed))
{
m_Mesh[2].vPos.z += 0.01;
}
else m_Mesh[2].vPos.z -= 0.001 * speed;
//当たり判定なし後移動
//m_Mesh[2].vPos.z -= 0.001 * speed;
}
//レイを描画(可視化のため不要)
RenderRay(m_Mesh[2].vPos, D3DXVECTOR3(0, -1, 0));
RenderRay(m_Mesh[2].vPos, D3DXVECTOR3(-1, 0, 0));
LayGround();
}
//
//
//地面のポリゴン部分とレイ判定
void MAIN::LayGround()
{
//落下量
float fall = 0.001;
//地面との距離
float gLen = 0;
if (jflag == false)//jflag処理ないとなぜかロボット2がぷるぷるする
{
//交差判定
if (RayHitDetection(m_Mesh[2].vPos, D3DXVECTOR3(0, -1, 0), &m_Mesh[0], &gLen))
{
//距離判定
if (gLen < 0.22f)
{
m_Mesh[2].vPos.y += 0.001;
jflag = true;
}
else
{
//距離がある限り落下
m_Mesh[2].vPos.y -= fall;
jflag = false;
}
}
else
{
//交差しない限り限り落下
m_Mesh[2].vPos.y -= fall;
jflag = false;
}
}
}
//
//問題:当たり判定ずれる、遅い
//モデル同士のレイ判定
bool MAIN::LayL(float speed)
{
bool ret = false;
float npcLen = 0;
//交差判定
if (RayHitDetection(m_Mesh[2].vPos, D3DXVECTOR3(-1, 0, 0), &m_Mesh[3], &npcLen))
{
//距離判定
if (npcLen < 0.22f)
{
ret = true;
}
}
return ret;
}
bool MAIN::LayR(float speed)
{
bool ret = false;
float npcLen = 0;
if (RayHitDetection(m_Mesh[2].vPos, D3DXVECTOR3(1, 0, 0), &m_Mesh[3], &npcLen))//交差判定
{
if (npcLen < 0.22f)//距離判定
{
ret = true;
}
}
return ret;
}
bool MAIN::LayF(float speed)
{
bool ret = false;
float npcLen = 0;
if (RayHitDetection(m_Mesh[2].vPos, D3DXVECTOR3(0, 0, 1), &m_Mesh[3], &npcLen))//交差判定
{
if (npcLen < 0.22f)//距離判定
{
ret = true;
}
}
return ret;
}
bool MAIN::LayB(float speed)
{
bool ret = false;
float npcLen = 0;
if (RayHitDetection(m_Mesh[2].vPos, D3DXVECTOR3(0, 0, -1), &m_Mesh[3], &npcLen))//交差判定
{
if (npcLen < 0.22f)//距離判定
{
ret = true;
}
}
return ret;
}
#include "MAIN.h"
//
//
//交差ありなら true なければ false
bool MAIN::RayHitDetection(D3DXVECTOR3 vStart, D3DXVECTOR3 vDir, MY_MESH* TargetMesh, float* fLength)
{
//対象メッシュのポリゴン全てを総当りで調べる。それぞれのポリゴンを平面方程式にして、レイと判定
bool ret = false;
float MinLength = FLT_MAX;
D3DXVECTOR3 vEnd = vStart + vDir * 50;//レイの長さとりあえず50単位
D3DXPLANE plane;
for (DWORD i = 0; i < TargetMesh->m_dwNumMaterial; i++)
{
for (DWORD k = 0; k < TargetMesh->dwNumFaceInMaterial[i]; k++)
{
//このポリゴンの3点を取得
D3DXVECTOR3 v1, v2, v3;
int index1 = TargetMesh->ppiVertexIndex[i][k * 3 + 0];
int index2 = TargetMesh->ppiVertexIndex[i][k * 3 + 1];
int index3 = TargetMesh->ppiVertexIndex[i][k * 3 + 2];
v1 = TargetMesh->pvVertices[index1];
v2 = TargetMesh->pvVertices[index2];
v3 = TargetMesh->pvVertices[index3];
//3点から平面方程式を作る
CalcPlane(&plane, &v1, &v2, &v3);
//平面とレイの交差を検出
if (Intersect(plane, vStart, vEnd, v1, v2, v3, fLength))
{
ret = true;
if (MinLength > *fLength) MinLength = *fLength;
}
}
}
*fLength = MinLength;
return ret;
}
//
//
//3点から平面方程式を求める
void MAIN::CalcPlane(D3DXPLANE* pPlane, D3DXVECTOR3* pvA, D3DXVECTOR3* pvB, D3DXVECTOR3* pvC)
{
//辺ベクトル
D3DXVECTOR3 vAB, vBC;
vAB = *pvB - *pvA;
vBC = *pvC - *pvB;
//平面法線ベクトル
D3DXVECTOR3 vNormal;
D3DXVec3Cross(&vNormal, &vAB, &vBC);
// 法線は平面の傾きでもあるので、そのまま代入
pPlane->a = vNormal.x;
pPlane->b = vNormal.y;
pPlane->c = vNormal.z;
// d を計算
pPlane->d = -(pPlane->a*pvA->x + pPlane->b*pvA->y + pPlane->c*pvA->z);
}
//
//
//その面と交差していれば true でなければ false
bool MAIN::Intersect(D3DXPLANE p, D3DXVECTOR3 vStart, D3DXVECTOR3 vEnd, D3DXVECTOR3 v1, D3DXVECTOR3 v2, D3DXVECTOR3 v3, float* pfLen)
{
//パラメトリック方程式の媒介変数” t "を解く。
float t = -((p.a * vEnd.x) + (p.b*vEnd.y) + (p.c*vEnd.z) + p.d) /
(((p.a*vStart.x) + (p.b*vStart.y) + (p.c*vStart.z)) - ((p.a*vEnd.x) + (p.b*vEnd.y) + (p.c*vEnd.z)));
// t が0から1の間であるなら交差していることになる(この時点では、まだ無限遠平面との交差)
if (t >= 0 && t <= 1.0)
{
//交点座標を得る tが分かっていれば両端点から簡単に求まる
D3DXVECTOR3 v;
v.x = t * vStart.x + (1 - t)*vEnd.x;
v.y = t * vStart.y + (1 - t)*vEnd.y;
v.z = t * vStart.z + (1 - t)*vEnd.z;
//交点が三角形の内か外かを判定 (ここで内部となれば、完全な交差となる)
if (IsInside(&v, &v1, &v2, &v3) == true)
{
//レイ始点と交点の距離を計算
*pfLen = D3DXVec3Length(&(v - vStart));
return true;
}
return false;
}
return false;
}
//
//
// 交点が面の内にあるときはtrueを、外にあるときはfalseを返す
bool MAIN::IsInside(D3DXVECTOR3* pvI, D3DXVECTOR3* pvA, D3DXVECTOR3* pvB, D3DXVECTOR3* pvC)
{
//辺ベクトル
D3DXVECTOR3 vAB, vBC, vCA;
vAB = *pvB - *pvA;
vBC = *pvC - *pvB;
vCA = *pvA - *pvC;
//辺ベクトルと「頂点から交点へ向かうベクトル」との、それぞれの外積用
D3DXVECTOR3 vCrossAB, vCrossBC, vCrossCA;
//「外積結果のベクトル」と平面法線ベクトルとの、それぞれの内積用
FLOAT fAB, fBC, fCA;
// 法線用
D3DXVECTOR3 vNormal;
// まず、3頂点から平面方程式を求める。これは、同時に平面の法線を求めることでもある
D3DXPLANE pln;
D3DXPlaneFromPoints(&pln, pvA, pvB, pvC);
vNormal.x = pln.a;//法線のx成分は平面方程式のx係数
vNormal.y = pln.b;//法線のy成分は平面方程式のy係数
vNormal.z = pln.c;//法線のz成分は平面方程式のz係数
D3DXVec3Normalize(&vNormal, &vNormal);
// 各頂点から交点Iに向かうベクトルをvVとする
D3DXVECTOR3 vV;
// 辺ABベクトル(頂点Bベクトル-頂点Aベクトル)と、頂点Aから交点Iへ向かうベクトル、の外積を求める
vV = *pvI - *pvA;
D3DXVec3Cross(&vCrossAB, &vAB, &vV);
// 辺BCベクトル(頂点Cベクトル-頂点Bベクトル)と、頂点Bから交点Iへ向かうベクトル、の外積を求める
vV = *pvI - *pvB;
D3DXVec3Cross(&vCrossBC, &vBC, &vV);
// 辺CAベクトル(頂点Aベクトル-頂点Cベクトル)と、頂点Cから交点Iへ向かうベクトル、の外積を求める
vV = *pvI - *pvC;
D3DXVec3Cross(&vCrossCA, &vCA, &vV);
// それぞれの、外積ベクトルとの内積を計算する
fAB = D3DXVec3Dot(&vNormal, &vCrossAB);
fBC = D3DXVec3Dot(&vNormal, &vCrossBC);
fCA = D3DXVec3Dot(&vNormal, &vCrossCA);
// 3つの内積結果のうち、一つでもマイナス符号のものがあれば、交点は外にある。
if (fAB >= 0 && fBC >= 0 && fCA >= 0)
{
// 交点は、面の内にある
return true;
}
// 交点は面の外にある
return false;
}
//
//
//確認用のレイを描画 判定自体には不要
void MAIN::RenderRay(D3DXVECTOR3 vStart, D3DXVECTOR3 vDir)
{
D3DXVECTOR3 vEnd = vStart + vDir * 100;//レイの長さは適当に100単位
MY_VERTEX vRay[2];
vRay[0].vPos = vStart;
vRay[1].vPos = vEnd;
//バーテックスバッファーを作成
ID3D10Buffer* pVertexBuffer = NULL;
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof(MY_VERTEX) * 2;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = vRay;
if (FAILED(m_pDevice->CreateBuffer(&bd, &InitData, &pVertexBuffer)))
return;
//使用するシェーダーの登録
m_pDevice->VSSetShader(m_pVertexShader);
m_pDevice->PSSetShader(m_pPixelShader);
//シェーダーのコンスタントバッファーに各種データを渡す
SIMPLESHADER_CONSTANT_BUFFER0* pcb;
if (SUCCEEDED(m_pConstantBuffer0->Map(D3D10_MAP_WRITE_DISCARD, NULL, (void**)&pcb)))
{
//ワールド、カメラ、射影行列を渡す
D3DXMATRIX m = mView * mProj;
D3DXMatrixTranspose(&m, &m);
pcb->mWVP = m;
m_pConstantBuffer0->Unmap();
}
//このコンスタントバッファーを使うシェーダーの登録
m_pDevice->VSSetConstantBuffers(0, 1, &m_pConstantBuffer0);
m_pDevice->PSSetConstantBuffers(0, 1, &m_pConstantBuffer0);
//頂点インプットレイアウトをセット
m_pDevice->IASetInputLayout(m_pVertexLayout);
//プリミティブ・トポロジーをセット
m_pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINELIST);
//バーテックスバッファーをセット
UINT stride = sizeof(MY_VERTEX);
UINT offset = 0;
m_pDevice->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
//プリミティブをレンダリング
m_pDevice->Draw(2, 0);
//
pVertexBuffer->Release();
}