渲染--案例Tutorial04

MSDN

一、需要存在一个渲染目标ID3D11RenderTargetView

 1、创建渲染目标,通过D3Ddevice

hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );

      A、获取的D3D设备(D3D设备是通过D3D11CreateDevice 接口获取而来的,但是对于不同系统、硬件、驱动等,可能支持的格式D3D12 D3D11 D3D10..)

// D3D设备类型---创建一个可用的设备,如果第一种不可用,则使用第二种。。类推
D3D_DRIVER_TYPE driverTypes[] =
{
    D3D_DRIVER_TYPE_HARDWARE,    // 硬件设备
    D3D_DRIVER_TYPE_WARP,        // 图形变换设备
    D3D_DRIVER_TYPE_REFERENCE,   // 基础设备
};

// 设备支持功能等级
D3D_FEATURE_LEVEL featureLevels[] =
{
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
};

// 创建设备--numDriverTypes=driverTypes个数,numFeatureLevels = featureLevels个数, g_pImmediateContext---设备上下文
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
    g_driverType = driverTypes[driverTypeIndex];
    hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
                            D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );

    if ( hr == E_INVALIDARG )
    {
        // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
        hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
                                D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
    }

    if( SUCCEEDED( hr ) )
        break;
}

      B、渲染目标的backBuffer是通过交换链获取而来的

            a、通过获取DXGIFactory2

// 获取到m_pBackBuffer
ID3D11Texture2D* pBackBuffer = nullptr;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( &pBackBuffer ) );

// 获取交换链IDXGISwapChain--from IDXGISwapChain1
hr = g_pSwapChain1->QueryInterface( __uuidof(IDXGISwapChain), reinterpret_cast<void**>(&g_pSwapChain) );

// 获取IDXGISwapChain1--通过IDXGIFactory2  g_hWnd---窗口句柄  sd=DXGI_SWAP_CHAIN_DESC1 交换链1参数
hr = dxgiFactory2->CreateSwapChainForHwnd( g_pd3dDevice, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1 );

DXGI_SWAP_CHAIN_DESC1 sd = {};
sd.Width = width;                                   // 窗口宽
sd.Height = height;                                 // 窗口高
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;             // 支持格式RGBA
sd.SampleDesc.Count = 1;                            // 个数
sd.SampleDesc.Quality = 0;                          // 图像质量等级。 质量越高,性能越低
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;   // 类型输出
sd.BufferCount = 1;                                 // buffer个数

// 获取DXGIFactory2--通过IDXGIFactory1
hr = dxgiFactory->QueryInterface( __uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2) );

// 获取IDXGIFactory1--通过D3D设备获取到DXGI枚举--IDXGIAdapter,然后通过IDXGIAdapter获得获取IDXGIFactory1
IDXGIFactory1* dxgiFactory = nullptr;
{
    IDXGIDevice* dxgiDevice = nullptr;
    hr = g_pd3dDevice->QueryInterface( __uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice) );
    if (SUCCEEDED(hr))
    {
        IDXGIAdapter* adapter = nullptr;
        hr = dxgiDevice->GetAdapter(&adapter);
        if (SUCCEEDED(hr))
        {
            hr = adapter->GetParent( __uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory) );
            adapter->Release();
        }
        dxgiDevice->Release();
    }
}

            b、通过DXGIFactory获取--优先使用第一种

// DirectX 11.0 systems
DXGI_SWAP_CHAIN_DESC 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;

hr = dxgiFactory->CreateSwapChain( g_pd3dDevice, &sd, &g_pSwapChain );

2、绑定输出--g_pImmediateContext  ID3D11DeviceContext(设备上下文)

// 获取设备上下文---ID3D11DeviceContext 通过D3D11CreateDevice 参考上面的获取设备
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, nullptr );  // 获取output-merger阶段绑定的资源指针。

二、初始化渲染数据(到底需要渲染个什么东西--多大、形状、颜色等)

