添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

在前面我们讲过了如何初始化D3D11Device设备初始化等等,这里所讲的绘制图形将在上一篇文章的项目里进行扩展,在屏幕中绘制图形。在3D的呈现中最小的单位为三角形,无论我们看到的是多么大或多么小的,都是有一个或很多个三角形通过各种方向,角度构成的,当然这会涉及到很多数学中的几何学问题,最悲剧的就是我在大学里却没学好代数以及几何学,有学也忘记了。不过Directx SDK中以及为我们解决了很多几何上的问题,通过他们的方法就可以得到结果,说了这么多目的就是我告诉大家,要掌握高阶运用,必然要学会基础知识,所以我们这里就来学习一下如何在屏幕上绘制一个三角形,并涂上颜色。

一个三角形由三个点组成,也可以说坐标。在坐标系里,三个不同的点就可以组成一个唯一的三角形,当然也就是唯一的面,我想3D图形是由很多个面组成的,这也就是最小单位为三角形的原因。为了能够让GPU(就是显卡中的CPU,简单的认为一下,(*^__^*) )呈现三角形,我们必须告诉他三个点的坐标,那样他才能够在屏幕中显示出来。例如:在2D中,我们要在屏幕中画出如下的图示的三角形,就必须告诉GPU他们三个顶点(0,0),(0,1),(1,0)的坐标,那样GPU才能够画出他们。

我们已经知道要把顶点告诉GPU,但是如何告诉他们呢?在Direct3D 11中,顶点信息如三角形三个顶点的坐标是存储在一个缓存资源中的,叫做顶点缓存(Vertex Buffer)。我们必须创建一个足够大的顶点缓存,让他能够承载三角形的三个顶点坐标信息。

INPUT LAYOUT

一个顶点不只包含一个坐标,还可能包含一个或多个颜色值,纹理坐标等等,而Input Layout就是定义这些信息如何在内存中存储:不同数据类型将会有不同的大小, 当然不同的大小也决定着不同的存储顺序。和C语言很像,一个顶点一般使用一个结构来定义。在这里,我们只需要定义一个三角形顶点的坐标,所以我们只要使用XMFLOAT3来定义一个坐标,具体代码如下:

#ifdef __cplusplus

_XMFLOAT3() {};
_XMFLOAT3(FLOAT _x, FLOAT _y, FLOAT _z) : x(_x), y(_y), z(_z) {};
_XMFLOAT3(CONST FLOAT * pArray);

_XMFLOAT3
& operator = (CONST _XMFLOAT3 & Float3);

#endif // __cplusplus

} XMFLOAT3;

// 以上是XMFLOAT3的结构信息,在3D中坐标的结构

struct SimpleVertex
XMFLOAT3 Pos;
// Position
}; UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
}     D3D11_INPUT_ELEMENT_DESC;

属性说明:

