Nanashi-soft○プログラマ専用○DirectX11開発○
#include <windows.h>PMDデータの解析部分です
#include <d3d11.h>
#include <d3dx11.h>
#include <xnamath.h>
#include <stdio.h>
#include "vs.h" //Vertex Shader
#include "ps.h" //Pixcel Shader
#include "ps_2.h" //Pixcel Shader 2
#include "modeldata.h" //モデルデータ保管クラス
#include "pmd.h" //PMDローダークラス
#pragma once
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
//ウィンドウのコールバック関数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message){
case WM_CLOSE:
PostMessage(hWnd, WM_DESTROY, 0, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hWnd, message, wParam, lParam));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
//ウィンドウクラスを登録して
TCHAR szWindowClass[] = "3DDISPPG";
WNDCLASS wcex;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
RegisterClass(&wcex);
//ウィンドウをクリエイト
HWND hWnd;
hWnd = CreateWindow(szWindowClass,
"3D Disp Pg",
WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
0,
0,
1920,
1080,
NULL,
NULL,
hInstance,
NULL);
D3D_DRIVER_TYPE driverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE(driverTypes);
DXGI_SWAP_CHAIN_DESC hDXGISwapChainDesc;
hDXGISwapChainDesc.BufferDesc.Width = 1980;
hDXGISwapChainDesc.BufferDesc.Height = 1080;
hDXGISwapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
hDXGISwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
hDXGISwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
hDXGISwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
hDXGISwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
hDXGISwapChainDesc.SampleDesc.Count = 1;
hDXGISwapChainDesc.SampleDesc.Quality = 0;
hDXGISwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
hDXGISwapChainDesc.BufferCount = 3;
hDXGISwapChainDesc.OutputWindow = hWnd;
hDXGISwapChainDesc.Windowed = TRUE;
hDXGISwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
hDXGISwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
//デバイスとスワップチェインを一気に生成
HRESULT hr;
D3D_DRIVER_TYPE hDriverType = D3D_DRIVER_TYPE_NULL;
IDXGISwapChain* hpDXGISwpChain = NULL;
ID3D11Device* hpDevice = NULL;
ID3D11DeviceContext* hpDeviceContext = NULL;
D3D_FEATURE_LEVEL hFeatureLevel = D3D_FEATURE_LEVEL_11_0;
for(UINT driverTypeIndex=0; driverTypeIndex < numDriverTypes; driverTypeIndex++){
hDriverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain(NULL, hDriverType, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &hDXGISwapChainDesc, &hpDXGISwpChain, &hpDevice, &hFeatureLevel, &hpDeviceContext);
if(SUCCEEDED(hr)){
break;
}
}
if(FAILED(hr)){
MessageBoxW(hWnd, L"D3D11CreateDeviceAndSwapChain", L"Err", MB_ICONSTOP);
goto End;
}
//スワップチェインのバックバッファ取得
ID3D11Texture2D* hpBackBuffer = NULL;
if(FAILED(hpDXGISwpChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&hpBackBuffer))){
MessageBoxW(hWnd, L"SwpChain GetBuffer", L"Err", MB_ICONSTOP);
goto End;
}
//そのバックバッファから描画ターゲット生成
ID3D11RenderTargetView *hpRenderTargetView = NULL;
if(FAILED(hpDevice->CreateRenderTargetView(hpBackBuffer, NULL, &hpRenderTargetView))){
MessageBoxW(hWnd, L"CreateRenderTargetView", L"Err", MB_ICONSTOP);
goto End;
}
//ステンシル用テクスチャー作成
ID3D11Texture2D* hpTexture2dDepth = NULL;
D3D11_TEXTURE2D_DESC hTexture2dDesc;
hTexture2dDesc.Width = hDXGISwapChainDesc.BufferDesc.Width;
hTexture2dDesc.Height = hDXGISwapChainDesc.BufferDesc.Height;
hTexture2dDesc.MipLevels = 1;
hTexture2dDesc.ArraySize = 1;
hTexture2dDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
hTexture2dDesc.SampleDesc = hDXGISwapChainDesc.SampleDesc;
hTexture2dDesc.Usage = D3D11_USAGE_DEFAULT;
hTexture2dDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
hTexture2dDesc.CPUAccessFlags = 0;
hTexture2dDesc.MiscFlags = 0;
if(FAILED(hpDevice->CreateTexture2D(&hTexture2dDesc, NULL, &hpTexture2dDepth))){
MessageBoxW(hWnd, L"CreateTexture2D", L"Err", MB_ICONSTOP);
goto End;
}
//ステンシルターゲット作成
ID3D11DepthStencilView* hpDepthStencilView = NULL;
D3D11_DEPTH_STENCIL_VIEW_DESC hDepthStencilViewDesc;
hDepthStencilViewDesc.Format = hTexture2dDesc.Format;
hDepthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
hDepthStencilViewDesc.Flags = 0;
if(FAILED(hpDevice->CreateDepthStencilView(hpTexture2dDepth, &hDepthStencilViewDesc, &hpDepthStencilView))){
MessageBoxW(hWnd, L"CreateDepthStencilView", L"Err", MB_ICONSTOP);
goto End;
}
//その描画ターゲットとステンシルターゲットコンテキストに設定
hpDeviceContext->OMSetRenderTargets(1, &hpRenderTargetView, hpDepthStencilView);
//ブレンディングステート生成
ID3D11BlendState* hpBlendState = NULL;
D3D11_BLEND_DESC BlendStateDesc;
BlendStateDesc.AlphaToCoverageEnable = FALSE;
BlendStateDesc.IndependentBlendEnable = FALSE;
for(int i=0; i < 8; i++){
BlendStateDesc.RenderTarget[i].BlendEnable = TRUE;
BlendStateDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA;
BlendStateDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
BlendStateDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD;
BlendStateDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE;
BlendStateDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ZERO;
BlendStateDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD;
BlendStateDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
}
hpDevice->CreateBlendState(&BlendStateDesc, &hpBlendState);
//そのブレンディングをコンテキストに設定
float blendFactor[4] = {D3D11_BLEND_ZERO, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO};
hpDeviceContext->OMSetBlendState(hpBlendState, blendFactor, 0xffffffff);
//ビューポート設定
D3D11_VIEWPORT vp;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = (float)hDXGISwapChainDesc.BufferDesc.Width;
vp.Height = (float)hDXGISwapChainDesc.BufferDesc.Height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
hpDeviceContext->RSSetViewports(1, &vp);
//ポリゴン頂点構造体
struct Vertex3D {
float pos[3]; //x-y-z
float col[4]; //r-g-b-a
float tex[2]; //x-y
};
//頂点レイアウト
//5番目のパラメータは先頭からのバイト数なので,COLORにはPOSITIONのfloat型4バイト×3を記述
D3D11_INPUT_ELEMENT_DESC hInElementDesc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 4*3, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 4*3 + 4*4, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
//それらをシェーダーに送る
struct ConstantBuffer
{
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
};
//constantバッファ生成
ID3D11Buffer* hpConstantBuffer = NULL;
D3D11_BUFFER_DESC hBufferDesc;
hBufferDesc.ByteWidth = sizeof(ConstantBuffer);
hBufferDesc.Usage = D3D11_USAGE_DEFAULT;
hBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
hBufferDesc.CPUAccessFlags = 0;
hBufferDesc.MiscFlags = 0;
hBufferDesc.StructureByteStride = sizeof(float);
if(FAILED(hpDevice->CreateBuffer(&hBufferDesc, NULL, &hpConstantBuffer))){
MessageBoxW(hWnd, L"Create ConstantBuffer", L"Err", MB_ICONSTOP);
goto End;
}
//描画時に使用する変数を宣言
ConstantBuffer hConstantBuffer;
XMMATRIX hWorld; //ワールド変換行列
XMMATRIX hView; //ビュー変換行列
XMMATRIX hProjection; //透視射影変換行列
//初期化ここまで
// =====================================================
modeldata *hModelData = new modeldata(); //モデルデータ保管クラス生成描画がなかなか安定せず,苦労しました
//pmdクラスを生成する。その際にコンストラクタにファイル名を教える
const int MODELDATA_MAX = 2;
char *pmdfile[] = {
"kagaminelin.pmd",
"hatsunemiku.pmd"
};
//モデルデータ分を予めGPUにセットする
for(int mdcnt=0; mdcnt < MODELDATA_MAX; mdcnt++){
pmd *modeldata = new pmd(pmdfile[mdcnt]);
// == PMDデータ読み込みここから ==
//頂点データを取得
int TYOUTEN = modeldata->vert_count;
Vertex3D *hVectorData;
hVectorData = new Vertex3D[TYOUTEN];
for(int i=0; i < TYOUTEN; i++){
hVectorData[i].pos[0] = modeldata->vertex[i].pos[0];
hVectorData[i].pos[1] = modeldata->vertex[i].pos[1];
hVectorData[i].pos[2] = modeldata->vertex[i].pos[2];
hVectorData[i].col[0] = 0.0f;
hVectorData[i].col[1] = 0.0f;
hVectorData[i].col[2] = 0.0f;
hVectorData[i].col[3] = 0.0f;
hVectorData[i].tex[0] = modeldata->vertex[i].uv[0];
hVectorData[i].tex[1] = modeldata->vertex[i].uv[1];
}
//インデックスデータを取得
int INDEXSU = modeldata->face_vert_count;
unsigned short *hIndexData;
hIndexData = new unsigned short[INDEXSU];
for(int i=0; i < INDEXSU; i++){
hIndexData[i] = modeldata->face_vert_index[i];
}
//カラーデータを取得
int COLORSU = modeldata->material_count;
//LPCSTRとかわけわかんないので,普通にCで書くよ
#define MATERIAL_FILENAME_MAX 21
char *texture_file = new char[COLORSU * MATERIAL_FILENAME_MAX];
memset(&texture_file[0], 0, COLORSU * MATERIAL_FILENAME_MAX);
int cnt_idx = 0; //インデックスカウンター
for(int i=0; i < COLORSU; i++){
//マテリアルにあるカウンター分回す
for(unsigned long j=0; j < modeldata->material[i].face_vert_count; j++){
//インデックスから頂点座標の行数を取り出す
int pos_vec = modeldata->face_vert_index[cnt_idx];
cnt_idx++; //インデックスカウンターを進める
//その頂点座標のカラーが現在のマテリアルカラー
hVectorData[pos_vec].col[0] = modeldata->material[i].diffuse_color[0]; //R
hVectorData[pos_vec].col[1] = modeldata->material[i].diffuse_color[1]; //G
hVectorData[pos_vec].col[2] = modeldata->material[i].diffuse_color[2]; //B
hVectorData[pos_vec].col[3] = modeldata->material[i].alpha; //A
}
//テクスチャー設定
//最後にNULLは保障されていないらしいので。。。
char w[MATERIAL_FILENAME_MAX];
memset(&w, 0, sizeof(w));
memcpy(&w, &modeldata->material[i].texture_file_name[0], MATERIAL_FILENAME_MAX - 1);
//テクスチャー名は0クリアされている保障は無かったし。。。
if(w[0] != 0){
//bmpの場合pngに変更
int w2 = 0;
while(w[w2] != 0){
w2++;
}
w2--;
if( (w[w2] == 'p' || w[w2] == 'P')
&& (w[w2-1] == 'm' || w[w2-1] == 'M')
&& (w[w2-2] == 'b' || w[w2-2] == 'B')
&& w[w2-3] == '.'){
w[w2] = 'g';
w[w2-1] = 'n';
w[w2-2] = 'p';
}
memcpy(&texture_file[i*MATERIAL_FILENAME_MAX], w, MATERIAL_FILENAME_MAX-1);
}
}
// == PMDデータ読み込みここまで ==
//モデルデータクラスの状況取得
//次のオブジェ番号を取得
int hObjNum = hModelData->getObjMax();
//次の頂点バッファー番号を取得
int hVctBufNum = hModelData->getMaxVctBufNum();
//次のインデックスバッファー番号を取得
int hIdxBufNum = hModelData->getMaxIdxBufNum();
// == GPUにデータ送信 ==
//頂点バッファ作成
D3D11_BUFFER_DESC hBufferDesc;
hBufferDesc.ByteWidth = sizeof(Vertex3D) * TYOUTEN;
hBufferDesc.Usage = D3D11_USAGE_DEFAULT;
hBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
hBufferDesc.CPUAccessFlags = 0;
hBufferDesc.MiscFlags = 0;
hBufferDesc.StructureByteStride = sizeof(float);
D3D11_SUBRESOURCE_DATA hSubResourceData;
hSubResourceData.pSysMem = hVectorData;
hSubResourceData.SysMemPitch = 0;
hSubResourceData.SysMemSlicePitch = 0;
if(FAILED(hpDevice->CreateBuffer(&hBufferDesc, &hSubResourceData, &hModelData->vctBuf[hVctBufNum]))){
MessageBoxW(hWnd, L"CreateBuffer", L"Err", MB_ICONSTOP);
goto End;
}
//インデックスバッファ作成
hBufferDesc.ByteWidth = sizeof(unsigned short) * INDEXSU;
hBufferDesc.Usage = D3D11_USAGE_DEFAULT;
hBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
hBufferDesc.CPUAccessFlags = 0;
hBufferDesc.MiscFlags = 0;
hBufferDesc.StructureByteStride = sizeof(unsigned short);
hSubResourceData.pSysMem = hIndexData;
hSubResourceData.SysMemPitch = 0;
hSubResourceData.SysMemSlicePitch = 0;
if(FAILED(hpDevice->CreateBuffer(&hBufferDesc, &hSubResourceData, &hModelData->idxBuf[hIdxBufNum]))){
MessageBoxW(hWnd, L"CreateBuffer Index", L"Err", MB_ICONSTOP);
goto End;
}
// == モデルデータクラスにデータをセット ==
//PMDデータはマテリアル単位で分割すればシェーダーを適切に当てられる(はず)
int hIdxStaWork = 0;
for(int i=0; i < COLORSU; i++){
//モデルデータ保管を生成(PMDのマテリアル単位に)
int hModelId = hModelData->newData();
//同一モデルとしてオブジェ番号をセット
hModelData->setObjNum(hModelId, hObjNum);
//頂点データはモデルデータ単位で同じ
hModelData->setVctCnt(hModelId, TYOUTEN);
hModelData->setVctBufNum(hModelId, hVctBufNum);
//そのマテリアルのインデックス数を取得
int hIdxCnt = modeldata->material[i].face_vert_count;
//インデックス情報をセット
hModelData->setIdxCnt(hModelId, hIdxCnt);
hModelData->setIdxSta(hModelId, hIdxStaWork);
hModelData->setIdxBufNum(hModelId, hIdxBufNum);
//テクスチャー情報をセット
//なぜかID3D11ShaderResourceViewをnewすると怒られるので,この場で生成してモデルデータクラスにセットする
if(texture_file[i*MATERIAL_FILENAME_MAX] != 0x00){
//テクスチャーファイルを読み込み
D3DX11_IMAGE_LOAD_INFO LoadInfo;
LoadInfo.Width = 0;
LoadInfo.Height = 0;
LoadInfo.Depth = 0;
LoadInfo.FirstMipLevel = 0;
LoadInfo.MipLevels = D3DX11_DEFAULT,
LoadInfo.Usage = D3D11_USAGE_DEFAULT;
LoadInfo.BindFlags = D3D11_BIND_SHADER_RESOURCE;
LoadInfo.CpuAccessFlags = 0;
LoadInfo.MiscFlags = 0;
LoadInfo.Format = DXGI_FORMAT_R32G32B32_FLOAT;
LoadInfo.Filter = D3DX11_FILTER_TRIANGLE;
LoadInfo.MipFilter = D3DX11_FILTER_TRIANGLE;
LoadInfo.pSrcInfo = NULL;
ID3D11ShaderResourceView* hpShaderResourceView = NULL;
LPCSTR file;
char w[MATERIAL_FILENAME_MAX];
memcpy(w, &texture_file[i*MATERIAL_FILENAME_MAX], MATERIAL_FILENAME_MAX);
file = w;
if(FAILED(D3DX11CreateShaderResourceViewFromFile(hpDevice, file, &LoadInfo, NULL, &hpShaderResourceView, NULL))){
MessageBoxW(hWnd, L"D3DX11CreateShaderResourceViewFromFile", L"Err", MB_ICONSTOP);
goto End;
}
//テクスチャー情報をセット
//次のテクスチャー番号を取得
int hTexSta = hModelData->getTexMax();
hModelData->setTexCnt(hModelId, 1);
hModelData->setTexSta(hModelId, hTexSta);
hModelData->setTexSRV(hTexSta, 0, hpShaderResourceView);
hModelData->setPsNum(hModelId, 1); //PSにテクスチャー描画をセット
}else{
hModelData->setPsNum(hModelId, 0); //PSにマテリアル描画をセット
}
//描画フラグをするに設定
hModelData->setDrawYes(hModelId, 1);
hIdxStaWork += hIdxCnt;
}
// == データ保管ここまで ==
delete []texture_file;
hVectorData = NULL;
}
//プリミティブ(ポリゴンの形状)をコンテキストに設定モデルデータを管理するクラスです
hpDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// hpDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
//予めHLSLをコンパイルしてヘッダーに追加しておきます
//頂点レイアウト作成
ID3D11InputLayout* hpInputLayout = NULL;
if(FAILED(hpDevice->CreateInputLayout(hInElementDesc, ARRAYSIZE(hInElementDesc), &g_vs_main, sizeof(g_vs_main), &hpInputLayout))){
MessageBoxW(hWnd, L"CreateInputLayout", L"Err", MB_ICONSTOP);
goto End;
}
//頂点レイアウトをコンテキストに設定
hpDeviceContext->IASetInputLayout(hpInputLayout);
//頂点シェーダー生成
ID3D11VertexShader* hpVertexShader;
if(FAILED(hpDevice->CreateVertexShader(&g_vs_main, sizeof(g_vs_main), NULL, &hpVertexShader))){
MessageBoxW(hWnd, L"CreateVertexShader", L"Err", MB_ICONSTOP);
goto End;
}
//ラスタライザー生成
ID3D11RasterizerState* hpRasterizerState = NULL;
D3D11_RASTERIZER_DESC hRasterizerDesc = {
D3D11_FILL_SOLID,
// D3D11_FILL_WIREFRAME,
D3D11_CULL_NONE, //ポリゴンの裏表を無くす
FALSE,
0,
0.0f,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE
};
if(FAILED(hpDevice->CreateRasterizerState(&hRasterizerDesc, &hpRasterizerState))){
MessageBoxW(hWnd, L"CreateRasterizerState", L"Err", MB_ICONSTOP);
goto End;
}
//ラスタライザーをコンテキストに設定
hpDeviceContext->RSSetState(hpRasterizerState);
//ピクセルシェーダー生成(マテリアル描画用)
// ID3D11PixelShader* hpPixelShaders = new ID3D11PixelShader[2]; //←できない
ID3D11PixelShader* hpPixelShader;
if(FAILED(hpDevice->CreatePixelShader(&g_ps_main, sizeof(g_ps_main), NULL, &hpPixelShader))){
MessageBoxW(hWnd, L"CreateVertexShader", L"Err", MB_ICONSTOP);
goto End;
}
//ピクセルシェーダー2生成(テクスチャー描画用)
ID3D11PixelShader* hpPixelShader2;
if(FAILED(hpDevice->CreatePixelShader(&g_ps_main2, sizeof(g_ps_main2), NULL, &hpPixelShader2))){
MessageBoxW(hWnd, L"CreateVertexShader 2", L"Err", MB_ICONSTOP);
goto End;
}
//グラフィックパイプライン処理
//頂点シェーダーをコンテキストに設定
hpDeviceContext->VSSetShader(hpVertexShader, NULL, 0);
//ハルシェーダーは無し
hpDeviceContext->HSSetShader(NULL, NULL, 0 );
//テッセレーターは無し
//ドメインシェーダーは無し
hpDeviceContext->DSSetShader(NULL, NULL, 0 );
//ジオメトリシェーダーは無し
hpDeviceContext->GSSetShader(NULL, NULL, 0 );
//メインループ
MSG hMsg;
while(true){
while(PeekMessageW(&hMsg, NULL, 0, 0, PM_REMOVE)){
if(hMsg.message == WM_QUIT){
goto End;
}
TranslateMessage(&hMsg);
DispatchMessage(&hMsg);
}
//背景クリア
float ClearColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
hpDeviceContext->ClearRenderTargetView(hpRenderTargetView, ClearColor);
hpDeviceContext->ClearDepthStencilView(hpDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
//カメラデータセット
hModelData->setCamEye(0, 0.0f, 10.0f, -20.0f, 0.0f); //カメラの位置
hModelData->setCamAt(0, 0.0f, 10.0f, 0.0f, 0.0f); //焦点の位置
hModelData->setCamUp(0, 0.0f, 1.0f, 0.0f, 0.0f);
hModelData->setCamFov(0, 60.0f, 16.0f/9.0f, 0.1f, 1000.0f);
//オブジェ単位に表示場所を設定
hModelData->setObjIdentity(1);
hModelData->setObjTranslation(1, 5.0, 0.0, 0.0);
hModelData->setObjIdentity(2);
hModelData->setObjTranslation(2, -5.0, 0.0, 0.0);
//最大セット可能モデルデータ数までループする
for(int mdcnt=0; mdcnt < hModelData->getMaxModelId(); mdcnt++){
//描画するデータが存在するか?
if (hModelData->getDrawYes(mdcnt)){
//シェーダーに送信
hConstantBuffer.mWorld = hModelData->getObjWld(hModelData->getObjNum(mdcnt));
hConstantBuffer.mView = hModelData->getCamView(0);
hConstantBuffer.mProjection = hModelData->getProjection(0);
hpDeviceContext->UpdateSubresource(hpConstantBuffer, 0, NULL, &hConstantBuffer, 0, 0);
hpDeviceContext->VSSetConstantBuffers(0, 1, &hpConstantBuffer);
//頂点バッファー切り替え
UINT hStrides = sizeof(Vertex3D);
UINT hOffsets = 0;
hpDeviceContext->IASetVertexBuffers(0, 1, &hModelData->vctBuf[hModelData->getVctBufNum(mdcnt)], &hStrides, &hOffsets);
//インデックスバッファー切り替え
hpDeviceContext->IASetIndexBuffer(hModelData->idxBuf[hModelData->getIdxBufNum(mdcnt)], DXGI_FORMAT_R16_UINT, 0);
//テクスチャー切り替え
ID3D11ShaderResourceView* hpShaderResourceViews[] = { hModelData->getTexSRV(hModelData->getTexSta(mdcnt), 0) };
hpDeviceContext->PSSetShaderResources(0, 1, hpShaderResourceViews);
//ピクセルシェーダー切り替え
if(hModelData->getPsNum(mdcnt) == 0){
hpDeviceContext->PSSetShader(hpPixelShader2, NULL, 0);
}else if(hModelData->getPsNum(mdcnt) == 1){
hpDeviceContext->PSSetShader(hpPixelShader, NULL, 0);
}
//インデックス描画
hpDeviceContext->DrawIndexed(hModelData->getIdxCnt(mdcnt), hModelData->getIdxSta(mdcnt), 0);
}
}
hpDXGISwpChain->Present(0, 0);
}
End:
//ポインタで生成したものはリリースする必要がある
//どの変数か識別し易いように,hpで始めてある
SAFE_RELEASE(hpPixelShader);
SAFE_RELEASE(hpVertexShader);
SAFE_RELEASE(hpInputLayout);
SAFE_RELEASE(hpRasterizerState);
//↓初期化
SAFE_RELEASE(hpRenderTargetView);
SAFE_RELEASE(hpBackBuffer);
SAFE_RELEASE(hpDXGISwpChain);
SAFE_RELEASE(hpDeviceContext);
SAFE_RELEASE(hpDevice);
return 0;
}
#include <d3d11.h>モデルデータの必要なデータを正確に出し入れできるようにする事が目的の部分です
#include <xnamath.h>
#define D3DX_PI ((FLOAT) 3.141592654f)
#define D3DXToRadian( degree ) ((degree) * (D3DX_PI / 180.0f))
class modeldata{
public:
static const int MAX_MODEL_ID = 256*256; //最大セット可能モデルデータ
static const int MAX_INDEX = 256*256*256; //最大インデックス数
static const int MAX_VECTOR = 256*256*256; //最大頂点数
static const int MAX_VTX_BUF = 256; //最大頂点バッファー
static const int MAX_IDX_BUF = 256; //最大インデックスバッファー
static const int MAX_TEXTURE = 128; //最大テクスチャー枚数(制限がコレっぽいが,今ひとつ確証は持てない)
static const int MAX_OBJET = 256; //最大セット可能なオブジェデータ
static const int MAX_CAMERA = 1; //とりあえずカメラは1台だけ
//頂点バッファー保存場所
ID3D11Buffer *vctBuf[MAX_VTX_BUF];
//インデックスバッファー保存場所
ID3D11Buffer *idxBuf[MAX_IDX_BUF];
private:
//管理用変数
int datYes[MAX_MODEL_ID]; //データが存在するか?
int drawYes[MAX_MODEL_ID]; //描画するか?
//モデルデータ保管用
//モデルデータヘッダー情報
int idxCnt[MAX_MODEL_ID]; //インデックス数
int idxSta[MAX_MODEL_ID]; //インデックス開始番号
int vctCnt[MAX_MODEL_ID]; //頂点数
int texCnt[MAX_MODEL_ID]; //テクスチャー数(最大1枚)
int texSta[MAX_MODEL_ID]; //テクスチャーデータ開始番号
int psNum[MAX_MODEL_ID]; //ピクセルシェーダー番号
int objNum[MAX_MODEL_ID]; //オブジェ番号
int vctBufNum[MAX_MODEL_ID]; //頂点バッファー番号
int idxBufNum[MAX_MODEL_ID]; //インデックスバッファー番号
//オブジェ管理データ
XMMATRIX objWld[MAX_OBJET];
//テクスチャーデータ保存場所
//ピクセルシェーダーHLSL的に,各モデルデータには1つだけしかテクスチャーを扱えない
ID3D11ShaderResourceView *texSRV[MAX_TEXTURE][1];
//カメラ用情報
float camEye[MAX_CAMERA][4]; //カメラの位置
float camAt[MAX_CAMERA][4]; //焦点の位置
float camUp[MAX_CAMERA][4]; //上の向き
float camFov[MAX_CAMERA][4]; //パースペクティブ射影行列作成
public:
//コンストラクタ
modeldata();
//デストラクタ
~modeldata();
//新しいモデルデータを生成
int newData();
//描画フラグを変更(モデルID, 0:描画しない/1:描画する)
void setDrawYes(int,int);
//保管モデルデータ最大数取得
int getMaxModelId(void);
//データが存在するかを返す
int getDatYes(int);
//描画するかを返す
int getDrawYes(int);
//頂点データ用メソッド郡
//頂点数をセット(モデルID,頂点数)
void setVctCnt(int,int);
//保管頂点バッファーデータ最大数取得
int getMaxVctBufNum(void);
//頂点バッファー番号をセット
void setVctBufNum(int,int);
//頂点バッファー番号を返す
int getVctBufNum(int);
//インデックスデータ用メソッド郡
//インデックス数をセット(モデルID,頂点数)
void setIdxCnt(int,int);
//インデックスデータ開始番号をセット(モデルID,開始番号)
void setIdxSta(int,int);
//インデックス数を返す(モデルID)
int getIdxCnt(int);
//インデックス開始番号を返す(モデルID)
int getIdxSta(int);
//保管頂点インデックスバッファーデータ最大数取得
int getMaxIdxBufNum(void);
//インデックスバッファー番号をセット
void setIdxBufNum(int,int);
//インデックスバッファー番号を返す
int getIdxBufNum(int);
//テクスチャーデータ用メソッド郡
//セットされている最大のテクスチャー番号を返す(次の開始位置が返る)
int getTexMax(void);
//テクスチャー数をセット(モデルID,頂点数)
void setTexCnt(int,int);
//テクスチャーデータ開始番号をセット(モデルID,開始番号)
void setTexSta(int,int);
//テクスチャーデータをセット(テクスチャー番号,カウント,テクスチャーデータ)
void setTexSRV(int,int,ID3D11ShaderResourceView*);
//テクスチャーデータを返す(テクスチャー番号,カウント)
ID3D11ShaderResourceView *getTexSRV(int,int);
//ピクセルシェーダー番号セット(モデルID,0:マテリアル/1:テクスチャー)
void setPsNum(int,int);
//テクスチャー開始番号を返す(モデルID)
int getTexSta(int);
//ピクセルシェーダー番号を返す(モデルID)
int getPsNum(int);
//カメラ用メソッド郡
void setCamEye(int,float,float,float,float);
void setCamAt(int,float,float,float,float);
void setCamUp(int,float,float,float,float);
void setCamFov(int,float,float,float,float);
//ビューを計算して返す
XMMATRIX getCamView(int);
//プロジェクションを計算して返す
XMMATRIX getProjection(int);
//オブジェ用メソッド郡
//セットされている最大のオブジェ番号を返す(次の開始位置が返る)
int getObjMax(void);
void setObjNum(int,int);
int getObjNum(int);
//ワールド座標を取得
XMMATRIX getObjWld(int);
//初期化(オブジェ番号)
void setObjIdentity(int);
//移動(オブジェ番号,X,Y,Z)
void setObjTranslation(int,float,float,float);
};
#include "modeldata.h"ついでに,カメラデータの管理も組み込みました
#include <windows.h>
//コンストラクタ
modeldata::modeldata()
{
for(int mdcnt=0; mdcnt < MAX_MODEL_ID; mdcnt++){
datYes[mdcnt] = 0; //データは存在しない
drawYes[mdcnt] = 0; //描画しない
idxCnt[mdcnt] = 0;
idxSta[mdcnt] = 0;
vctCnt[mdcnt] = 0;
texCnt[mdcnt] = 0;
texSta[mdcnt] = 0;
psNum[mdcnt] = 0;
objNum[mdcnt] = 0;
vctBufNum[mdcnt] = 0;
idxBufNum[mdcnt] = 0;
}
}
//デストラクタ
modeldata::~modeldata()
{
}
//新しいモデルデータを生成
int modeldata::newData(){
for(int mdcnt=0; mdcnt < MAX_MODEL_ID; mdcnt++){
if(datYes[mdcnt] == 0){
datYes[mdcnt] = 1; //データは存在する
return mdcnt; //生成したモデルデータのカウントを返す
}
}
return -1; //生成エラー
}
//描画フラグを変更(モデルID, 0:描画しない/1:描画する)
void modeldata::setDrawYes(int modelId, int flag){
drawYes[modelId] = flag;
}
//頂点数をセット(モデルID,頂点数)
void modeldata::setVctCnt(int modelId, int hVctCnt){
vctCnt[modelId] = hVctCnt;
}
//保管頂点バッファーデータ最大数取得
int modeldata::getMaxVctBufNum(void){
//最終位置を探す
int hMaxVctBufNum = 0;
for(int i=0; i < MAX_MODEL_ID; i++){
if(hMaxVctBufNum < vctBufNum[i]){
hMaxVctBufNum = vctBufNum[i];
}
}
//次の値にする
hMaxVctBufNum++;
return hMaxVctBufNum;
}
//頂点バッファー番号をセット
void modeldata::setVctBufNum(int modelId, int hVctBufNum){
vctBufNum[modelId] = hVctBufNum;
}
//頂点バッファー番号を返す
int modeldata::getVctBufNum(int modelId){
return vctBufNum[modelId];
}
//保管モデルデータ最大数取得
int modeldata::getMaxModelId(){
return MAX_MODEL_ID;
}
//データが存在するかを返す
int modeldata::getDatYes(int hIdxNum){
return datYes[hIdxNum];
}
//描画するかを返す
int modeldata::getDrawYes(int hIdxNum){
return drawYes[hIdxNum];
}
//インデックス数をセット(モデルID,頂点数)
void modeldata::setIdxCnt(int modelId, int hIdxCnt){
idxCnt[modelId] = hIdxCnt;
}
//インデックスデータ開始番号をセット(モデルID,開始番号)
void modeldata::setIdxSta(int modelId, int hIdxSta){
idxSta[modelId] = hIdxSta;
}
//保管インデックスバッファーデータ最大数取得
int modeldata::getMaxIdxBufNum(void){
//最終位置を探す
int hMaxIdxBufNum = 0;
for(int i=0; i < MAX_MODEL_ID; i++){
if(hMaxIdxBufNum < idxBufNum[i]){
hMaxIdxBufNum = idxBufNum[i];
}
}
//次の値にする
hMaxIdxBufNum++;
return hMaxIdxBufNum;
}
//インデックスバッファー番号をセット
void modeldata::setIdxBufNum(int modelId, int hIdxBufNum){
idxBufNum[modelId] = hIdxBufNum;
}
//インデックスバッファー番号を返す
int modeldata::getIdxBufNum(int modelId){
return idxBufNum[modelId];
}
//セットされている最大のテクスチャー番号を返す(次の開始位置が返る)
int modeldata::getTexMax(void){
//最終位置を探す
int hMaxTexSta = 0;
int hMaxTexCnt = 0;
for(int i=0; i < MAX_MODEL_ID; i++){
if(hMaxTexSta < texSta[i]){
hMaxTexSta = texSta[i];
hMaxTexCnt = texCnt[i];
}
}
//それに,それ自身の頂点数を加算した値がラスト
hMaxTexSta += hMaxTexCnt;
return hMaxTexSta;
}
//テクスチャーをセット(モデルID,テクスチャー数)
void modeldata::setTexCnt(int modelId, int hTexCnt){
texCnt[modelId] = hTexCnt;
}
//テクスチャーデータ開始番号をセット(モデルID,開始番号)
void modeldata::setTexSta(int modelId, int hTexSta){
texSta[modelId] = hTexSta;
}
//テクスチャーデータをセット(モデルid,テクスチャーID,テクスチャーデータ)
void modeldata::setTexSRV(int modelId, int id, ID3D11ShaderResourceView* hSRV){
texSRV[modelId][id] = hSRV;
}
//テクスチャーデータを返す(モデルid,テクスチャーID)
ID3D11ShaderResourceView *modeldata::getTexSRV(int modelId, int id){
return texSRV[modelId][id];
}
//ピクセルシェーダー番号セット(モデルID,0:マテリアル/1:テクスチャー)
void modeldata::setPsNum(int modelId,int hPsNum){
psNum[modelId] = hPsNum;
}
//インデックス数を返す
int modeldata::getIdxCnt(int hIdxNum){
return idxCnt[hIdxNum];
}
//インデックス開始番号を返す
int modeldata::getIdxSta(int hIdxNum){
return idxSta[hIdxNum];
}
//テクスチャー開始番号を返す(モデルID)
int modeldata::getTexSta(int hIdxNum){
return texSta[hIdxNum];
}
//ピクセルシェーダー番号を返す(モデルID)
int modeldata::getPsNum(int hIdxNum){
return psNum[hIdxNum];
}
//カメラ用メソッド郡PMDデータを読み込むプログラムのヘッダーです
void modeldata::setCamEye(int hCamNum,float hEyeX,float hEyeY,float hEyeZ,float hEyeW){
camEye[hCamNum][0] = hEyeX;
camEye[hCamNum][1] = hEyeY;
camEye[hCamNum][2] = hEyeZ;
camEye[hCamNum][3] = hEyeW;
}
void modeldata::setCamAt(int hCamNum,float hAtX,float hAtY,float hAtZ,float hAtW){
camAt[hCamNum][0] = hAtX;
camAt[hCamNum][1] = hAtY;
camAt[hCamNum][2] = hAtZ;
camAt[hCamNum][3] = hAtW;
}
void modeldata::setCamUp(int hCamNum,float hUpX,float hUpY,float hUpZ,float hUpW){
camUp[hCamNum][0] = hUpX;
camUp[hCamNum][1] = hUpY;
camUp[hCamNum][2] = hUpZ;
camUp[hCamNum][3] = hUpW;
}
void modeldata::setCamFov(int hCamNum,float hFovAngY,float hAspHByW,float hNearZ,float hFarZ){
camFov[hCamNum][0] = hFovAngY;
camFov[hCamNum][1] = hAspHByW;
camFov[hCamNum][2] = hNearZ;
camFov[hCamNum][3] = hFarZ;
}
//ビューを計算して返す
XMMATRIX modeldata::getCamView(int hCamNum){
XMVECTOR hEye = XMVectorSet(camEye[hCamNum][0], camEye[hCamNum][1], camEye[hCamNum][2], camEye[hCamNum][3]); //カメラ
XMVECTOR hAt = XMVectorSet(camAt[hCamNum][0], camAt[hCamNum][1], camAt[hCamNum][2], camAt[hCamNum][3]); //焦点の位置
XMVECTOR hUp = XMVectorSet(camUp[hCamNum][0], camUp[hCamNum][1], camUp[hCamNum][2], camUp[hCamNum][3]);
XMMATRIX hView = XMMatrixLookAtLH(hEye, hAt, hUp);
return XMMatrixTranspose(hView);
}
//プロジェクションを計算して返す
XMMATRIX modeldata::getProjection(int hCamNum){
XMMATRIX hProjection = XMMatrixPerspectiveFovLH(D3DXToRadian(camFov[hCamNum][0]), camFov[hCamNum][1], camFov[hCamNum][2], camFov[hCamNum][3]);
return XMMatrixTranspose(hProjection);
}
//オブジェ用メソッド郡
//セットされている最大のオブジェ番号を返す(次の開始位置が返る)
int modeldata::getObjMax(void){
//最大のオブジェ番号を探す
int hMaxObj = 0;
for(int i=0; i < MAX_MODEL_ID; i++){
if(hMaxObj < objNum[i]){
hMaxObj = objNum[i];
}
}
//次の開始位置にする
hMaxObj++;
return hMaxObj;
}
void modeldata::setObjNum(int hIdxNum,int hObjNum){
objNum[hIdxNum] = hObjNum;
}
int modeldata::getObjNum(int hIdxNum){
return objNum[hIdxNum];
}
//ワールド座標を取得
XMMATRIX modeldata::getObjWld(int hObjNum){
return XMMatrixTranspose(objWld[hObjNum]);
}
//初期化(オブジェ番号)
void modeldata::setObjIdentity(int hObjNum){
objWld[hObjNum] = XMMatrixIdentity();
}
//移動(オブジェ番号,X,Y,Z)
void modeldata::setObjTranslation(int hObjNum,float hX,float hY,float hZ){
XMMATRIX hMatrix = XMMatrixTranslation(hX, hY, hZ);
objWld[hObjNum] = XMMatrixMultiply(objWld[hObjNum], hMatrix);
}
class pmd{PMDデータを読み込むプログラム部分です
public:
#pragma pack(push,1) //アラインメント制御をオフる
//ヘッダー
struct t_header{
unsigned char magic[3];
float version;
unsigned char model_name[20];
unsigned char comment[256];
};
t_header header;
//頂点リスト
unsigned long vert_count;
struct t_vertex{
float pos[3];
float normal_vec[3];
float uv[2];
unsigned short bone_num[2];
unsigned char bone_weight;
unsigned char edge_flag;
};
t_vertex *vertex;
//面頂点リスト
unsigned long face_vert_count;
unsigned short *face_vert_index;
//材質リスト
unsigned long material_count;
struct t_material{
float diffuse_color[3];
float alpha;
float specularity;
float specular_color[3];
float mirror_color[3];
unsigned char toon_index;
unsigned char edge_flag;
unsigned long face_vert_count;
char texture_file_name[20];
};
t_material *material;
#pragma pack(pop) //アラインメント制御エンド
//コンストラクタ
pmd(char *);
//デストラクタ
~pmd();
};
#include "pmd.h"頂点シェーダーHLSLです
#include <windows.h>
#include <stdio.h>
//コンストラクタ
pmd::pmd(char *filename)
{
FILE *hFP;
hFP = fopen(filename, "rb");
if(hFP != 0){
//ヘッダー読み込み
fread(&header, sizeof(struct t_header), 1, hFP);
//頂点数読み込み
fread(&vert_count, sizeof(vert_count), 1, hFP);
//頂点データ読み込み
vertex = new t_vertex[vert_count];
fread(vertex, 38, vert_count, hFP);
//面頂点リスト読み込み
fread(&face_vert_count, sizeof(face_vert_count), 1, hFP);
//面頂点リストデータ読み込み
face_vert_index = new unsigned short[face_vert_count];
fread(face_vert_index, 2, face_vert_count, hFP);
//材質リスト材質数
fread(&material_count, sizeof(material_count), 1, hFP);
//材質リストデータ読み込み
material = new t_material[material_count];
fread(material, 70, material_count, hFP);
fclose(hFP);
}else{
MessageBoxW(NULL, L"fopen", L"Err", MB_ICONSTOP);
}
}
//デストラクタ
pmd::~pmd(void)
{
delete [] vertex;
delete [] face_vert_index;
delete [] material;
}
"C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Utilities\bin\x64\fxc.exe" vs.fx /T vs_4_0 /E vs_main /Fh vs.h・vs.fx
//入力用ピクセルシェーダーのHLSLです
struct vertexIn
{
float4 pos : POSITION0;
float4 col : COLOR0;
float2 tex : TEXCOORD0;
};
//出力用
struct vertexOut
{
float4 pos : SV_POSITION;
float4 col : COLOR;
float2 tex : TEXCOORD0;
};
//変換用行列
cbuffer ConstantBuffer : register(b0)
{
matrix World; //ワールド変換行列
matrix View; //ビュー変換行列
matrix Projection; //透視射影変換行列
}
vertexOut vs_main(vertexIn IN)
{
vertexOut OUT;
OUT.pos = mul(IN.pos, World);
OUT.pos = mul(OUT.pos, View);
OUT.pos = mul(OUT.pos, Projection);
OUT.col = IN.col;
OUT.tex = IN.tex;
return OUT;
}
"C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Utilities\bin\x64\fxc.exe" ps.fx /T ps_4_0 /E ps_main /Fh ps.h今までのソースをまとめて実行すると,こういう風に描画されます
"C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Utilities\bin\x64\fxc.exe" ps.fx /T ps_4_0 /E ps_main2 /Fh ps_2.h
//入力用
struct pixcelIn
{
float4 pos : SV_POSITION;
float4 col : COLOR;
float2 tex : TEXCOORD0;
};
Texture2D txDiffuse : register(t0);
SamplerState samLinear : register(s0);
float4 ps_main(pixcelIn IN) : SV_Target
{
pixcelIn OUT;
OUT.col = txDiffuse.Sample(samLinear, IN.tex);
//なんか妙に明るくなるので,少し暗くする
OUT.col.r -= 0.3f;
OUT.col.g -= 0.3f;
OUT.col.b -= 0.3f;
return OUT.col;
}
float4 ps_main2(pixcelIn IN) : SV_Target
{
pixcelIn OUT;
//カラーをそのまま返す
OUT.col = IN.col;
//なんか妙に明るくなるので,少し暗くする
OUT.col.r -= 0.3f;
OUT.col.g -= 0.3f;
OUT.col.b -= 0.3f;
return OUT.col;
}