1、初始化渲染视口

 D3D11_VIEWPORT vp;
 vp.Width = (FLOAT)width;   // 渲染的宽 ---分辨率
 vp.Height = (FLOAT)height; // 渲染的高---分辨率
 vp.MinDepth = 0.0f;        // 最小深度0~1(近裁平面)
 vp.MaxDepth = 1.0f;        // 最大深度0~1(远裁平面)
 vp.TopLeftX = 0;           // 视口左侧位置
 vp.TopLeftY = 0;           // 视口右侧位置
 
 g_pImmediateContext->RSSetViewports( 1, &vp );

2、初始化渲染大小、颜色---顶点数据

// 定义顶点数据结构---此内容存在Sharder中
struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;     // 位置 X、Y、Z、W
    float4 Color : COLOR0;        // 颜色 R、G、B、A
};

// 编译vertex shader
//VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
//{
//    VS_OUTPUT output = (VS_OUTPUT)0;
//    output.Pos = mul( Pos, World );
//    output.Pos = mul( output.Pos, View );
//    output.Pos = mul( output.Pos, Projection );
//    output.Color = Color;
//    return output;
//}
 
 ID3DBlob* pVSBlob = nullptr;
 hr = CompileShaderFromFile( L"Tutorial04.fxh", "VS", "vs_4_0", &pVSBlob );
 hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader );

3、定义输入布局

//typedef struct D3D11_INPUT_ELEMENT_DESC
//{
//    LPCSTR SemanticName;              // 用来描述属性的字符串,其实没什么卵用
//    UINT SemanticIndex;               // 表示SemanticName的属性有几个,用来补充SemanticName,0表示 索引为0 (1个)
//    DXGI_FORMAT Format;               // 格式
//    UINT InputSlot;                   // GPU可以从哪个顶点缓冲区获取这个元素。索引为0 (第1个)
//    UINT AlignedByteOffset;           // 一个顶点保存在一个顶点缓冲区中,这个顶点缓冲区是一块连续的内存。AlignedByteOffset告诉GPU偏移量来获取这个元素。
//    D3D11_INPUT_CLASSIFICATION InputSlotClass; // :为了区分顶点数据和实例数据
//    UINT InstanceDataStepRate;        // 指定每个实例数据有多少个实例要绘制...顶点数据设置为0   
//} D3D11_INPUT_ELEMENT_DESC

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 },  
}

//创建inputLayout  numElements---layout个数
hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
                          pVSBlob->GetBufferSize(), &g_pVertexLayout );
                          
g_pImmediateContext->IASetInputLayout( g_pVertexLayout );

4、编译pixel shader

//float4 PS( VS_OUTPUT input ) : SV_Target
//{
//    return input.Color;
//}

ID3DBlob* pPSBlob = nullptr;
hr = CompileShaderFromFile( L"Tutorial04.fxh", "PS", "ps_4_0", &pPSBlob );
hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader );

5、分配顶点内存

// Create vertex buffer---这里画出来的是一个立方体
SimpleVertex vertices[] =     // XMFLOAT3--- x、y、z   XMFLOAT4---r、g、b、a
{  
    { 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 ) },
};

6、初始化D3D11_BUFFER_DESC

// typedef struct D3D11_BUFFER_DESC {
// UINT        ByteWidth;             // 缓冲区大小
// D3D11_USAGE Usage;                 // 读取和写入缓冲区类型---D3D11_USAGE_DEFAULT(默认)、D3D11_USAGE_IMMUTABLE(只读--创建后无法更改)
                                      // D3D11_USAGE_DYNAMIC(可读可写)、D3D11_USAGE_STAGING(从GPU复制)
// UINT        BindFlags;             // 绑定类型分为VERTEX、Index。。。。等等
// UINT        CPUAccessFlags;        // CPU访问标志--使用Dynamic resources时指定可写
// UINT        MiscFlags;             // 其他标志--参看D3D11_RESOURCE_MISC_FLAG 
// UINT        StructureByteStride;   // 缓冲区结构中每个元素的大小
// } D3D11_BUFFER_DESC;

D3D11_BUFFER_DESC bd = {};
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 8;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;

