So I am currently implementing Diffuse & Ambient Lighting based off this tutorial: https://www.braynzarsoft.net/viewtutorial/q16390-simple-lighting
I think I have implemented everything correctly, so the Ambient & Diffuse Light should work correctly but I just get Ambient Light. Can someone help me fix this? Here is my code.
HEADER.H
#pragma once
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// 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 <DirectXMath.h>
using namespace DirectX;
// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")
// 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
ID3D11Buffer* squareIndexBuffer;
ID3D11Buffer* squareVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;
ID3D11Texture2D* pDepthStencil;
ID3D11DepthStencilView* pDSV;
ID3D11Buffer* cbPerObjectBuffer;
ID3D11Buffer* cbPerFrameBuffer;
ID3D11ShaderResourceView* CubesTexture;
ID3D11SamplerState* CubesTexSamplerState;
XMMATRIX WVP;
XMMATRIX World;
XMMATRIX camView;
XMMATRIX camProjection;
XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;
XMMATRIX cube1World;
XMMATRIX cube2World;
XMMATRIX Rotation;
XMMATRIX Scale;
XMMATRIX Translation;
float rot = 0.01f;
// 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 InitScene(void);
void UpdateScene(void);
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "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 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
UINT numElements = ARRAYSIZE(layout);
struct cbPerObject
{
XMMATRIX WVP;
XMMATRIX World;
};
struct Vertex
{
Vertex() {}
Vertex(float x, float y, float z, float u, float v, float nx, float ny, float nz)
: pos(x, y, z), texCoord(u, v), normal(nx, ny, nz){}
XMFLOAT3 pos;
XMFLOAT2 texCoord;
XMFLOAT3 normal;
};
struct Light
{
Light()
{
ZeroMemory(this, sizeof(Light));
}
XMFLOAT3 dir;
float pad;
XMFLOAT4 ambient;
XMFLOAT4 diffuse;
};
Light light;
struct cbPerFrame
{
Light light;
};
cbPerFrame constbuffPerFrame;
MAIN.CPP
#include "Header.h"
// 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.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = { 0, 0, 800, 600 };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Eagle Engine (Alpha)",
WS_OVERLAPPEDWINDOW,
SCREEN_WIDTH,
SCREEN_HEIGHT,
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);
}
cbPerObject cbPerObj;
// 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));
HRESULT hr = S_OK;
// fill the swap chain description struct
scd.BufferCount = 2; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
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 = 8; // how many multisamples
scd.SampleDesc.Quality = 1;
scd.Windowed = TRUE;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching// windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
hr = 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();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
ID3D11Texture2D* pDepthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = SCREEN_WIDTH;
descDepth.Height = SCREEN_HEIGHT;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
descDepth.SampleDesc.Count = scd.SampleDesc.Count;
descDepth.SampleDesc.Quality = scd.SampleDesc.Quality;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = dev->CreateTexture2D(&descDepth, NULL, &pDepthStencil);
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
descDSV.Texture2D.MipSlice = 0;
dev->CreateTexture2D(&descDepth, NULL, &pDepthStencil);
// Create the depth stencil view
ID3D11DepthStencilView* pDSV;
hr = dev->CreateDepthStencilView(pDepthStencil, // Depth stencil texture
&descDSV, // Depth stencil desc
&pDSV); // [out] Depth stencil view
devcon->OMSetRenderTargets(1, &backbuffer, pDSV);
// 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);
//Create the buffer to send to the cbuffer in effect file
D3D11_BUFFER_DESC cbbd;
ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerObject);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;
dev->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);
ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerFrame);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;
dev->CreateBuffer(&cbbd, NULL, &cbPerFrameBuffer);
//Camera information
camPosition = XMVectorSet(-5.0f, 3.0f, -5.0f, 0.0f); //Position X,Y,Z
camTarget = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); //Rotation X,Y,Z
camUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
//Set the View matrix
camView = XMMatrixLookAtLH(camPosition, camTarget, camUp);
//Set the Projection matrix
camProjection = XMMatrixPerspectiveFovLH(0.4f*3.14f, (float)SCREEN_WIDTH/SCREEN_HEIGHT , 1.0f, 1000.0f);
D3DX11CreateShaderResourceViewFromFile(dev, L"braynzar.jpg", NULL, NULL, &CubesTexture, NULL);
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
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, &CubesTexSamplerState);
InitScene();
UpdateScene();
}
// this is the function used to render a single frame
void RenderFrame(void)
{
//Clear our backbuffer
float bgColor[4] = { (0.0f, 0.0f, 0.0f, 0.0f) };
devcon->ClearRenderTargetView(backbuffer, bgColor);
//Refresh the Depth/Stencil view
devcon->ClearDepthStencilView(pDSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
constbuffPerFrame.light = light;
devcon->UpdateSubresource(cbPerFrameBuffer, 0, NULL, &constbuffPerFrame, 0, 0);
devcon->PSSetConstantBuffers(0, 1, &cbPerFrameBuffer);
///////////////**************new**************////////////////////
//Set the WVP matrix and send it to the constant buffer in effect file
WVP = cube1World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
devcon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
devcon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);
devcon->PSSetShaderResources(0, 1, &CubesTexture);
devcon->PSSetSamplers(0, 1, &CubesTexSamplerState);
//Draw the first cube
devcon->DrawIndexed(36, 0, 0);
WVP = cube2World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
devcon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
devcon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);
devcon->PSSetShaderResources(0, 1, &CubesTexture);
devcon->PSSetSamplers(0, 1, &CubesTexSamplerState);
//Draw the second cube
devcon->DrawIndexed(36, 0, 0);
///////////////**************new**************////////////////////
//Present the backbuffer to the screen
swapchain->Present(0, 0);
};
// 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
swapchain->Release();
dev->Release();
backbuffer->Release();
devcon->Release();
squareIndexBuffer->Release();
squareVertBuffer->Release();
VS->Release();
PS->Release();
VS_Buffer->Release();
PS_Buffer->Release();
vertLayout->Release();
cbPerObjectBuffer->Release();
cbPerFrameBuffer->Release();
}
void InitScene()
{
//Compile Shaders from shader file
D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0);
D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0);
//Create the Shader Objects
dev->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
dev->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);
//Set Vertex and Pixel Shaders
devcon->VSSetShader(VS, 0, 0);
devcon->PSSetShader(PS, 0, 0);
light.dir = XMFLOAT3(0.25f, 1.0f, 1.0f);
light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
light.diffuse = XMFLOAT4(1.0f, 1.0f, 2.0f, 5.0f);
//Create the vertex buffer
Vertex v[] =
{
// Front Face
Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f),
Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f,-1.0f, 1.0f, -1.0f),
Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f),
Vertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f),
// Back Face
Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f),
Vertex(1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f),
Vertex(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f),
Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,-1.0f, 1.0f, 1.0f),
// Top Face
Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f,-1.0f, 1.0f, -1.0f),
Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f),
Vertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f),
Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f),
// Bottom Face
Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f),
Vertex(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f),
Vertex(1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f),
Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f,-1.0f, -1.0f, 1.0f),
// Left Face
Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f,-1.0f, -1.0f, 1.0f),
Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f),
Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f,-1.0f, 1.0f, -1.0f),
Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f),
// Right Face
Vertex(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f),
Vertex(1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f),
Vertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f),
Vertex(1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f),
};
DWORD indices[] =
{
// Front Face
0, 1, 2,
0, 2, 3,
// Back Face
4, 5, 6,
4, 6, 7,
// Top Face
8, 9, 10,
8, 10, 11,
// Bottom Face
12, 13, 14,
12, 14, 15,
// Left Face
16, 17, 18,
16, 18, 19,
// Right Face
20, 21, 22,
20, 22, 23
};
D3D11_BUFFER_DESC indexBufferDesc;
ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
dev->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);
devcon->IASetIndexBuffer(squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 24;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = v;
dev->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &squareVertBuffer);
//Set the vertex buffer
UINT stride = sizeof(Vertex);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &squareVertBuffer, &stride, &offset);
//Create the Input Layout
dev->CreateInputLayout(layout, numElements, VS_Buffer->GetBufferPointer(),
VS_Buffer->GetBufferSize(), &vertLayout);
//Set the Input Layout
devcon->IASetInputLayout(vertLayout);
//Set Primitive Topology
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
void UpdateScene()
{
//Reset cube1World
cube1World = XMMatrixIdentity();
Translation = XMMatrixTranslation(0.0f, 0.0f, 4.0f);
//Define cube2's world space matrix
Scale = XMMatrixScaling(1.3f, 1.3f, 1.3f);
//Set cube1's world space using the transformations
cube1World = Translation;
//Reset cube2World
cube2World = XMMatrixIdentity();
//Set cube2's world space matrix
cube2World = Scale;
}
EFFECTS.FX
struct Light
{
float3 dir;
float4 ambient;
float4 diffuse;
};
cbuffer cbPerFrame
{
Light light;
};
cbuffer cbPerObject
{
float4x4 WVP;
float4x4 World;
};
Texture2D ObjTexture;
SamplerState ObjSamplerState;
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float2 TexCoord : TEXCOORD;
float3 normal : NORMAL;
};
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.normal = mul(normal, World);
output.TexCoord = inTexCoord;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
input.normal = normalize(input.normal);
float4 diffuse = ObjTexture.Sample(ObjSamplerState, input.TexCoord);
float3 finalColor;
finalColor = diffuse * light.ambient;
finalColor += saturate(dot(light.dir, input.normal) * light.diffuse * diffuse);
return float4(finalColor, diffuse.a);
}