Related
I wanted to draw a 3D cube, but it doesn't display correctly. That is, the Z buffer (depth buffer) does not work.
The initialization of the depth buffer occurs in the InitDepthBuffer method, which I copied from the manual from Microsoft. The InitDepthBuffer method is called in the InitD3D method below.
Why "cube" is not displayed correctly and how to fix the program?
My Game.cpp
// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>
// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")
// define the screen resolution
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// global declarations
IDXGISwapChain* swapchain; // the pointer to the swap chain interface
ID3D11Device* dev; // the pointer to our Direct3D device interface
ID3D11DeviceContext* devcon; // the pointer to our Direct3D device context
ID3D11RenderTargetView* backbuffer; // the pointer to our back buffer
ID3D11InputLayout* pLayout; // the pointer to the input layout
ID3D11VertexShader* pVS; // the pointer to the vertex shader
ID3D11PixelShader* pPS; // the pointer to the pixel shader
ID3D11Buffer* pVBuffer; // the pointer to the vertex buffer
ID3D11Buffer* pIBuffer;
ID3D11Buffer* wvpConstBuffer;
ID3D11ShaderResourceView* pTexture; // the texture
ID3D11SamplerState* pSamplerState;
ID3D11RasterizerState* pRasterState;
ID3D11Texture2D* pDepthStencil = NULL;
ID3D11DepthStencilState* pDSState;
ID3D11DepthStencilView* pDSV;
// a struct to define a single vertex
struct VERTEX { FLOAT X, Y, Z, texX, texY; };
struct ConstantBuffer
{
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
};
XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection;
// function prototypes
void InitD3D(HWND hWnd); // sets up and initializes Direct3D
void RenderFrame(void); // renders a single frame
void CleanD3D(void); // closes Direct3D and releases memory
void InitGraphics(void); // creates the shape to render
void InitPipeline(void); // loads and prepares the shaders
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"My Game",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
InitD3D(hWnd);
// enter the main loop:
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
}
RenderFrame();
}
// clean up DirectX and COM
CleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void InitDepthBuffer()
{
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = SCREEN_WIDTH;
descDepth.Height = SCREEN_HEIGHT;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
dev->CreateTexture2D(&descDepth, NULL, &pDepthStencil);
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dev->CreateDepthStencilState(&dsDesc, &pDSState);
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
dev->CreateDepthStencilView(pDepthStencil, // Depth stencil texture
&descDSV, // Depth stencil desc
&pDSV); // [out] Depth stencil view
}
// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = SCREEN_WIDTH; // set the back buffer width
scd.BufferDesc.Height = SCREEN_HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
// get the address of the back buffer
ID3D11Texture2D* pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
InitDepthBuffer();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, pDSV);
devcon->OMSetDepthStencilState(pDSState, 1);
// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = SCREEN_WIDTH;
viewport.Height = SCREEN_HEIGHT;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
devcon->RSSetViewports(1, &viewport);
InitPipeline();
InitGraphics();
}
// this is the function used to render a single frame
void RenderFrame(void)
{
// update WVP matrices
ConstantBuffer cb;
cb.mWorld = XMMatrixTranspose(g_World);
cb.mView = XMMatrixTranspose(g_View);
cb.mProjection = XMMatrixTranspose(g_Projection);
devcon->UpdateSubresource(wvpConstBuffer, 0, NULL, &cb, 0, 0);
// clear the back buffer to a deep blue and the depth buffer
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));
devcon->ClearDepthStencilView(pDSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// select which vertex buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(pIBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->VSSetConstantBuffers(0, 1, &wvpConstBuffer);
// select which primtive type we are using
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// draw the vertex buffer to the back buffer
devcon->DrawIndexed(24, 0, 0);
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
g_World *= XMMatrixRotationY(XM_PI / 12);
Sleep(100);
}
// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
// close and release all existing COM objects
pLayout->Release();
pVS->Release();
pPS->Release();
pVBuffer->Release();
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}
void InitTextures()
{
D3DX11CreateShaderResourceViewFromFile(dev, L"texture.png", NULL, NULL, &pTexture, NULL);
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(D3D11_SAMPLER_DESC));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
dev->CreateSamplerState(&sampDesc, &pSamplerState);
}
// this is the function that creates the shape to render
void InitGraphics()
{
// create a triangle using the VERTEX struct
VERTEX OurVertices[] =
{ // CUBE
{-0.5f, 0.5f, 0.5f, 0.0f, 0.0f}, // Front
{0.5f, 0.5f, 0.5f, 1.0f, 0.0f},
{0.5f, -0.5f, 0.5f, 1.0f, 1.0f},
{-0.5f, -0.5f, 0.5f, 0.0f, 1.0f},
{-0.5f, 0.5f, -0.5f, 1.0f, 0.0f}, // Back
{0.5f, 0.5f, -0.5f, 0.0f, 0.0f},
{0.5f, -0.5f, -0.5f, 0.0f, 1.0f},
{-0.5f, -0.5f, -0.5f, 1.0f, 1.0f},
};
// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC; // write access access by CPU and GPU
bd.ByteWidth = sizeof(OurVertices); // size is the VERTEX struct * 3
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // allow CPU to write in buffer
dev->CreateBuffer(&bd, NULL, &pVBuffer); // create the buffer
// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices)); // copy the data
devcon->Unmap(pVBuffer, NULL); // unmap the buffer
unsigned int indices[] =
{
0, 1, 2, // front
0, 2, 3,
4, 0, 3, // left
4, 3, 7,
//4, 5, 6, // back
//4, 6, 7,
6, 5, 1, // right
6, 1, 2,
};
// indices
D3D11_BUFFER_DESC bdIndices;
bdIndices.Usage = D3D11_USAGE_DEFAULT;
bdIndices.ByteWidth = sizeof(indices);
bdIndices.BindFlags = D3D11_BIND_INDEX_BUFFER;
bdIndices.CPUAccessFlags = 0;
bdIndices.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
InitData.pSysMem = indices;
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;
dev->CreateBuffer(&bdIndices, &InitData, &pIBuffer);
D3D11_BUFFER_DESC bdWVP;
ZeroMemory(&bdWVP, sizeof(D3D11_BUFFER_DESC));
bdWVP.Usage = D3D11_USAGE_DEFAULT;
bdWVP.ByteWidth = sizeof(ConstantBuffer);
bdWVP.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bdWVP.CPUAccessFlags = 0;
dev->CreateBuffer(&bdWVP, NULL, &wvpConstBuffer);
g_World = XMMatrixIdentity();
XMVECTOR Eye = XMVectorSet(0.0f, 1.0f, -3.0f, 0.0f);
XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
g_View = XMMatrixLookAtLH(Eye, At, Up);
g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, 0.01f, 100.0f);
}
void InitRasterizer()
{
D3D11_RASTERIZER_DESC raster_desc;
raster_desc.FillMode = D3D11_FILL_SOLID;
raster_desc.CullMode = D3D11_CULL_NONE;
raster_desc.FrontCounterClockwise = false;
raster_desc.DepthBias = 0;
raster_desc.DepthBiasClamp = 0.0f;
raster_desc.SlopeScaledDepthBias = 0.0f;
raster_desc.DepthClipEnable = true;
raster_desc.ScissorEnable = false;
raster_desc.MultisampleEnable = false;
raster_desc.AntialiasedLineEnable = false;
dev->CreateRasterizerState(&raster_desc, &pRasterState);
}
// this function loads and prepares the shaders
void InitPipeline()
{
InitRasterizer();
InitTextures();
// load and compile the two shaders
ID3D10Blob* VS, * PS;
D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);
// encapsulate both shaders into shader objects
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);
// set the texture
devcon->PSSetShaderResources(0, 1, &pTexture);
devcon->PSSetSamplers(0, 1, &pSamplerState);
// off cull mode
devcon->RSSetState(pRasterState);
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
devcon->IASetInputLayout(pLayout);
}
shaders.shader
cbuffer ConstantBuffer : register(b0)
{
matrix World;
matrix View;
matrix Projection;
}
Texture2D ObjTexture;
SamplerState ObjSamplerState;
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float2 TexCoord : TEXCOORD;
};
VS_OUTPUT VShader(float4 Pos : POSITION, float4 inTexCoord : TEXCOORD)
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul(Pos, World);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);
output.TexCoord = inTexCoord;
return output;
}
float4 PShader(VS_OUTPUT input) : SV_Target
{
return ObjTexture.Sample(ObjSamplerState, input.TexCoord);
}
the "cube"
I've looked all over but couldn't solve the problem.
With a fresh eye today i've noticed that besides things i've mentioned earlier render target view and depth stencil view are using different multisampling settings: render target use 4 samples while depth stencil only 1. In order for them to work together their dimensions and multisampling settings must be exactly the same.
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:
initGeometry
In this function I set up my geometry, shaders and read information from file. I think that I do something wrong at the end of this function, because I didn't change shaders part and initializations part, only added new way to fill up a vertex array
render
This function didn't changed at all from my first version, where I filled up a vertecies array mannualy.
Structs
Just some 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
OBJ file format stores indices using one-based numbering (first vertex index is 1) Wavefron Obg file format. DirectX uses zero-based numbering (first vertex index is 0, same as C, C++).
So you should convert indices values to use them. You can do it like this:
for (int i = 0; i < meshInfo.indexiesAmount; i++) {
indixies[i] = meshInfo.indexiesPoints[i] - 1;
}
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.
Okay so loading in a model works fine but when I try to add a texture or lighting they become stretched, I think it is having problems sharing vertices. I have tried changing the sampler_desc address as well as messing around with the input layout but no luck. The results
HRESULT Model::CreateTextureSampler(char* filename) {
hr = D3DX11CreateShaderResourceViewFromFile(m_pD3DDevice, filename,
NULL, NULL,
&m_pTexture0, NULL);
if (FAILED(hr)) // Dont fail if error is just a warning
return hr;
D3D11_SAMPLER_DESC sampler_desc;
ZeroMemory(&sampler_desc, sizeof(sampler_desc));
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.MinLOD = 0;
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
hr = m_pD3DDevice->CreateSamplerState(&sampler_desc, &m_pSampler0);
if (FAILED(hr)) // Dont fail if error is just a warning
return hr;
}
HRESULT Model::CreateInputLayout()
{
// Create and set the input layout object
D3D11_INPUT_ELEMENT_DESC m_iedesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0,DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
hr = m_pD3DDevice->CreateInputLayout(m_iedesc, 4, M_VS->GetBufferPointer(),
M_VS->GetBufferSize(), &m_pInputLayout);
if (FAILED(hr)) // Dont fail if error is just a warning
return hr;
m_pImmediateContext->IASetInputLayout(m_pInputLayout);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
return S_OK;
}
When I'm looking at your line of code and I see this line here:
"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
You are passing to the input element descriptor for the tex coord with a third parameter of DXGI_FORMAT_R32G32B32A32_FLOAT. You might want to check this flag to see if this is causing your problem.
Normally texture coords are a vec2 object when using simple textures, unless if you are using a 3D Texture.
You might want to change this to DXGI_FORMAT_R32G32_FLOAT, and give the appropriate [S,T] or [P,Q] vertices for the texture file. Textures are normally images stored in memory linearly but are representing a MxN structure.
i would like to draw Instances of an obj File. After i implemented the Instancing instead of drawing each Object by his own draw() function (which worked just fine), the Instances are not positioned correctly. Probably the data from the InstanceBuffer is not set in the shader correctly.
D3DMain.cpp - creating input layout
struct INSTANCE {
//D3DXMATRIX matTrans;
D3DXVECTOR3
};
/***/
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
//vertex buffer
{"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},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
//instance buffer
{"INSTTRANS", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1},
//{"INSTTRANS", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
//{"INSTTRANS", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
//{"INSTTRANS", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
};
if (FAILED(d3ddev->CreateInputLayout(ied, 4, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout))) throw(std::string("Input Layout Creation Error"));
d3ddevcon->IASetInputLayout(pLayout);
World.cpp - setting up instance buffer
std::vector<INSTANCE> instanceBuffer;
INSTANCE insertInstance;
D3DXMATRIX scaleMat, transMat;
D3DXMatrixScaling(&scaleMat, 50.0f, 50.0f, 50.0f);
int i=0;
for (std::list<SINSTANCES>::iterator it = sInstances.begin(); it != sInstances.end(); it++) {
if ((*it).TypeID == typeId) {
//do something
D3DXMatrixTranslation(&transMat, (*it).pos.x, (*it).pos.y, (*it).pos.z);
insertInstance.matTrans = (*it).pos;//scaleMat * transMat;
instanceBuffer.push_back(insertInstance);
i++;
}
}
instanceCount[typeId] = i;
//create new IB
D3D11_BUFFER_DESC instanceBufferDesc;
ZeroMemory(&instanceBufferDesc, sizeof(instanceBufferDesc));
instanceBufferDesc.Usage = D3D11_USAGE_DEFAULT;
instanceBufferDesc.ByteWidth = sizeof(INSTANCE) * i;
instanceBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
instanceBufferDesc.CPUAccessFlags = 0;
instanceBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA instanceData;
ZeroMemory(&instanceData, sizeof(instanceData));
instanceData.pSysMem = &instanceBuffer[0];
if (FAILED(d3ddev->CreateBuffer(&instanceBufferDesc, &instanceData, &instanceBufferMap[typeId]))) throw(std::string("Failed to Update Instance Buffer"));
OpenDrawObj.cpp - drawing .obj file
UINT stride[2] = {sizeof(VERTEX), sizeof(INSTANCE)};
UINT offset[2] = {0, 0};
ID3D11Buffer* combinedBuffer[2] = {meshVertBuff, instanceBuffer};
d3ddevcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3ddevcon->IASetVertexBuffers(0, 2, combinedBuffer, stride, offset);
d3ddevcon->IASetIndexBuffer(meshIndexBuff, DXGI_FORMAT_R32_UINT, 0);
std::map<std::wstring, OBJMATERIAL>::iterator fit;
for (std::vector<DRAWLIST>::iterator it = drawList.begin(); it != drawList.end(); it++) {
fit = objMaterials.find((*it).material);
if (fit != objMaterials.end()) {
if ((*fit).second.texture != NULL) {
d3ddevcon->PSSetShaderResources(0, 1, &((*fit).second.texture));
}
d3ddevcon->DrawIndexedInstanced((*it).indexCount, instanceCount, (*it).startIndex, 0, 0);
}
}
the drawing function (above) is called here: I pass the instance buffer (map(int, ID3D11Buffer*) and the instance numbers)
(*it).second->draw(0.0f, 0.0f, 0.0f, 0, instanceBufferMap[typeId], instanceCount[typeId]);
shader.hlsl
struct VIn
{
float4 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
//row_major float4x4 instTrans : INSTTRANS;
float4 instTrans : INSTTRANS;
uint instanceID : SV_InstanceID;
};
VOut VShader(VIn input)
{
VOut output;
//first: transforming instance
//output.position = mul(input.instTrans, input.position);
output.position = input.position;
output.position.xyz *= 50.0; //scale
output.position.z += input.instTrans.z; //apply only z value
float4 transPos = mul(world, output.position); //transform position with world matrix
output.position = mul(view, transPos); //project to screen
the "input.instTrans" in the last file is incorrect and contains ramdom data.
Do you have any ideas?
So i found the bug, it was at an totally unexpected location...
So here is the code snippet:
ID3D10Blob *VS, *VS2, *PS, *PS2; //<- i only used VS and PS before
//volume shader
if (FAILED(D3DX11CompileFromFile(L"resources/volume.hlsl", 0, 0, "VShader", "vs_5_0", D3D10_SHADER_PREFER_FLOW_CONTROL | D3D10_SHADER_SKIP_OPTIMIZATION, 0, 0, &VS, 0, 0))) throw(std::string("Volume Shader Error 1"));
if (FAILED(D3DX11CompileFromFile(L"resources/volume.hlsl", 0, 0, "PShader", "ps_5_0", D3D10_SHADER_PREFER_FLOW_CONTROL | D3D10_SHADER_SKIP_OPTIMIZATION, 0, 0, &PS, 0, 0))) throw(std::string("Volume Shader Error 2"));
// encapsulate both shaders into shader objects
if (FAILED(d3ddev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pvolumeVS))) throw(std::string("Volume Shader Error 1A"));
if (FAILED(d3ddev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pvolumePS))) throw(std::string("Volume Shader Error 2A"));
//sky shader
if (FAILED(D3DX11CompileFromFile(L"resources/sky.hlsl", 0, 0, "VShader", "vs_5_0", D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, 0, &VS2, 0, 0))) throw(std::string("Sky Shader Error 1"));
if (FAILED(D3DX11CompileFromFile(L"resources/sky.hlsl", 0, 0, "PShader", "ps_5_0", D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, 0, &PS2, 0, 0))) throw(std::string("Sky Shader Error 2"));
// encapsulate both shaders into shader objects
if (FAILED(d3ddev->CreateVertexShader(VS2->GetBufferPointer(), VS2->GetBufferSize(), NULL, &pskyVS))) throw(std::string("Sky Shader Error 1A"));
if (FAILED(d3ddev->CreatePixelShader(PS2->GetBufferPointer(), PS2->GetBufferSize(), NULL, &pskyPS))) throw(std::string("Sky Shader Error 2A"));
Using two buffers for compiling the shaders solved the problem, though i have no idea why. Thank you for the support, though ;)
Using the tutorial here, I have managed to get a red triangle up on my screen: http://www.directxtutorial.com/Lesson.aspx?lessonid=9-4-4
CUSTOMVERTEX OurVertices[] =
{
{ 0, 0, 0, 1.0f, D3DCOLOR_XRGB( 127, 0, 0 ) },
{ WIDTH, 0, 0, 1.0f, D3DCOLOR_XRGB( 127, 0, 0 ) },
{ 0, 300, 0, 1.0f, D3DCOLOR_XRGB( 127, 0, 0 ) },
{ WIDTH, 300, 0, 1.0f, D3DCOLOR_XRGB( 127, 0, 0 ) }
};
d3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&vBuffer,
NULL);
VOID* pVoid; // the void* we were talking about
vBuffer->Lock(0, 0, (void**)&pVoid, 0); // locks v_buffer, the buffer we made earlier
memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy vertices to the vertex buffer
vBuffer->Unlock(); // unlock v_buffer
d3dDevice->SetFVF(CUSTOMFVF);
d3dDevice->SetStreamSource(0, vBuffer, 0, sizeof(CUSTOMVERTEX));
d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
But you can see that I really want to be drawing a rectangle.
I have changed the Primitive to draw 2 triangles and extended the buffer size to 4*size of my custom vertex but I can't really say I understand how to get it from my triangle to my rectangle I would like:
Is there a better way of drawing a rectangle rather than using a quad considering I just want to sling some text on top of it something like this:
http://1.bp.blogspot.com/-6HjFVnrVM94/TgRq8oP4U-I/AAAAAAAAAKk/i8N0OZU999E/s1600/monkey_island_screen.jpg
I had to exend my buffer to allow for 4 vertex array size:
d3dDevice->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&vBuffer,
NULL);
And then changed the draw primitive from TRIANGLELIST to STRIP extending the amount of triangles drawn to 2
d3dDevice->DrawPrimitive (D3DPT_TRIANGLESTRIP, 0, 2 );
Source: http://www.mdxinfo.com/tutorials/tutorial4.php