7、初始化D3D11_SUBRESOURCE_DATA

// typedef struct D3D11_SUBRESOURCE_DATA {
// const void *pSysMem;             // 初始化后的顶点数据
// UINT       SysMemPitch;          // 纹理的一行开始到下一行的距离
// UINT       SysMemSlicePitch;     // 一个深度级别的起点到下一个深度级别的距离
// } D3D11_SUBRESOURCE_DATA;

 D3D11_SUBRESOURCE_DATA InitData = {};
 InitData.pSysMem = vertices;    

8、创建ID3D11Buffer---Vertex Buffer

hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
 
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

9、创建 index buffer(索引缓冲区)--参看MSDN,目的:为渲染做好准备

//vertices的index  每一行代表一个三角形,共十二行
WORD indices[] =
{
    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,
};

D3D11_BUFFER_DESC bd
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * 36;        // 都是用三角形绘制出来的---四边形可以看做2个三角形合并的结果,里锥体6个面,需要12个三角形
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;    // index buffer
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );

// 设置顶点数据
g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );

10、创建constant buffer

 D3D11_BUFFER_DESC bd
 bd.Usage = D3D11_USAGE_DEFAULT; 
 bd.ByteWidth = sizeof(ConstantBuffer);
 bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;    //constant buffer
 bd.CPUAccessFlags = 0;
 hr = g_pd3dDevice->CreateBuffer( &bd, nullptr, &g_pConstantBuffer );

11、初始化世界向量矩阵--初始化视图矩阵、初始化投影矩阵

XMMATRIX M;
M.r[0] = g_XMIdentityR0.v;     // x
M.r[1] = g_XMIdentityR1.v;     // y
M.r[2] = g_XMIdentityR2.v;     // z
M.r[3] = g_XMIdentityR3.v;     // w
return M;

// 初始化视图矩阵
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 );      // 通过at和up能确定看的角度

g_View = XMMatrixLookAtLH( Eye, At, Up );

// 初始化投影矩阵
g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV2, width / (FLOAT)height, 0.01f, 100.0f );

三、渲染

1、 根据时间获取到立方体动画 

// 获取时间
static float t = 0.0f;
if( g_driverType == D3D_DRIVER_TYPE_REFERENCE )
{
    t += ( float )XM_PI * 0.0125f;
}
else
{
    static ULONGLONG timeStart = 0;
    ULONGLONG timeCur = GetTickCount64();
    if( timeStart == 0 )
        timeStart = timeCur;
    t = ( timeCur - timeStart ) / 1000.0f;
}
// 获取动画
g_World = XMMatrixRotationY( t );

2、清除后台缓冲区

g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, Colors::MidnightBlue );

3、更新视图

ConstantBuffer cb;
cb.mWorld = XMMatrixTranspose( g_World );  // world表示当前空间物体的位置
cb.mView = XMMatrixTranspose( g_View );    // view表示我们眼睛观测点的位置
cb.mProjection = XMMatrixTranspose( g_Projection );             // 投影

// 更新buffer 
g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, nullptr, &cb, 0, 0 );

4、渲染(填充数据)

g_pImmediateContext->VSSetShader( g_pVertexShader, nullptr, 0 );
g_pImmediateContext->VSSetConstantBuffers( 0, 1, &g_pConstantBuffer );    
g_pImmediateContext->PSSetShader( g_pPixelShader, nullptr, 0 );   
g_pImmediateContext->DrawIndexed( 36, 0, 0 );        // 12个三角形 36个顶点

5、使用交换链更新缓冲区(后缓冲区更新到前缓冲区)

g_pSwapChain->Present( 0, 0 );

四、渲染图分析

从上面的渲染图形来看,像是一个三棱锥,并不是立方体,这和我们眼睛的位置,看的方向有关系

我们看到眼睛的位置,看的点,Y坐标都是一致的,我们为了更加准确的观看到图形的真实形状,我们吧eye的Y改为3,

XMVECTOR Eye = XMVectorSet( 0.0f, 3.0f, -5.0f, 0.0f );

此时看到的就是立方体了

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值