Lesson 15: SDK文档:Tutorial 4 3D Spaces分析
来源:互联网 发布:mac 4k 显示器 hdmi2 编辑:程序博客网 时间:2024/05/24 06:33
Constant Buffer
Constant buffer(cb)是DX10中引入的概念,它取代了DX9时代GPU常量寄存器的概念,允许通过一块大小可变的buffer向shader提供常量数据,而不是之前数量非常受限的n个寄存器,这也是我们遇到的第一种可在shader着色阶段由HLSL访问的资源。 管线的每个可编程阶段都能同时访问一个或者几个cb,对于shader代码来说,cb中的数据都是全局常量,作为cb而创建的资源不能绑定到其他类型的管线位置,但同一个cb可以同时绑定到管线的多个不同阶段。
世界空间与世界矩阵
模型空间:
每个模型(3D物体)都有它自己的空间,空间的中心(原点)就是模型的中心。在模型空间里,只有模型上的不同点有位置的相对关系。
世界空间:
世界就是物体(模型)所存在的地方。当我们把一个模型放进世界里面去,那么它就有了一个世界坐标,这个世界坐标是用来标记世界中不同的模型所处的位置的。在世界空间里,世界的中心就是原点(0, 0, 0),也就是你显示器屏幕中间的那一点。我们可以在世界空间里摆放很多个模型,并且设置它们在世界空间中的坐标,这样模型与模型之间就有了相对的位置。
世界矩阵:
我们可以利用它来改变世界空间的坐标。这样,在世界空间里面的模型就可以移动、旋转和缩放了。
世界变换包括平移、旋转和缩放变换。
视图空间与视图矩阵
在视图空间里,我们可以建立我们在三维空间中的眼睛:摄像机。我们就是通过这个虚拟的摄像机来观察世界空间中的模型的。所以视图空间也叫摄像机空间。
要建立起这个虚拟的摄像机,我们需要一个视图矩阵,产生视图矩阵的一个函数是
XMMATRIX XMMatrixLookAtLH( // 设置摄像机的位置 XMVECTOR EyePosition, // 设置摄像机的观察点 XMVECTOR FocusPosition, // 设置方向“上” XMVECTOR UpDirection);
这个函数的后缀LH是表示左手系的意思,左手系中的Z正方向是指向显示器里面,另外有一个叫D3DXMatrixLookAtRH的函数。
投影与投影矩阵
定义投影矩阵很像是定义摄像机的镜头,下面看它的函数声明:
XMMATRIX XMMatrixPerspectiveFovLH( // 定义镜头垂直观察范围,以弧度为单位。 float FovAngleY, // 设置纵横比。如果定义为1,那么所看到的物体大小不变。 // 如果定义为其它值,你所看到的物体就会变形。 // 不过一般情况下这个值设为显示器屏幕的长宽比。 float AspectRati, // 设置摄像机所能观察到的最近距离 float NearZ, // 设置摄像机所能观察到的最远距离 float FarZ);
头文件:
#include <windows.h>#include <d3d11.h>#include <d3dx11.h>#include <d3dcompiler.h>#include <xnamath.h>#include "resource.h"
结构体:
// Structures// 顶点结构体struct SimpleVertex{ XMFLOAT3 Pos; XMFLOAT4 Color;};// ConstantBuffer结构体struct ConstantBuffer{ XMMATRIX mWorld; XMMATRIX mView; XMMATRIX mProjection;};
全局变量声明:
// Global VariablesHINSTANCE g_hInst = NULL; //实例句柄HWND g_hWnd = NULL; //窗口句柄D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL; //驱动类型D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0; //特征等级ID3D11Device* g_pd3dDevice = NULL; //设备接口指针ID3D11DeviceContext* g_pImmediateContext = NULL; //设备上下文接口指针IDXGISwapChain* g_pSwapChain = NULL; //交换链接口指针ID3D11RenderTargetView* g_pRenderTargetView = NULL; //渲染目标视图接口指针ID3D11VertexShader* g_pVertexShader = NULL; //顶点着色器接口指针ID3D11PixelShader* g_pPixelShader = NULL; //像素着色器接口指针ID3D11InputLayout* g_pVertexLayout = NULL; //顶点布局接口指针ID3D11Buffer* g_pVertexBuffer = NULL; //顶点缓存接口指针ID3D11Buffer* g_pIndexBuffer = NULL; //索引缓存接口指针ID3D11Buffer* g_pConstantBuffer = NULL; //常量数据缓存接口指针XMMATRIX g_World; //世界变换矩阵XMMATRIX g_View; //视图变换矩阵XMMATRIX g_Projection; //投影变换矩阵
函数声明:
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); //窗口初始化函数HRESULT InitDevice(); //设备初始化函数void CleanupDevice(); //清除设备函数LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); //窗口过程函数void Render(); //渲染函数
程序入口点函数:
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ // 框架不变}
窗口初始化函数:
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // 框架不变}
辅助编译着色器函数:
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut ){ // 框架不变}
设备初始化函数:
// Create Direct3D device and swap chainHRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0;#ifdef _DEBUG createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;#endif D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = ARRAYSIZE( driverTypes ); D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, }; UINT numFeatureLevels = ARRAYSIZE( featureLevels ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ) { g_driverType = driverTypes[driverTypeIndex]; hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // Create a render target view ID3D11Texture2D* pBackBuffer = NULL; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL ); // Setup the viewport D3D11_VIEWPORT vp; vp.Width = (FLOAT)width; vp.Height = (FLOAT)height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; g_pImmediateContext->RSSetViewports( 1, &vp ); // Compile the vertex shader ID3DBlob* pVSBlob = NULL; hr = CompileShaderFromFile( L"Tutorial04 d3d11.fx", "VS", "vs_4_0", &pVSBlob ); if( FAILED( hr ) ) { MessageBox( NULL, L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK ); return hr; } // Create the vertex shader hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader ); if( FAILED( hr ) ) { pVSBlob->Release(); return hr; } // 定义输入布局 // Define the input layout D3D11_INPUT_ELEMENT_DESC layout[] = { // 描述POSITION属性 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 描述COLOR属性 { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = ARRAYSIZE( layout ); // 创建输入布局 // Create the input layout hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &g_pVertexLayout ); pVSBlob->Release(); if( FAILED( hr ) ) return hr; // 设置输入布局 // Set the input layout g_pImmediateContext->IASetInputLayout( g_pVertexLayout ); // Compile the pixel shader ID3DBlob* pPSBlob = NULL; hr = CompileShaderFromFile( L"Tutorial04 d3d11.fx", "PS", "ps_4_0", &pPSBlob ); if( FAILED( hr ) ) { MessageBox( NULL, L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK ); return hr; } // Create the pixel shader hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader ); pPSBlob->Release(); if( FAILED( hr ) ) return hr; // 创建顶点缓存 // Create vertex buffer SimpleVertex vertices[] = { // 8个顶点 { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) }, { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) }, { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f ) }, { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) }, { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 0.0f, 1.0f, 1.0f ) }, { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 0.0f, 1.0f ) }, { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) }, { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) }, }; D3D11_BUFFER_DESC bd; ZeroMemory( &bd, sizeof(bd) ); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 8; 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; // 设置顶点缓存 // Set vertex buffer UINT stride = sizeof( SimpleVertex ); UINT offset = 0; g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset ); // 创建索引缓存 // Create index buffer WORD indices[] = { // 12条边 3,1,0, 2,1,3, 0,5,4, 1,5,0, 3,4,7, 0,4,3, 1,6,5, 2,6,1, 2,7,6, 3,7,2, 6,4,5, 7,4,6, }; bd.Usage = D3D11_USAGE_DEFAULT; // 3*2*6 = 36 个顶点大小 bd.ByteWidth = sizeof( WORD ) * 36; // 36 vertices needed for 12 triangles in a triangle list bd.BindFlags = D3D11_BIND_INDEX_BUFFER; bd.CPUAccessFlags = 0; InitData.pSysMem = indices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ); if( FAILED( hr ) ) return hr; // 设置索引缓存 // Set index buffer g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 ); // 设置原始拓扑 // Set primitive topology // 三角形列表 g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // 创建常量数据缓冲区 // Create the constant buffer 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_pConstantBuffer ); if( FAILED( hr ) ) return hr; // 初始化世界变换矩阵 // Initialize the world matrix // 返回单位矩阵,即对角线全1,其他全0 g_World = XMMatrixIdentity(); // 初始化视图变换矩阵 // Initialize the view matrix XMVECTOR Eye = XMVectorSet( 0.0f, 1.0f, -5.0f, 0.0f ); XMVECTOR At = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); g_View = XMMatrixLookAtLH( Eye, At, Up ); // 初始化投影变换矩阵 // Initialize the projection matrix // XM_PIDIV2表示镜头垂直观察范围是PI/2即90° g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV2, width / (FLOAT)height, 0.01f, 100.0f ); return S_OK;}
清除设备函数:
void CleanupDevice(){ if( g_pImmediateContext ) g_pImmediateContext->ClearState(); if( g_pConstantBuffer ) g_pConstantBuffer->Release(); if( g_pVertexBuffer ) g_pVertexBuffer->Release(); if( g_pIndexBuffer ) g_pIndexBuffer->Release(); if( g_pVertexLayout ) g_pVertexLayout->Release(); if( g_pVertexShader ) g_pVertexShader->Release(); if( g_pPixelShader ) g_pPixelShader->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pImmediateContext ) g_pImmediateContext->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release();}
窗口过程函数:
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ // 框架不变}
渲染函数:
void Render(){ // 根据游戏时间旋转相应矩阵 // 更新时间 // Update our time // 定义一个静态变量表示游戏时间 static float t = 0.0f; // 每一帧运行时更新t值,同时对矩阵作相应旋转 if( g_driverType == D3D_DRIVER_TYPE_REFERENCE ) { t += ( float )XM_PI * 0.0125f; } else { static DWORD dwTimeStart = 0; DWORD dwTimeCur = GetTickCount(); if( dwTimeStart == 0 ) dwTimeStart = dwTimeCur; // 构造一个从0到1的连续的时间周期 t = ( dwTimeCur - dwTimeStart ) / 1000.0f; } // 立方体动画 // // Animate the cube // // 将世界变换矩阵沿Y轴旋转t g_World = XMMatrixRotationY( t ); // 清除后台缓冲区 // // Clear the back buffer // float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red,green,blue,alpha g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); // 更新常量数据缓存Updating Constant Buffers // // Update variables // ConstantBuffer cb; // 因为C++中的矩阵处理与HLSL不同,我们先要得到转置矩阵 cb.mWorld = XMMatrixTranspose( g_World ); cb.mView = XMMatrixTranspose( g_View ); cb.mProjection = XMMatrixTranspose( g_Projection ); // 利用cb通过设备上下文调用UpdateSubresource函数更新常量数据缓存 g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb, 0, 0 ); // 渲染三角形 // // Renders a triangle // // 设置顶点着色器 g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 ); // 设置常量数据缓冲区 g_pImmediateContext->VSSetConstantBuffers( 0, 1, &g_pConstantBuffer ); // 设置像素着色器 g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 ); // 利用索引绘制图案 g_pImmediateContext->DrawIndexed( 36, 0, 0 ); // 36 vertices needed for 12 triangles in a triangle list // 页面翻转 // // Present our back buffer to our front buffer // g_pSwapChain->Present( 0, 0 );}
文档中关于顶点着色器修改的说明:
因为顶点布局被定义在模型空间中,所以输出前我们必须在顶点着色器中对其进行转换。
我们通过三步来完成转换:
1.从模型空间转换到世界空间
2.从世界空间转换到视图空间
3.从视图空间转换到投影空间
在FX文件中:
定义全局变量constant buffer
cbuffer ConstantBuffer : register( b0 ) { matrix World; matrix View; matrix Projection; }
更新顶点着色器:
VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR ) { VS_OUTPUT output = (VS_OUTPUT)0; // each mul() applies one transformation to the input position output.Pos = mul( Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Color = Color; return output; }
- Lesson 15: SDK文档:Tutorial 4 3D Spaces分析
- Lesson 16: SDK文档:Tutorial 5 3D Transformation分析
- Tutorial 4: 3D Spaces(Directx手册)
- Lesson 13: SDK文档:Tutorial 1 Direct3D 11 Basics分析
- Lesson 17: SDK文档:Tutorial 6 Lighting分析
- Lesson 18: SDK文档:Tutorial 7 Texture Mapping and Constant Buffers分析
- 【DirectX 11 SDK 学习笔记】3D Spaces
- Lesson 14: SDK文档:Tutorial02 Rendering a Triangle分析
- Direct3D 11第四节 3D Spaces
- Tinyos tutorial learning tips -- lesson 4
- Tinyos tutorial learning tips -- lesson 3
- JAVA EE 7 SDK Tutorial分析
- Tutorial Lesson 1: Using Quartz
- DirectX9 SDK Samples(4) Tutorial 4: Lights
- AndEngine Tutorial: Rotation in 3D
- iPhone之Quartz 2D系列--颜色和颜色空间(4)Color and Color Spaces
- iPhone之Quartz 2D系列--颜色和颜色空间(4)Color and Color Spaces
- iPhone之Quartz 2D系列--颜色和颜色空间(4)Color and Color Spaces
- 2016.12.15 接口
- DOM中监听节点变化的事件(变动事件)的用法 — 第13.4.6节
- 88
- 跟小马哥学算法leetcode_13
- sparksql各种数据源
- Lesson 15: SDK文档:Tutorial 4 3D Spaces分析
- Html学习笔记 --- Html与Htm区别与联系
- Android studio运行时闪退找不到错误日志
- 小程序案例-美容预约
- Android从零开搞系列:网络框架系列(1)OkHttp+可测试的服务器URL+Gson分析(上)
- 【BZOJ 1861】[Zjoi2006]Book 书架 splay
- linux中shell变量$#,$@,$0,$1,$2的含义解释
- html
- hadoop map reduce 中间的combiner的作用