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;    }
0 0
原创粉丝点击