I'm trying to render a model in OBJ file format with DirectX. I'm using simple cube model, but I get some really strange results(picture below)
I've tried to render a cube by filling vertecies array manually and it worked pretty good. After studing OBJ file format I've thougth that I should do the similar thing, but I don't understand why this is not working.
Sending two functions and structs descriptions:
HRESULT RenderDevice::initGeometry() {
///////READING INFO FROM FILE//////////
ifstream *inp = new ifstream("test.obj");
ofstream *out = new ofstream("result.txt");
char str[256];
while (!inp->eof()) {
inp->getline(str, 256);
meshInfo.coord.push_back(new std::string(str));
}
HRESULT hr = S_OK;
ID3DBlob *pVSBlob = NULL;
hr = compileShaderFromFile(L"texture.fx", "VS", "vs_4_0", &pVSBlob);
if (FAILED(hr)) {
MessageBox(NULL, L"Can't compile Vertex Shader", L"Error", MB_OK);
return hr;
}
hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);
if (FAILED(hr)) {
pVSBlob->Release();
return hr;
}
D3D11_INPUT_ELEMENT_DESC layout[] = {
{"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}
};
UINT numElemenets = ARRAYSIZE(layout);
hr = g_pd3dDevice->CreateInputLayout(layout, numElemenets, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &g_pVertexLayout);
pVSBlob->Release();
if (FAILED(hr)) {
return hr;
}
g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
ID3DBlob *pPSBlob = NULL;
hr = compileShaderFromFile(L"texture.fx", "PS", "ps_4_0", &pPSBlob);
if (FAILED(hr)) {
MessageBox(NULL, L"Can't compile Pixel Shader", L"Error", MB_OK);
return hr;
}
hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);
pPSBlob->Release();
if (FAILED(hr)) {
return hr;
}
pPSBlob = NULL;
hr = compileShaderFromFile(L"texture.fx", "PSSolid", "ps_4_0", &pPSBlob);
if (FAILED(hr)) {
MessageBox(NULL, L"Can't compile Solid Pixel Shader", L"Error", MB_OK);
return hr;
}
hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShaderSolid);
pPSBlob->Release();
if (FAILED(hr)) {
return hr;
}
/////////SPLITING INFO INTO DIFFERENT VECTORS/////////////////
for (int i = 0; i < meshInfo.coord.size(); i++) {
if (meshInfo.coord[i]->c_str()[0] == 'v' && meshInfo.coord[i]->c_str()[1] != 'n') {
float tmpx, tmpy, tmpz;
sscanf_s(meshInfo.coord[i]->c_str(), "v %f %f %f", &tmpx, &tmpy, &tmpz);
meshInfo.positions.push_back(XMFLOAT3(tmpx, tmpy, tmpz));
} else if (meshInfo.coord[i]->c_str()[0] == 'v' && meshInfo.coord[i]->c_str()[1] == 'n') {
float tmpx, tmpy, tmpz;
sscanf_s(meshInfo.coord[i]->c_str(), "vn %f %f %f", &tmpx, &tmpy, &tmpz);
meshInfo.normals.push_back(XMFLOAT3(tmpx, tmpy, tmpz));
} else if (meshInfo.coord[i]->c_str()[0] == 'f') {
int iX, iY, iZ, nX, nY, nZ;
sscanf_s(meshInfo.coord[i]->c_str(), "f %d//%d %d//%d %d//%d", &iX, &nX, &iY, &nY, &iZ, &nZ);
meshInfo.indexiesPoints.push_back(iX);
meshInfo.indexiesPoints.push_back(iY);
meshInfo.indexiesPoints.push_back(iZ);
meshInfo.indexiesNormals.push_back(nX);
meshInfo.indexiesNormals.push_back(nY);
meshInfo.indexiesNormals.push_back(nZ);
}
}
meshInfo.indexiesAmount = meshInfo.indexiesPoints.size();
meshInfo.vertexAmount = meshInfo.positions.size();
meshInfo.normalsAmount = meshInfo.normals.size();
Vertex *vertices = new Vertex[meshInfo.indexiesAmount];
//////////////FILLING VERTECIES ARRAY///////////////
for (int i = 0; i < meshInfo.indexiesAmount; i++) {
vertices[i].normal.x = meshInfo.normals[meshInfo.indexiesNormals[i] - 1].x;
vertices[i].normal.y = meshInfo.normals[meshInfo.indexiesNormals[i] - 1].y;
vertices[i].normal.z = meshInfo.normals[meshInfo.indexiesNormals[i] - 1].z;
vertices[i].pos.x = meshInfo.positions[meshInfo.indexiesPoints[i] - 1].x;
vertices[i].pos.y = meshInfo.positions[meshInfo.indexiesPoints[i] - 1].y;
vertices[i].pos.z = meshInfo.positions[meshInfo.indexiesPoints[i] - 1].z;
}
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(Vertex) * meshInfo.indexiesAmount;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA initData;
ZeroMemory(&initData, sizeof(initData));
initData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer(&bd, &initData, &g_pVertexBuffer);
if (FAILED(hr)) {
return hr;
}
///////////////////FILLING INIXIES ARRAY///////////////////
WORD *indixies = new WORD[meshInfo.indexiesAmount];
for (int i = 0; i < meshInfo.indexiesAmount; i++) {
indixies[i] = meshInfo.indexiesPoints[i];
}
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(int) * meshInfo.indexiesAmount;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
initData.pSysMem = indixies;
hr = g_pd3dDevice->CreateBuffer(&bd, &initData, &g_pIndexBuffer);
if (FAILED(hr)) {
return hr;
}
UINT stride = sizeof(Vertex);
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBuffer);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
hr = g_pd3dDevice->CreateBuffer(&bd, NULL, &g_pCBMatrixes);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
void RenderDevice::render() {
float clearColor[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, clearColor);
g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
updateLigth();
for (int i = 0; i < 6; i++) {
updateMatrix(MX_SETWORLD, i * (XM_PI * 2) / 6);
g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pCBMatrixes);
g_pImmediateContext->VSSetConstantBuffers(1, 1, &g_pCBLigth);
g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pCBMatrixes);
g_pImmediateContext->PSSetConstantBuffers(1, 1, &g_pCBLigth);
g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
g_pImmediateContext->DrawIndexed(meshInfo.indexiesAmount, 0, 0);
}
g_pImmediateContext->PSSetShader(g_pPixelShaderSolid, NULL, 0);
for (int m = 0; m < 2; m++) {
updateMatrix(m, 0);
g_pImmediateContext->DrawIndexed(meshInfo.indexiesAmount, 0, 0);
}
g_pSwapChain->Present(0, 0);
}
typedef struct Vertex {
XMFLOAT3 pos;
XMFLOAT3 normal;
}Vertex;
typedef struct MeshInfo {
int vertexAmount;
int normalsAmount;
vector<XMFLOAT3> positions;
vector<XMFLOAT3> normals;
vector<string*> coord;
vector<int> indexiesPoints;
vector<int> indexiesNormals;
int indexiesAmount;
}MeshInfo;
typedef struct ConstantBuffer {
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
XMFLOAT4 vLigthDir[2];
XMFLOAT4 vLigthColor[2];
XMFLOAT4 vOutputColor;
}ConstantBuffer;
I expect to see 6 cubes in my program's window, but I get this thing
I've actually found a solution to my problem. The main problem was to make a correct order for vertecies to draw. But in .OBJ files only UNIQUE vertices, normals and texture coordinates are written. Also they are separated from each other (for example it can be 8 UNIQUE vertex coordinates and 6 UNIQUE normals coordinates). The main thing is happening in part, where are faces are described. Each face is pointing to a specific index of position, normal and texture coordinate, meaning that we can use same normals, positions and texture coordinates different times(I know it's obviously). And I realised that in my realisation I don't need indexies array at all, because Vertecies array, that I've filled up was already a model! And I ended up using method Draw instead of DrawIndexed in ID3D11DeviceContext.