SemanticName:用来描述目的或名称的字符,只要任何符合C语言结构的字符串都可以使用,并且忽略大小写,比如用于描述顶点坐标可以使用“POSITION”字符串。
  • SemanticIndex:这个用来描述索引,当SemanticName相同的情况下就可以使用索引来描述到底哪个才是当前需要的。因为一个顶点可能包含多个颜色,或纹理坐标等等,例如多个颜色可以使用如COLOR0,COLOR1来描述,也可以都是用COLOR来描述,使用0和1来填充SemanticIndex。
  • Format:描述这个数据的数据类型,如: DXGI_FORMAT_R32G32B32_FLOAT描述3个32位的float数据类型,即12字节长度;而DXGI_FORMAT_R16G16B16A16_UINT表示4个16位的uint数据类型,即8字节长度。 InputSlot:输入槽,在前面提到过的,每一个顶点信息都通过一个Vertex Buffer输入让GPU识别,在Direct 3D 11中多个顶点信息可以同时的输入,最多可以有16个,这样就需要让GPU知道当前将使用哪个Vertex Buffer信息,也就是这个值将在0到15之间了。
    AlignedByteOffset:内存偏移量,告诉GPU当前缓存内存起始偏移量。
    InputSlotClass :这个一般使用 D3D11_INPUT_PER_VERTEX_DATA来填充,当使用实例数据类型时,将使用D3D11_INPUT_PER_INSTANCE_DATA,这个是比较高级的或许在我们以后的学习当中会遇到,这里我们不大清楚,就先放过。
    InstanceDataStepRate :这个用于D3D11_INPUT_PER_INSTANCE_DATA时候,如果不是则必须将其设置为0。

    了解了上面的信息,我们就可以定义我们自己的

    D3D11_INPUT_ELEMENT_DESC了,具体代码如下所示: 1 // Define the input layout
    2 D3D11_INPUT_ELEMENT_DESC layout[] =
    3 {
    4 { " POSITION " , 0 , DXGI_FORMAT_R32G32B32_FLOAT, 0 , 0 , D3D11_INPUT_PER_VERTEX_DATA, 0 },
    5 };
    6 UINT numElements = ARRAYSIZE( layout );

    Vertex Layout

    顶点布局主要就是为了给顶点着色器(Vertex Shader)提供计算的【注:也许这个描述不正确】,为了创建一个顶点布局就需要顶点着色器输入签名,我们使用ID3DBlob接口对象来描述,而ID3DBlob接口通过D3DX11CompileFromFile来检索顶点着色器包含签名的二进制数据。只要我们有了这个数据,就可以通过ID3D11Device::CreateInputLayout()方法来创建我们的Vertex Layout对象,和使用ID3D11DeviceContext::IASetInputLayout()方法来激活它,具体代码如下:

    2 if ( FAILED( g_pd3dDevice -> CreateInputLayout( layout, numElements, pVSBlob -> GetBufferPointer(),
    3 pVSBlob -> GetBufferSize(), & g_pVertexLayout ) ) )
    4 return FALSE;
    5 // Set the input layout
    6 g_pImmediateContext -> IASetInputLayout( g_pVertexLayout );

    创建Vertex Buffer

    知道了上面的内容我们还需要做一件事,在初始化时我们必须创建一个Vertex Buffer并且承载了这个顶点的数据信息。为了创建Vertex Buffer,必须填充两个结构D3D11_BUFFER_DESC和D3D11_SUBRESOURCE_DATA,然后使用ID3D11Device::CreateBuffer()方法进行创建。D3D11_BUFFER_DESC结构对Vertex Buffer要创建的内容对象进行描述,而

    D3D11_SUBRESOURCE_DATA则是包含了具体的数据信息,这些数据信息在创建时会进行拷贝。创建缓存和初始化是在同一时间完成的,在创建后我们可以使用ID3D11DeviceContext::IASetVertexBuffers()方法将其绑定到设备中,那样我们就可以在屏幕上呈现出来了,具体代码如下: XMFLOAT3(
    0.0f , 0.5f , 0.5f ),
    XMFLOAT3(
    0.5f , - 0.5f , 0.5f ),
    XMFLOAT3(
    - 0.5f , - 0.5f , 0.5f ),
    D3D11_BUFFER_DESC bd;
    ZeroMemory(
    & bd, sizeof (bd) );
    bd.Usage
    = D3D11_USAGE_DEFAULT;
    bd.ByteWidth
    = sizeof ( SimpleVertex ) * 3 ;
    bd.BindFlags
    = D3D11_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags
    = 0 ;
    bd.MiscFlags
    = 0 ;
    D3D11_SUBRESOURCE_DATA InitData;
    ZeroMemory(
    & InitData, sizeof (InitData) );
    InitData.pSysMem
    = vertices;
    if ( FAILED( g_pd3dDevice -> CreateBuffer( & bd, & InitData, & g_pVertexBuffer ) ) )
    return FALSE;

    // Set vertex buffer
    UINT stride = sizeof ( SimpleVertex );
    UINT offset
    = 0 ;
    g_pImmediateContext
    -> IASetVertexBuffers( 0 , 1 , & g_pVertexBuffer, & stride, & offset );

    Primitive Topology (原型拓扑结构)

    从上面我们可以得知,如果要呈现一个三角形那样就需要将三个顶点信息告知GPU,那样如果两个三角形就必须告诉GPU6个顶点的信息,如果一个四边形(两个三角形组成),也就是说有两个顶点是共有的,PrimitiveTopology就是为了解决这个问题的。在四边形中,只要传入是个顶点信息,就可以画出四边形了,如图所示,就可以很好的理解了。

    如上图,如果要呈现3a中的图,只要告诉GPU是个顶点,GPU就会直接画出这个四边形了,当然也要注意一下顺序:A B C D,其实在Vertex Buffer中描述的是A B C和B C D,这样 B C两点是共用的,当然在3b图形中也一样。我们只要设置如下代码就可以得到,如下所示:

    g_pImmediateContext -> IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    接下来就是画出三角形,以上这些都是在设备初始化后进行的。而画出三角形就需要用到顶点和像素着色器,具体代码如下:

    void Render()
    // 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 );

    // Render a triangle
    g_pImmediateContext -> VSSetShader( g_pVertexShader, NULL, 0 );
    g_pImmediateContext
    -> PSSetShader( g_pPixelShader, NULL, 0 );
    g_pImmediateContext
    -> Draw( 3 , 0 );

    // Present the information rendered to the back buffer to the front buffer (the screen)
    g_pSwapChain -> Present( 0 , 0 );

    最终显示结果如下:

    本文转自网魂小兵博客园博客,原文链接:http://www.cnblogs.com/xdotnet/archive/2011/07/26/directx11_direct3d_reader_triangle.html,如需转载请自行联系原作者