#include "pch.h"
#include "Sample3DSceneRenderer.h"
#include "..\Common\DirectXHelper.h"
using namespace App1;
using namespace DirectX;
using namespace Windows::Foundation;
using namespace concurrency;
using namespace Windows::Storage;
Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
m_loadingComplete(false),
m_degreesPerSecond(45),
m_indexCount(0),
m_tracking(false),
m_Resources(deviceResources)
{
CreateDeviceDependentResources();
CreateWindowSizeDependentResources();
m_Device = m_Resources->GetD3DDevice();
m_Context = m_Resources->GetD3DDeviceContext();
BasicReaderWriter^ reader = ref new BasicReaderWriter();
Array<byte>^ buf = reader->ReadData("ConeColor.x");
//Array<byte>^ buf = reader->ReadData("gal2.x");
SetByte(buf);
}
void Sample3DSceneRenderer::CreateWindowSizeDependentResources()
{
Size outputSize = m_Resources->GetOutputSize();
float aspectRatio = outputSize.Width / outputSize.Height;
float fovAngleY = 70.0f * XM_PI / 180.0f;
if (aspectRatio < 1.0f)
{
fovAngleY *= 2.0f;
}
XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH(
fovAngleY,
aspectRatio,
0.01f,
100.0f
);
XMFLOAT4X4 orientation = m_Resources->GetOrientationTransform3D();
XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);
XMStoreFloat4x4(
&m_constantBufferData.projection,
XMMatrixTranspose(perspectiveMatrix * orientationMatrix)
);
//static const XMVECTORF32 eye = { 0.0f, 0.7f, 2.0f, 0.0f };
static const XMVECTORF32 eye = { 0.0f, 0.7f, 4.0f, 0.0f };
static const XMVECTORF32 at = { 0.0f, -0.1f, 0.0f, 0.0f };
static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };
XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
}
void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
{
if (!m_tracking)
{
float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
double totalRotation = timer.GetTotalSeconds() * radiansPerSecond;
float radians = static_cast<float>(fmod(totalRotation, XM_2PI));
Rotate(radians);
}
}
void Sample3DSceneRenderer::Rotate(float radians)
{
//更新されたモデル マトリックスをシェーダーに渡す準備をします
XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(radians)));
}
void Sample3DSceneRenderer::StartTracking()
{
m_tracking = true;
}
void Sample3DSceneRenderer::TrackingUpdate(float positionX)
{
if (m_tracking)
{
float radians = XM_2PI * 2.0f * positionX / m_Resources->GetOutputSize().Width;
Rotate(radians);
}
}
void Sample3DSceneRenderer::StopTracking()
{
m_tracking = false;
}
// 頂点とピクセル シェーダーを使用して、1 つのフレームを描画します。
void Sample3DSceneRenderer::Render()
{
if (!m_loadingComplete) { return; }
//auto context = m_deviceResources->GetD3DDeviceContext();
// レンダー ターゲットを画面に設定します。
ID3D11RenderTargetView *const targets[1] = { m_Resources->GetBackBufferRenderTargetView() };
m_Context->OMSetRenderTargets(1, targets, m_Resources->GetDepthStencilView());
// 定数バッファーを準備して、グラフィックス デバイスに送信します。
m_Context->UpdateSubresource(
m_constantBuffer.Get(),
0,
NULL,
&m_constantBufferData,
0,
0
);
UINT stride = sizeof(VertexPosition);
UINT offset = 0;
m_Context->IASetVertexBuffers(
0,
1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset
);
m_Context->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0
);
// カリング設定
D3D11_RASTERIZER_DESC rasterizerDesc;
ZeroMemory( &rasterizerDesc, sizeof( D3D11_RASTERIZER_DESC ) );
//rasterizerDesc.CullMode = D3D11_CULL_BACK;
rasterizerDesc.CullMode = D3D11_CULL_FRONT;
rasterizerDesc.FillMode = D3D11_FILL_SOLID;
rasterizerDesc.DepthClipEnable = FALSE;
rasterizerDesc.MultisampleEnable = TRUE;
rasterizerDesc.DepthBiasClamp = 0;
rasterizerDesc.SlopeScaledDepthBias = 0;
DX::ThrowIfFailed(
m_Device->CreateRasterizerState(
&rasterizerDesc, &m_RasterizerState));
m_Context->RSSetState(m_RasterizerState);
m_Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_Context->IASetInputLayout(m_inputLayout.Get());
// 頂点シェーダーをアタッチします。
m_Context->VSSetShader(
m_vertexShader.Get(),
nullptr,
0
);
// 定数バッファーをグラフィックス デバイスに送信します。
m_Context->VSSetConstantBuffers(
0,
1,
m_constantBuffer.GetAddressOf()
);
// ピクセル シェーダーをアタッチします。
m_Context->PSSetShader(
m_pixelShader.Get(),
nullptr,
0
);
// オブジェクトを描画します。
m_Context->DrawIndexed(
m_indexCount,
0,
0
);
}
void Sample3DSceneRenderer::ReleaseDeviceDependentResources()
{
m_loadingComplete = false;
m_vertexShader.Reset();
m_inputLayout.Reset();
m_pixelShader.Reset();
m_constantBuffer.Reset();
m_vertexBuffer.Reset();
m_indexBuffer.Reset();
}
void Sample3DSceneRenderer::CreateDeviceDependentResources()
{
// シェーダーを非同期で読み込みます。
auto loadVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso");
auto loadPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso");
// 頂点シェーダー ファイルを読み込んだ後、シェーダーと入力レイアウトを作成します。
auto createVSTask = loadVSTask.then([this](const std::vector<byte>& fileData) {
DX::ThrowIfFailed(
m_Device->CreateVertexShader(
&fileData[0],
fileData.size(),
nullptr,
&m_vertexShader
)
);
static const D3D11_INPUT_ELEMENT_DESC vertexDesc [] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
DX::ThrowIfFailed(
m_Device->CreateInputLayout(
vertexDesc,
ARRAYSIZE(vertexDesc),
&fileData[0],
fileData.size(),
&m_inputLayout
)
);
});
// ピクセル シェーダー ファイルを読み込んだ後、シェーダーと定数バッファーを作成します。
auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) {
DX::ThrowIfFailed(
m_Device->CreatePixelShader(
&fileData[0],
fileData.size(),
nullptr,
&m_pixelShader
)
);
CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer) , D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_Device->CreateBuffer(
&constantBufferDesc,
nullptr,
&m_constantBuffer
)
);
});
// メッシュが読み込まれたら、オブジェクトを描画する準備が完了します。
createPSTask.then([this]() { m_loadingComplete = true; });
}
//★ 入力した X-FILE TEXT(モデルデータ)を受け取って解析
void Sample3DSceneRenderer::SetByte(Array<byte>^ text)
{
int num, pt, pw;
char *w;
w = (char *)&(text[0]);
m_x = w;
// String を行で切り分ける(m_x⇒VT)
VT.clear();
num = m_x.size();
for (pt = 0; pt<num;)
{
pw = pt;
for (pt++; pt<num && m_x[pt] != '\n'; pt++);
if (pt >= num) break;
pt++;
Word = Word.assign(m_x, pw, pt - pw);
VT.push_back(Word);
}
VT.push_back("}\r\n");
VT_size = VT.size();
// Header Check("xof 0303txt 0032")
m_Col= VT[0].find("xof");
if (m_Col==-1)
{ return;
}
m_Col= VT[0].find("txt");
if (m_Col==-1)
{ return;
}
// template をスキップ
m_Line= 1;
m_Col= 0;
while(true)
{ Token();
if (Word!="template") break;
Search("}");
m_Line++;
}
m_Top= m_Line;
// Material(MTBL)を取得
SetMTBL();
// 頂点座標を取得
m_pos.clear();
m_Line = m_Top;
if (SetXMFLOAT3("Mesh ", &m_pos))
{
SetFTBL();
}
else
{ OutputDebugString(L"Mesh File Format Error\r\n");
return;
}
// 法線を取得
m_norm.clear();
m_Line = m_Top;
m_normflag = false;
if (SetXMFLOAT3("MeshNormals ", &m_norm))
{
m_normflag = SetNorm();
}
// MeshMaterialList を取得
MatList();
// Face 構造体の FTBL ⇒ POL3
Convt_3P(m_normflag);
//★ pos, norm, color を組み合わせて、モデルの頂点座標を作成
m_indexCount = POL3.size()*3;
VertexPosition *Vertices = new VertexPosition[m_indexCount];
unsigned short *Indices = new unsigned short[m_indexCount];
for(unsigned i=0; i<POL3.size(); i++)
{ for(unsigned j=0; j<3; j++)
{ Vertices[i*3+j].pos = m_pos[POL3[i].Pos[j]];
if (m_normflag) Vertices[i*3+j].norm = m_norm[POL3[i].Norm[j]];
else Vertices[i*3+j].norm= XMFLOAT3(0.0f, 0.0f, 0.0f);
//Vertices[i*3+j].color= XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);
int idx= POL3[i].Midx;
if (idx != -1)
{
Vertices[i * 3 + j].color.x = MTBL[idx].faceColor.x;
Vertices[i * 3 + j].color.y = MTBL[idx].faceColor.y;
Vertices[i * 3 + j].color.z = MTBL[idx].faceColor.z;
Vertices[i * 3 + j].color.w = 1.0f;
}
else
Vertices[i*3+j].color= XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
Indices[i*3+j]= i*3+j;
}
}
// 法線ベクトルの計算
if (m_normflag==false)
ComputeNorm(Vertices, m_indexCount);
// 頂点データをフレームバッファに転送
D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
vertexBufferData.pSysMem = Vertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(VertexPosition)*m_indexCount, D3D11_BIND_VERTEX_BUFFER);
DX::ThrowIfFailed(
m_Device->CreateBuffer(
&vertexBufferDesc, &vertexBufferData, &m_vertexBuffer));
// インデックスデータをフレームバッファに転送
D3D11_SUBRESOURCE_DATA indexBufferData = {0};
indexBufferData.pSysMem = Indices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(unsigned short)*m_indexCount, D3D11_BIND_INDEX_BUFFER);
DX::ThrowIfFailed(
m_Device->CreateBuffer(
&indexBufferDesc, &indexBufferData, &m_indexBuffer));
// 領域の解放
if (Vertices) delete Vertices;
if (Indices) delete Indices;
}
//★ X-FILE 解析関数
// Line, Col から次の Token を取得 ⇒ Word に設定(Line 行だけ検索)
bool Sample3DSceneRenderer::LineToken()
{
int wk;
Word= "";
if (m_Col>=(int)VT[m_Line].size()) return false;
wk= VT[m_Line].find_first_not_of(" ,;{}\r\n", m_Col);
m_Col= wk;
wk= VT[m_Line].find_first_of(" ,;}\r\n", m_Col);
if (wk>m_Col)
{ Word= Word.assign(VT[m_Line], m_Col, wk-m_Col);
m_Col= wk + 1;
return true;
}
return false;
}
//★ "Material" で始まる行を検索(先頭から順に並ぶ)
void Sample3DSceneRenderer::SetMTBL()
{ Mat mat;
MTBL.clear();
m_Line= m_Top;
while(m_Line<VT_size)
{ Search("Material ");
if (m_Col==-1) break;
LineToken();
LineToken(); // 二回目で名前を取得
mat.matName= Word;
// "Material" に続く色を格納する
m_Line++;
m_Col= 0;
Token();
mat.faceColor.x= (float)atof(Word.data());
Token();
mat.faceColor.y= (float)atof(Word.data());
Token();
mat.faceColor.z= (float)atof(Word.data());
Token();
//mat.faceColor.a= (float)_wtof(Word.data());
//mat.faceColor.w= (float)atof(Word.data());
MTBL.push_back(mat);
}
}
//★ "MeshMaterialList" で始まる行を検索
void Sample3DSceneRenderer::MatList()
{
vector<int> fm; // Face Material
vector<int> midx; // Material(MTBL) の Index
int fcnt,num,i;
unsigned j;
m_Line= m_Top;
Search("MeshMaterialList ");
if (m_Col==-1) return;
m_Line++;
m_Col= 0;
Token();
num= atoi(Word.data());
Token();
fcnt= atoi(Word.data());
if (FTBL.size()!=fcnt)
{ Debug(L"Mesh Face= ", FTBL.size());
Debug(L"MeshMaterialList Face= ", fcnt);
return;
}
// Face に対応する Material番号を設定
for(i=0; i<fcnt; i++)
{ Token();
fm.push_back(atoi(Word.data()));
}
// Material 名で検索して、Material Index を設定
for(i=0; i<num; i++)
{ Token();
if (Word!="Material")
{
for(j=0; j<MTBL.size(); j++)
{ if (MTBL[j].matName==Word) break;
}
if (j<MTBL.size()) midx.push_back(j);
else midx.push_back(j);
}
else midx.push_back(i);
Search("}");
}
// fm, midx を参照して Face ごとの Midx を設定
for(i=0; i<fcnt; i++)
{ FTBL[i].Midx= midx[fm[i]];
}
}
//★ 頂点に続く Index を vector<Face> に格納する
bool Sample3DSceneRenderer::SetFTBL()
{
Face face;
int i,j,num;
unsigned short wk;
FTBL.clear();
Token();
num = atoi(Word.data());
if (num<3)
{ return false; }
face.Midx= -1;
for(i=0; i<num; i++)
{
Token();
face.Num= atoi(Word.data());
face.Pos.clear();
for(j=0; j<face.Num; j++)
{
Token();
wk= atoi(Word.data());
face.Pos.push_back(wk);
}
FTBL.push_back(face);
}
return true;
}
// 法線に続く Index を Face(FTBL) の Norm に格納する
bool Sample3DSceneRenderer::SetNorm()
{
int i,j,num,cn;
unsigned short wk;
Token();
num= atoi(Word.data());
if (FTBL.size()!=num)
{ OutputDebugString(L"MeshNormals Face Count Error");
return false;
}
for(i=0; i<num; i++)
{ Token();
cn= atoi(Word.data());
for(j=0; j<cn; j++)
{
Token();
wk= atoi(Word.data());
FTBL[i].Norm.push_back(wk);
}
}
return true;
}
// vector<Face> FTBL ⇒ vector<Pol3> POL3 TRIANGLELIST に変換
// bool flg は法線ベクトルが定義されているか否かの区別
void Sample3DSceneRenderer::Convt_3P(bool flg)
{ Pol3 pol3;
int i, j;
for(i=0; i<(int)FTBL.size(); i++)
{
pol3.Midx= FTBL[i].Midx;
switch(FTBL[i].Num)
{ case 3: //TRIANGLELIST
pol3.Pos[0]= FTBL[i].Pos[0];
pol3.Pos[1]= FTBL[i].Pos[1];
pol3.Pos[2]= FTBL[i].Pos[2];
if (flg)
{
pol3.Norm[0]= FTBL[i].Norm[0];
pol3.Norm[1]= FTBL[i].Norm[1];
pol3.Norm[2]= FTBL[i].Norm[2];
}
POL3.push_back(pol3);
break;
case 4: //TRIANGLESTRIP 4
pol3.Pos[0]= FTBL[i].Pos[0];
pol3.Pos[1]= FTBL[i].Pos[1];
pol3.Pos[2]= FTBL[i].Pos[2];
if (flg)
{ pol3.Norm[0]= FTBL[i].Norm[0];
pol3.Norm[1]= FTBL[i].Norm[1];
pol3.Norm[2]= FTBL[i].Norm[2];
}
POL3.push_back(pol3);
pol3.Pos[0]= FTBL[i].Pos[0];
pol3.Pos[1]= FTBL[i].Pos[2];
pol3.Pos[2]= FTBL[i].Pos[3];
if (flg)
{ pol3.Norm[0]= FTBL[i].Norm[0];
pol3.Norm[1]= FTBL[i].Norm[2];
pol3.Norm[2]= FTBL[i].Norm[3];
}
POL3.push_back(pol3);
break;
default: //TRIANGLEFAN
for(j=0; j<=FTBL[i].Num-3; j++)
{
pol3.Pos[0]= FTBL[i].Pos[0];
pol3.Pos[1]= FTBL[i].Pos[j+1];
pol3.Pos[2]= FTBL[i].Pos[j+2];
if (flg)
{
pol3.Norm[0]= FTBL[i].Norm[0];
pol3.Norm[1]= FTBL[i].Norm[j+1];
pol3.Norm[2]= FTBL[i].Norm[j+2];
}
POL3.push_back(pol3);
}
break;
}
}
}
|