I am working on my first Direct3D game and even after many days of searching Internet and experimenting I can't figure out how to work with normals properly. As a result, the lights are not working correctly. The scene is shown on the below picture.
The camera is always pointed into center of the scene (0,0,0) and rotates around it. The scene itself is static, only the vehicles can move forward or backward. The light source is a static point light. So I would presume the diffuse lighting level of the objects must be static during camera rotation. But it isn't. When I rotate the camera, the lighting levels of particular parts of objects are changing (even if I disable the specular part of light). Also the diffuse light on the objects is not correct with respect to the light position. So I would say I am doing something completely wrong with the normals. I am trying to figure it out for 1 week but with no success. So I am kindly asking you for any help which can push me forward.
I have found (e.g. here), that I must multiply my normal vectors with transposed inverse matrix of the original world matrix applied to my vertices, because my models are scaled. But this is not helping. Below are relevant parts of my code.
Render scene method:
struct CBUFFER {
DirectX::XMMATRIX world;
DirectX::XMMATRIX rotation;
DirectX::XMMATRIX invTrWorld;
DirectX::XMVECTOR cameraPosition;
DirectX::XMVECTOR lightVector;
DirectX::XMVECTOR diffuseColor;
DirectX::XMVECTOR ambientColor;
float specularPower;
DirectX::XMVECTOR specularColor;
};
void Game::Render() {
CBUFFER cBuffer;
XMMATRIX matView, matPerspective;
XMVECTOR camPosition = XMVectorSet(0.0f, 4.0f, -10.0f, 0.0f);
camPosition = XMVector4Transform(camPosition, _rotation); // _rotation - defines the angle of the camera
//Set the View matrix
matView = XMMatrixLookAtLH(
camPosition, // the camera position (rotating around the center of the board)
XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f), // the look-at position
XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f) // the up direction
);
cBuffer.cameraPosition = camPosition;
// create a projection matrix
matPerspective = XMMatrixPerspectiveFovLH((FLOAT)XMConvertToRadians(45), (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, 1.0f, 100.0f);
cBuffer.lightVector = XMVectorSet(-10.0f, 10.0f, 10.0f, 1.0f);
cBuffer.diffuseColor = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f);
cBuffer.ambientColor = XMVectorSet(_ambientColorIntensity, _ambientColorIntensity, _ambientColorIntensity, 1.0f);
cBuffer.specularColor = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f);
// clear the back buffer to a deep blue
FLOAT bgColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
_d3d->GetDeviceContext()->ClearRenderTargetView(_d3d->GetBackBuffer(), bgColor);
// clear the depth buffer
_d3d->GetDeviceContext()->ClearDepthStencilView(_d3d->GetZBuffer(), D3D11_CLEAR_DEPTH, 1.0f, 0);
// select which vertex buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
_d3d->GetDeviceContext()->IASetVertexBuffers(0, 1, _d3d->GetVBufferAddr(), &stride, &offset);
_d3d->GetDeviceContext()->IASetIndexBuffer(_d3d->GetIBuffer(), DXGI_FORMAT_R32_UINT, 0);
// select which primtive type we are using
_d3d->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_d3d->GetDeviceContext()->IASetInputLayout(_d3d->GetLayout());
// select Rasterizer and Sampler configuration
_d3d->GetDeviceContext()->RSSetState(_d3d->GetRState());
_d3d->GetDeviceContext()->PSSetSamplers(0, 1, _d3d->GetSStateAddr());
// Draw model instances - Non-vehicle objects
for (auto it = _minstances.begin(); it != _minstances.end(); it++) {
ModelInstance mi = it->second;
// Store instance transformation into constant buffer
XMMATRIX worldMatrix = mi.GetTransformation() * _worldOffset;
worldMatrix *= matView * matPerspective;
XMMATRIX trInvWorld = XMMatrixInverse(nullptr, XMMatrixTranspose(worldMatrix));
cBuffer.world = worldMatrix;
cBuffer.invTrWorld = invTrWorld;
// TODO: obtain specularPower from model
cBuffer.specularPower = 1.0f;
// Send constant buffer
_d3d->GetDeviceContext()->UpdateSubresource(_d3d->GetCBuffer(), 0, 0, &cBuffer, 0, 0);
for (auto i : mi.GetModel().GetMeshEntries()) {
// select texture
_d3d->GetDeviceContext()->PSSetShaderResources(0, 1, &i._pTexture);
_d3d->GetDeviceContext()->DrawIndexed(i._numIndices, i._baseIndex, i._baseVertex);
}
}
// Draw vehicles
for (auto it = _vehicles.begin(); it != _vehicles.end(); it++) {
Vehicle mi = it->second;
if (mi.IsHidden()) {
continue;
}
// Store vehicle transformation into constant buffer
XMMATRIX worldMatrix = mi.GetTransformation() * _worldOffset;
worldMatrix *= matView * matPerspective;
XMMATRIX trInvWorld = XMMatrixInverse(nullptr, XMMatrixTranspose(worldMatrix));
cBuffer.world = worldMatrix;
cBuffer.invTrWorld = invTrWorld;
// Store vehicle color into constant buffer
XMVECTOR vehicleColor = mi.GetColor();
cBuffer.diffuseColor = vehicleColor;
cBuffer.specularColor = vehicleColor;
float glowIntensity = _ambientColorIntensity + mi.GetGlowLevel();
cBuffer.ambientColor = XMVectorSet(vehicleColor.m128_f32[0] * glowIntensity,
vehicleColor.m128_f32[1] * glowIntensity,
vehicleColor.m128_f32[2] * glowIntensity,
vehicleColor.m128_f32[3] * glowIntensity);
// TODO: obtain specularPower from model
cBuffer.specularPower = 32.0f;
// Send constant buffer
_d3d->GetDeviceContext()->UpdateSubresource(_d3d->GetCBuffer(), 0, 0, &cBuffer, 0, 0);
for (auto i : mi.GetModel().GetMeshEntries()) {
// select texture
_d3d->GetDeviceContext()->PSSetShaderResources(0, 1, &i._pTexture);
_d3d->GetDeviceContext()->DrawIndexed(i._numIndices, i._baseIndex, i._baseVertex);
}
}
// print FPS info
_d2d->PrintInfo();
// switch the back buffer and the front buffer
_d3d->GetSwapChain()->Present(0, 0);
}
HLSL code:
cbuffer ConstantBuffer {
matrix world;
matrix rotation;
matrix trinvworld;
float4 camposition; // position of the camera
float4 lightpos; // the diffuse light's vector
float4 diffusecol; // the diffuse light's color
float4 ambientcol; // the ambient light's color
float specularpow; // the specular light's power
float4 specularcol; // the specular light's color
}
Texture2D Texture;
SamplerState ss;
struct VOut {
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 position : SV_POSITION;
};
VOut VShader(float4 position : POSITION, float3 normal : NORMAL, float2 texcoord : TEXCOORD) {
VOut output;
// VERTEX POSITION TRANSFORMATION
// Calculate the position of the vertex in the world
float4 worldposition4 = mul(world, position);
// float3 worldposition = mul((float3x3)world, position.xyz);
output.position = worldposition4
// AMBIENT LIGHT & NORMAL TRANSFORMATION
float4 color = ambientcol;
float3 norm = normalize(mul((float3x3)trinvworld, normal));
//float3 norm = normalize(mul((float3x3)world, normal));
// DIFFUSE LIGHT
// float3 lightpos3 = lightpos.xyz;
// float3 lightvec = normalize(lightpos3 - worldposition);
float4 lightvec = normalize(lightpos - worldposition4);
lightvec = -lightvec;
float lightintensity = saturate(dot(norm, lightvec)); // calculate the amount of light
// SPECULAR LIGHT
//float3 camposition3 = camposition.xyz;
float3 camvec = normalize(camposition - worldposition4);
camvec = -camvec;
float3 reflectedlight = reflect(lightvec, norm);
float specularfactor = saturate(dot(reflectedlight, camvec));
float dampedfactor = pow(specularfactor, specularpow);
float4 finalspecular = dampedfactor * specularcol;
// COMBINE ALL LIGTHS TOGETHER
color += diffusecol * lightintensity + finalspecular;
output.color = saturate(color);
// TEXTURE
output.texcoord = texcoord;
return output;
}
float4 PShader(float4 color : COLOR, float2 texcoord : TEXCOORD) : SV_TARGET
{
return color *Texture.Sample(ss, texcoord);
}
The normals are part of loaded models. The models are loaded using Assimp Importer:
Model::Model(const char* pFile, ID3D11Device* dev) {
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
_pScene = _imp.ReadFile(pFile, aiProcess_FlipUVs | aiProcess_FixInfacingNormals | aiProcess_MakeLeftHanded |
aiProcess_GenSmoothNormals | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType);
if (!_pScene) {
}else {
if (_pScene->mNumMeshes < 1) {
}
else {
// Process all meshes
for (unsigned int m = 0; m < _pScene->mNumMeshes; m++) {
_pMesh = _pScene->mMeshes[m];
MeshEntry me;
me._baseVertex = Model::_objectVertices.size();
me._baseIndex = _objectIndices.size();
if (_pMesh) {
// Load vertices
Model::_objectVertices.reserve(Model::_objectVertices.size() + _pMesh->mNumVertices);
for (unsigned int i = 0; i < _pMesh->mNumVertices; i++) {
const aiVector3D* pPos = &(_pMesh->mVertices[i]);
const aiVector3D* pNormal = (_pMesh->mNormals != nullptr) ? &(_pMesh->mNormals[i]) : &Zero3D;
const aiVector3D* pTexCoord = (_pMesh->HasTextureCoords(0)) ? &(_pMesh->mTextureCoords[0][i]) : &Zero3D;
VERTEX v;
v.pos.x = pPos->x; v.pos.y = pPos->y; v.pos.z = pPos->z;
v.normal.x = pNormal->x; v.normal.y = pNormal->y; v.normal.z = pNormal->z;
//v.normal.x = 1.0f; v.normal.y = 0.0f; v.normal.z = 0.0f;
v.textCoord.x = pTexCoord->x; v.textCoord.y = pTexCoord->y;
Model::_objectVertices.push_back(v);
}
// Load indices
_objectIndices.reserve(_objectIndices.size() + (_pMesh->mNumFaces * 3));
for (unsigned int i = 0; i < _pMesh->mNumFaces; i++) {
if (_pMesh->mFaces[i].mNumIndices == 3) {
_objectIndices.push_back(_pMesh->mFaces[i].mIndices[0]);
_objectIndices.push_back(_pMesh->mFaces[i].mIndices[1]);
_objectIndices.push_back(_pMesh->mFaces[i].mIndices[2]);
me._numIndices += 3;
}
}
// Process material of the mesh
if (_pScene->HasMaterials()) {
aiMaterial* material = _pScene->mMaterials[_pMesh->mMaterialIndex];
aiString aiTextureFile;
me._materialIndex = _pMesh->mMaterialIndex;
// Load texture file
if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0) {
material->GetTexture(aiTextureType_DIFFUSE, 0, &aiTextureFile);
// Convert aiString to LPWSTR
size_t size = strlen(aiTextureFile.C_Str()) + 1; // plus null
wchar_t* wcTextureFile = new wchar_t[size];
std::shared_ptr<wchar_t> sp(wcTextureFile, std::default_delete<wchar_t[]>());
size_t outSize;
mbstowcs_s(&outSize, wcTextureFile, size, aiTextureFile.C_Str(), size - 1);
LPWSTR textureFile = wcTextureFile;
CreateWICTextureFromFile(dev, nullptr, textureFile, nullptr, &(me._pTexture), 0);
if (me._pTexture == nullptr) {
CreateDDSTextureFromFile(dev, nullptr, textureFile, nullptr, &(me._pTexture), 0);
}
}
}
// If no texture found, use the default one
if (me._pTexture == nullptr) {
CreateWICTextureFromFile(dev, nullptr, L"models/default.jpg", nullptr, &(me._pTexture), 0);
}
_entries.push_back(me);
}
}
}
}
}
And the D3D scene is initialized by D3D class.
D3D.h
#pragma once
#include <d3d11.h>
#include <directxmath.h>
#include <vector>
#include "RushHour.h"
#include "D3DSupplementary.h"
class D3D {
public:
D3D() = delete;
D3D(HWND hWnd);
D3D(D3D&&) = default;
D3D& operator= (D3D&&) = default;
~D3D();
// D3D must not be copied, as it would release all elements after copy
D3D(const D3D&) = delete;
D3D& operator=(const D3D&) = delete;
void CreateVertexBuffer(std::vector<VERTEX> OurVertices);
void CreateIndexBuffer(std::vector<UINT> OurIndices);
IDXGISwapChain* GetSwapChain() const { return _swapChain; };
IDXGIDevice* GetDXGIDevice() const { return _dxgiDevice; }
ID3D11Device* GetDevice() const { return _dev; }
ID3D11DeviceContext* GetDeviceContext() const { return _devCon; }
ID3D11RenderTargetView* GetBackBuffer() const { return _bBuffer; }
ID3D11DepthStencilView* GetZBuffer() const { return _zBuffer; }
ID3D11Buffer* GetCBuffer() const { return _cBuffer; }
ID3D11Buffer* GetVBuffer() const { return _vBuffer; }
ID3D11Buffer** GetVBufferAddr() { return &(_vBuffer); }
ID3D11Buffer* GetIBuffer() const { return _iBuffer; }
ID3D11InputLayout* GetLayout() const { return _layout; }
ID3D11RasterizerState* GetRState() const { return _rs; }
ID3D11SamplerState* GetSState() const { return _ss; }
ID3D11SamplerState** GetSStateAddr() { return &(_ss); }
private:
IDXGISwapChain* _swapChain; // swap chain interface
IDXGIDevice* _dxgiDevice;
ID3D11Device* _dev; // device interface
ID3D11DeviceContext* _devCon; // device context
ID3D11VertexShader* _vs; // vertex shader
ID3D11PixelShader* _ps; // pixel shader
ID3D11InputLayout* _layout; // layout
ID3D11RenderTargetView* _bBuffer; // backbuffer
ID3D11DepthStencilView* _zBuffer; // depth buffer
ID3D11Buffer* _cBuffer; // constant buffer
ID3D11Buffer* _vBuffer; // vertex buffer
ID3D11Buffer* _iBuffer; // index buffer
// State objects
ID3D11RasterizerState* _rs; // the default rasterizer state
ID3D11SamplerState* _ss; // sampler state
void CreateDevice(HWND hWnd);
void CreateDepthBuffer();
void CreateRenderTarget();
void SetViewport();
void LoadShaders();
void CreateConstantBuffer();
void InitRasterizer();
void InitSampler();
};
D3D.cpp:
#include "stdafx.h"
#include <d3dcompiler.h>
#include "CommonException.h"
#include "D3D.h"
D3D::D3D(HWND hWnd) {
// this function initializes and prepares Direct3D for use
CreateDevice(hWnd);
CreateDepthBuffer();
CreateRenderTarget();
SetViewport();
LoadShaders();
CreateConstantBuffer();
InitRasterizer();
InitSampler();
}
D3D::~D3D() {
// switch to windowed mode
if (_swapChain) _swapChain->SetFullscreenState(FALSE, NULL);
// release all the stuff
if (_zBuffer) _zBuffer->Release();
if (_layout) _layout->Release();
if (_vs) _vs->Release();
if (_ps) _ps->Release();
if (_vBuffer) _vBuffer->Release();
if (_iBuffer) _iBuffer->Release();
if (_cBuffer) _cBuffer->Release();
if (_swapChain) _swapChain->Release();
if (_bBuffer) _bBuffer->Release();
if (_rs) _rs->Release();
if (_ss) _ss->Release();
if (_dev) _dev->Release();
if (_devCon) _devCon->Release();
}
void D3D::CreateDevice(HWND hWnd) {
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferDesc.Width = SCREEN_WIDTH; // set the back buffer width
scd.BufferDesc.Height = SCREEN_HEIGHT; // set the back buffer height
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.RefreshRate.Numerator = 0; // refresh rate: 0 -> do not care
scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; // unspecified scan line ordering
scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // unspecified scaling
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.SampleDesc.Quality = 0;
scd.Windowed = RUNINWINDOW; // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching by Alt-Enter
D3D_FEATURE_LEVEL featureLevel;
// create a device, device context and swap chain using the information in the scd struct
if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
D3D11_CREATE_DEVICE_BGRA_SUPPORT /* This flag is necessary for compatibility with Direct2D */,
NULL, NULL, D3D11_SDK_VERSION, &scd, &_swapChain, &_dev, &featureLevel, &_devCon))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create the Direct3D device!");
} else if (featureLevel < D3D_FEATURE_LEVEL_11_0) {
throw CommonException((LPWSTR)L"Critical error: You need DirectX 11.0 or higher to run this game!");
}
if (FAILED(_dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<LPVOID*>(&_dxgiDevice)))) {
throw CommonException((LPWSTR)L"Critical error: Unable to get Direct3D DXGI device!");
}
}
void D3D::CreateDepthBuffer() {
// create the depth buffer texture
D3D11_TEXTURE2D_DESC texd;
ZeroMemory(&texd, sizeof(texd));
texd.Width = SCREEN_WIDTH;
texd.Height = SCREEN_HEIGHT;
texd.ArraySize = 1;
texd.MipLevels = 1;
texd.SampleDesc.Count = 4;
texd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
texd.Usage = D3D11_USAGE_DEFAULT;
texd.BindFlags = D3D11_BIND_DEPTH_STENCIL;
ID3D11Texture2D *pDepthBuffer;
if (FAILED(_dev->CreateTexture2D(&texd, NULL, &pDepthBuffer))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D depth buffer texture!");
}
// create the depth buffer
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd;
ZeroMemory(&dsvd, sizeof(dsvd));
//dsvd.Format = DXGI_FORMAT_D32_FLOAT;
dsvd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
if (FAILED(_dev->CreateDepthStencilView(pDepthBuffer, &dsvd, &_zBuffer))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D depth buffer!");
}
pDepthBuffer->Release();
}
void D3D::CreateRenderTarget() {
// create backbuffer and render target
ID3D11Texture2D *pBackBuffer;
if (FAILED(_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<LPVOID*>(&pBackBuffer)))) {
throw CommonException((LPWSTR)L"Critical error: Unable to get Direct3D depth buffer!");
}
if (FAILED(_dev->CreateRenderTargetView(pBackBuffer, NULL, &_bBuffer))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D depth buffer!");
}
pBackBuffer->Release();
_devCon->OMSetRenderTargets(1, &_bBuffer, _zBuffer);
}
void D3D::SetViewport() {
// 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;
viewport.MaxDepth = 1;
_devCon->RSSetViewports(1, &viewport);
}
void D3D::LoadShaders() {
// load and compile vertex and pixel shader
ID3D10Blob *VS, *PS;
D3DCompileFromFile(L"shaders.shader", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, "VShader", "vs_4_0", 0, 0, &VS, NULL);
D3DCompileFromFile(L"shaders.shader", NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, "PShader", "ps_4_0", 0, 0, &PS, NULL);
if (FAILED(_dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &_vs))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D vertex shader!");
}
if (FAILED(_dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &_ps))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D pixel shader!");
}
_devCon->VSSetShader(_vs, 0, 0);
_devCon->PSSetShader(_ps, 0, 0);
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{ "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 },
};
if (FAILED(_dev->CreateInputLayout(ied, 3, VS->GetBufferPointer(), VS->GetBufferSize(), &_layout))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D input layout!");
}
_devCon->IASetInputLayout(_layout);
}
void D3D::CreateConstantBuffer() {
// constant buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(CBUFFER);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
if (FAILED(_dev->CreateBuffer(&bd, NULL, &_cBuffer))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D constant buffer!");
}
_devCon->VSSetConstantBuffers(0, 1, &_cBuffer);
}
void D3D::CreateVertexBuffer(std::vector<VERTEX> OurVertices) {
// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(VERTEX) * OurVertices.size();
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(_dev->CreateBuffer(&bd, NULL, &_vBuffer))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D vertex buffer!");
}
// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
if (FAILED(_devCon->Map(_vBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms))) {
throw CommonException((LPWSTR)L"Critical error: Unable to map Direct3D vertex buffer!");
}
memcpy(ms.pData, OurVertices.data(), sizeof(VERTEX) * OurVertices.size());
_devCon->Unmap(_vBuffer, NULL);
}
void D3D::CreateIndexBuffer(std::vector<UINT> OurIndices) {
// create the index buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(UINT) * OurIndices.size();
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
if (FAILED(_dev->CreateBuffer(&bd, NULL, &_iBuffer))) {
throw CommonException((LPWSTR)L"Critical error: Unable to create Direct3D index buffer!");
}
// copy the indices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
if (FAILED(_devCon->Map(_iBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms))) {
throw CommonException((LPWSTR)L"Critical error: Unable to map Direct3D index buffer!");
}
memcpy(ms.pData, OurIndices.data(), sizeof(UINT) * OurIndices.size());
_devCon->Unmap(_iBuffer, NULL);
}
void D3D::InitRasterizer() {
D3D11_RASTERIZER_DESC rd;
rd.FillMode = D3D11_FILL_SOLID;
rd.CullMode = D3D11_CULL_BACK;
rd.FrontCounterClockwise = TRUE;
rd.DepthClipEnable = TRUE;
rd.ScissorEnable = FALSE;
rd.AntialiasedLineEnable = FALSE;
rd.MultisampleEnable = FALSE;
rd.DepthBias = 0;
rd.DepthBiasClamp = 0.0f;
rd.SlopeScaledDepthBias = 0.0f;
if (FAILED(_dev->CreateRasterizerState(&rd, &_rs))) {
throw CommonException((LPWSTR)L"Critical error: Unable to creat Direct3D rasterizer state!");
}
}
void D3D::InitSampler() {
D3D11_SAMPLER_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sd.MaxAnisotropy = 16;
sd.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sd.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sd.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sd.BorderColor[0] = 0.0f;
sd.BorderColor[1] = 0.0f;
sd.BorderColor[2] = 0.0f;
sd.BorderColor[3] = 0.0f;
sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
sd.MinLOD = 0.0f;
sd.MaxLOD = FLT_MAX;
sd.MipLODBias = 0.0f;
if (FAILED(_dev->CreateSamplerState(&sd, &_ss))) {
throw CommonException((LPWSTR)L"Critical error: Unable to creat Direct3D sampler state!");
}
}
I hope I have provided all important parts of the code. Just for case, the complete code can be found here.
Another thing I don't understand in my app might not be connected with my problem at all, but maybe it is connected so I rather mention it here:
Transformation matrices are ok to be stored into constant buffer in original form (== not transposed). As far as I understood from articles I found (e.g. here) the CPU stores arrays in row-major format while HLSL needs them in column-major format so I must transpose all matrices before I store them into the constant buffer. But in my project it works without transposed matrices. When I transpose them, the scene is completely broken.
float4 worldposition4 = mul(world, position);
), and once without (float3 worldposition = mul((float3x3)world, position.xyz);
)? \$\endgroup\$