08.世界视图和本地空间
本节学习3D世界中的世界视图和局部空间,这将使我们能够创建相机,这样只有相机看到的东西才会被绘制到屏幕上。
我们将学习如何实现静态(非移动)相机,以及如何使用着色器常量缓冲区,这些是着色器可以使用的效果文件中的变量,我们可以从代码中更新它们。
代码下载地址:
- DX11_Lesson_08_World_View_Projection_Spaces_zip.zip
- https://www.braynzarsoft.net/file/8
简介
我们将了解 3D 世界中的不同空间,包括世界空间、视图空间、投影空间、本地空间和屏幕空间。
我们可以使用这些空间来创建相机效果,该效果将仅显示相机所看到的内容。要使用这些空间,我们将把它们发送到效果文件内常量缓冲区中的变量,顶点着色器将使用该变量来确定构成对象的顶点的坐标。
WVP=世界X相机X相机投影
局部(对象)空间
局部空间是相对于对象的空间。当我们创建一个对象时,我们通常会以点 (0, 0, 0) 为中心,这使得创建和定义顶点变得容易得多。想象一下一个立方体。如果我们要相对于实际 3D 场景的中心点 (0, 0, 0) 创建立方体,我们将很难定义它的顶点,特别是如果立方体稍微倾斜的话。不仅如此,也许我们还需要制作一片森林。当我们所要做的只是创建一次树并制作副本并重新定位每个副本时,创建大量定义森林的树木将是一种浪费。
局部空间定义该对象中顶点相对于其他顶点的位置。局部空间中的顶点位置通常在包含 3D 对象的文件中定义,该文件由 3D 建模程序创建。
世界空间
世界空间用于在世界空间中定位每个对象相对于彼此的位置。每个对象都有自己独特的世界空间矩阵。世界空间是 3D 场景中对象的位置、大小和旋转。所有对象都将围绕单个中心点 (0, 0, 0) 定位,该中心点是世界空间中心。要创建世界空间矩阵,我们需要对正在为其创建世界空间矩阵的对象进行变换(平移、旋转、缩放。下一课将介绍)。
世界空间由每个物体上的单独变换、平移、旋转和缩放定义。我们将使用世界空间矩阵将物体顶点从其局部空间变换到世界空间,其中顶点位置相对于场景中的其他物体。我们将在下一课中讨论这些变换。
视图空间
视图空间基本上就是相机的空间。相机位于点 (0, 0, 0),相机沿 z 轴向下看,相机向上的方向是 y 轴,世界被平移到相机空间。因此,当我们进行变换时,看起来相机正在围绕世界移动,而实际上,世界在移动,而相机静止。
视图空间是通过创建一个矩阵来定义的,该矩阵描述了我们的相机位置、视图方向(目标)和向上(相机的 y 轴)。我们可以使用 3 个向量(位置、目标和向上)以及函数 XMMatrixLookAtLH() 轻松创建一个视图矩阵。
投影空间
这基本上就是一个空间,如果物体在里面,它们就会被渲染到屏幕上,如果物体在外面,它们就会被丢弃。这个空间是不同的,因为它是由六个平面定义的,即近平面、远平面、顶部、左侧、底部和右侧平面。如果我们将投影空间渲染为几何图形,它看起来就像一个尖端被切掉的金字塔。金字塔的尖端将是相机的位置,尖端被切掉的地方将是近 z 平面,金字塔的底部将是远 z 平面。近平面和远平面由浮点值定义,其他四个由纵横比和 FOV(弧度视野)定义。
投影空间定义了 3D 场景中从相机的视角可见的对象的区域(将在屏幕上显示的对象)。我们可以使用函数 XMMatrixPerspectiveFovLH() 轻松定义投影矩阵,并将 FOV(以弧度表示的视野)、纵横比、近 z 平面和远 z 平面传递给它。我将更好地解释纵横比和 FOV 的作用。纵横比是用于查找近平面和远平面的宽度和高度的值,通常您需要将宽度除以屏幕的高度(宽度/高度)。1:1 的比例(将纵横比设置为 1)将为您提供一个精确的正方形。当然,远平面将比近平面大(就像金字塔的想法一样),其大多少由 FOV 定义。FOV 越大,后平面与近平面相比就越大,从而将更多的对象放在屏幕上。
屏幕空间
最后一个空间基本上是后缓冲区的 x 和 y 值(以像素为单位),其中 (0, 0) 标记空间的左上角,(width, height) 标记空间的右下角。这是实际显示在显示器上的 2D 空间。
我们不必定义这个空间,它更像是显示器的物理空间的概念。但是,当我们用鼠标选择时,我们将使用这个空间的概念。我们将在屏幕空间中获取鼠标的 x 和 y 坐标,以查看我们是否单击了 3d 对象。
变换空间
变换空间通常意味着将顶点从一个空间变换到另一个空间。
渲染管道使用我们将定义的三个空间:世界、视图和投影。我们将从一个空间变换到另一个空间,并将结果矩阵放入另一个称为 WVP(世界视图投影)的矩阵中。
要将它们从一个变换到另一个,我们将把它们相乘,但请记住,我们相乘矩阵的顺序会改变结果矩阵,因此我们将按以下顺序相乘:世界 视图 投影。然后,我们将 WVP 矩阵发送到效果文件中的常量缓冲区,VS 将使用该缓冲区来变换对象的顶点。
因此顺序如下:本地空间中的对象顶点将被发送到顶点着色器。VS 将使用在我们调用绘制函数之前传递给它的 WVP,并将顶点位置与 WVP 矩阵相乘。这会导致对象的位置处于我们想要的世界位置,并且如果对象不在摄像机视野范围内,则会将其从渲染中剪裁掉。
常量缓冲区
常量缓冲区基本上是效果文件中的结构,它包含我们能够从游戏代码中更新的变量。我们可以使用 cbuffer 类型创建一个常量缓冲区。我们将使用的示例如下所示:
cbuffer cbPerObject
{
float4x4 WVP;
};
常量缓冲区应根据更新频率进行区分。这样,我们可以尽可能少地调用它们,因为执行此操作需要处理时间。我们调用常量缓冲区的不同频率的示例如下:
- 每个场景(每个场景仅调用一次缓冲区,例如整个场景中不会改变的光照)
- 每帧(例如每帧都会改变位置的照明或其他东西,如太阳在天空中移动)
- 每个对象(就像我们将要做的那样。我们更新每个对象的 WVP,因为每个对象都有不同的世界空间、位置、旋转或缩放)
全局声明
这是一个 direct3d 缓冲区接口,我们将使用它来存储我们的常量缓冲区变量(WVP 矩阵),以便发送到效果文件中的实际常量缓冲区。
ID3D11Buffer* cbPerObjectBuffer;
现在我们定义四个矩阵和三个向量。四个矩阵代表物体顶点到达屏幕需要经过的各个不同空间,三个向量用于定义相机的位置、目标和向上方向。
XMMATRIX WVP;
XMMATRIX World;
XMMATRIX camView;
XMMATRIX camProjection;//相机投影
XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;
常量缓冲区结构
我们需要确保代码中的常量缓冲区与效果文件中的常量缓冲区结构布局完全相同。然后我们创建一个常量缓冲区对象。
struct cbPerObject
{
XMMATRIX WVP;
};
cbPerObject cbPerObj;
释放Buffer接口
cbPerObjectBuffer->Release();
在代码中创建常量缓冲区
这里我们创建一个缓冲区,它将保存我们想要传递给效果文件中的常量缓冲区的信息。我们首先创建缓冲区描述,就像我们已经知道如何做的那样。不过这里唯一的区别是,我们将绑定标志成员更改为 D3D11_BIND_CONSTANT_BUFFER。这表示缓冲区将绑定到效果文件中的常量缓冲区。之后,我们使用刚刚创建的描述创建缓冲区 cbPerObjectBuffer。
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;
hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);
相机
在这里我们将定义相机的位置、目标和向上向量。非常容易理解,除了还有第四个参数。我们不使用它,所以将其设置为 0.0f。这是因为微软希望我们使用更流行的 xna 数学库……所以就按照流程来吧。
camPosition = XMVectorSet( 0.0f, 0.0f, -0.5f, 0.0f );
camTarget = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
camUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
建视图空间
我们可以使用 xna 库中的 XMMatrixLookAtLH() 函数创建视图空间矩阵。参数应该不难理解。我们在这里初始化相机矩阵,但稍后当我们创建第一人称和第三人称相机时,它将每帧更新一次。
camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
创建投影空间
现在我们使用 XMMatrixPerspectiveFovLH() xna 函数创建投影空间矩阵。这通常不必每帧都更新,但有时您可能希望更新它以获得某种效果。这是函数参数:
XMMATRIX XMMatrixPerspectiveFovLH
(
FLOAT FovAngleY,
FLOAT AspectRatio,
FLOAT NearZ,
FLOAT FarZ
)
其中每个参数的描述如下:
- FovAngleY - 沿 y 轴的视野(以弧度为单位)。
- AspectRatio - 纵横比,通常是宽度/高度。
- NearZ - 一个浮点数,描述了从相机到近 z 平面的距离。
- FarZ - 一个浮点数,描述了从相机到远平面的距离。
如果物体距离相机的远平面较远,则不会渲染该物体;如果物体距离相机的近平面较近,则也不会渲染该物体。
注意我们如何将 Width 转换为浮点类型。这是因为 Width 和 Height 是整数,因此将它们相除也会产生一个整数。我们希望宽高比用小数表示,除非宽度和高度恰好相同,否则将产生 1:1 的比例,或者当我们进行 Width/Height 运算时,得出 1.0f 的乘积。
camProjection = XMMatrixPerspectiveFovLH( 0.4f*3.14f, (float)Width/Height, 1.0f, 1000.0f);
创建 WVP 矩阵
在这里,我们将创建 WVP 矩阵,该矩阵将被发送到顶点着色器,以正确重新定位对象的顶点。每个对象都有自己的世界空间,因此应该对场景中的每个对象执行此操作。我们使用 XMMatrixIdentity() 函数重置世界矩阵,该函数返回一个空白矩阵。然后我们通过按顺序乘以世界、视图和投影矩阵来定义 WVP。
World = XMMatrixIdentity();
WVP = World * camView * camProjection;
更新常量缓冲区
记住这一点很重要。在 direct3d 11 中将矩阵发送到效果文件时,我们必须发送“转置”矩阵,其中行和列被交换。我们将缓冲区 WVP 矩阵设置为 WVP 矩阵的转置。然后,我们使用 ID3D11DeviceContext 接口的 UpdateSubresource() 方法,使用包含更新的 WVP 矩阵的 cbPerObj 结构更新应用程序常量缓冲区缓冲区。之后,我们使用方法 ID3D11DeviceContext::VSSetConstantBuffers() 将 Vertex Shaders 常量缓冲区设置为应用程序常量缓冲区缓冲区。
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
常量缓冲区
这是我们效果文件中的常量缓冲区。我们使用 cbuffer 创建常量缓冲区结构。记得将它们分开,并根据更新频率命名。效果文件中的矩阵变量由 float4x4 类型表示。您可以通过更改数字来获得其他大小。
cbuffer cbPerObject
{
float4x4 WVP;
};
更新的顶点缓冲区
这是我们的顶点缓冲区。我们在这里唯一做的事情就是添加一条新线,它将根据我们上次更新的 WVP 矩阵平移对象顶点。我们可以使用 mul() 函数乘以顶点位置。
VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.Color = inColor;
return output;
}
现在我们有了一个简单的静态相机。我希望你能更好地理解 3D 空间,我知道我解释得不是很好,但我不想让你厌烦这些细节。
代码
main.cpp
//Include and link appropriate libraries and headers//
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>
//Global Declarations - Interfaces//
IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;
ID3D11Buffer* squareIndexBuffer;
ID3D11DepthStencilView* depthStencilView;
ID3D11Texture2D* depthStencilBuffer;
ID3D11Buffer* squareVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;
///////////////**************new**************////////////////////
ID3D11Buffer* cbPerObjectBuffer;
///////////////**************new**************////////////////////
//Global Declarations - Others//
LPCTSTR WndClassName = L"firstwindow";
HWND hwnd = NULL;
HRESULT hr;
const int Width = 300;
const int Height = 300;
///////////////**************new**************////////////////////
XMMATRIX WVP;
XMMATRIX World;
XMMATRIX camView;
XMMATRIX camProjection;
XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;
///////////////**************new**************////////////////////
//Function Prototypes//
bool InitializeDirect3d11App(HINSTANCE hInstance);
void CleanUp();
bool InitScene();
void UpdateScene();
void DrawScene();
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd,
int width, int height,
bool windowed);
int messageloop();
LRESULT CALLBACK WndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam);
///////////////**************new**************////////////////////
//Create effects constant buffer's structure//
struct cbPerObject
{
XMMATRIX WVP;
};
cbPerObject cbPerObj;
///////////////**************new**************////////////////////
//Vertex Structure and Vertex Layout (Input Layout)//
struct Vertex //Overloaded Vertex Structure
{
Vertex(){}
Vertex(float x, float y, float z,
float cr, float cg, float cb, float ca)
: pos(x,y,z), color(cr, cg, cb, ca){}
XMFLOAT3 pos;
XMFLOAT4 color;
};
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE(layout);
int WINAPI WinMain(HINSTANCE hInstance, //Main windows function
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true))
{
MessageBox(0, L"Window Initialization - Failed",
L"Error", MB_OK);
return 0;
}
if(!InitializeDirect3d11App(hInstance)) //Initialize Direct3D
{
MessageBox(0, L"Direct3D Initialization - Failed",
L"Error", MB_OK);
return 0;
}
if(!InitScene()) //Initialize our scene
{
MessageBox(0, L"Scene Initialization - Failed",
L"Error", MB_OK);
return 0;
}
messageloop();
CleanUp();
return 0;
}
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd,
int width, int height,
bool windowed)
{
typedef struct _WNDCLASS {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
wc.lpszMenuName = NULL;
wc.lpszClassName = WndClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Error registering class",
L"Error", MB_OK | MB_ICONERROR);
return 1;
}
hwnd = CreateWindowEx(
NULL,
WndClassName,
L"Lesson 4 - Begin Drawing",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
NULL,
NULL,
hInstance,
NULL
);
if (!hwnd)
{
MessageBox(NULL, L"Error creating window",
L"Error", MB_OK | MB_ICONERROR);
return 1;
}
ShowWindow(hwnd, ShowWnd);
UpdateWindow(hwnd);
return true;
}
bool InitializeDirect3d11App(HINSTANCE hInstance)
{
//Describe our SwapChain Buffer
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
bufferDesc.Width = Width;
bufferDesc.Height = Height;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//Describe our SwapChain
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
//Create our SwapChain
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);
//Create our BackBuffer
ID3D11Texture2D* BackBuffer;
hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer );
//Create our Render Target
hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView );
BackBuffer->Release();
//Describe our Depth/Stencil Buffer
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = Width;
depthStencilDesc.Height = Height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
//Create the Depth/Stencil View
d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);
//Set our Render Target
d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, depthStencilView );
return true;
}
void CleanUp()
{
//Release the COM Objects we created
SwapChain->Release();
d3d11Device->Release();
d3d11DevCon->Release();
renderTargetView->Release();
squareVertBuffer->Release();
squareIndexBuffer->Release();
VS->Release();
PS->Release();
VS_Buffer->Release();
PS_Buffer->Release();
vertLayout->Release();
depthStencilView->Release();
depthStencilBuffer->Release();
///////////////**************new**************////////////////////
cbPerObjectBuffer->Release();
///////////////**************new**************////////////////////
}
bool InitScene()
{
//Compile Shaders from shader file
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0);
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0);
//Create the Shader Objects
hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);
//Set Vertex and Pixel Shaders
d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);
//Create the vertex buffer
Vertex v[] =
{
Vertex( -0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f ),
Vertex( -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f ),
Vertex( 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f ),
Vertex( 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f ),
};
DWORD indices[] = {
0, 1, 2,
0, 2, 3,
};
D3D11_BUFFER_DESC indexBufferDesc;
ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * 2 * 3;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);
d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 4;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
vertexBufferData.pSysMem = v;
hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &squareVertBuffer);
//Set the vertex buffer
UINT stride = sizeof( Vertex );
UINT offset = 0;
d3d11DevCon->IASetVertexBuffers( 0, 1, &squareVertBuffer, &stride, &offset );
//Create the Input Layout
hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(),
VS_Buffer->GetBufferSize(), &vertLayout );
//Set the Input Layout
d3d11DevCon->IASetInputLayout( vertLayout );
//Set Primitive Topology
d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
//Create the Viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = Width;
viewport.Height = Height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
//Set the Viewport
d3d11DevCon->RSSetViewports(1, &viewport);
///////////////**************new**************////////////////////
//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;
hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);
//Camera information
camPosition = XMVectorSet( 0.0f, 0.0f, -0.5f, 0.0f );
camTarget = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
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, Width/Height, 1.0f, 1000.0f);
///////////////**************new**************////////////////////
return true;
}
void UpdateScene()
{
}
void DrawScene()
{
//Clear our backbuffer
float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);
//Refresh the Depth/Stencil view
d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);
///////////////**************new**************////////////////////
//Set the World/View/Projection matrix, then send it to constant buffer in effect file
World = XMMatrixIdentity();
WVP = World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
///////////////**************new**************////////////////////
//Draw the triangle
d3d11DevCon->DrawIndexed( 6, 0, 0 );
//Present the backbuffer to the screen
SwapChain->Present(0, 0);
}
int messageloop(){
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(true)
{
BOOL PeekMessageL(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg
);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else{
// run game code
UpdateScene();
DrawScene();
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch( msg )
{
case WM_KEYDOWN:
if( wParam == VK_ESCAPE ){
DestroyWindow(hwnd);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,
msg,
wParam,
lParam);
}
Effects.fx
cbuffer cbPerObject
{
float4x4 WVP;
};
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR;
};
VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.Color = inColor;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
return input.Color;
}