Practical Rendering and Computation with Direct3D 11
+ -

04.开始绘制2

2024-06-11 41 0

顶点结构与输入布局

我们制作的所有3D对象都将由具有属性(如颜色)的点组成,这些属性称为顶点。我们必须制作自己的顶点结构。这是一个重载的顶点结构(因此我们可以轻松动态地创建和编辑顶点),只有一个位置。注意XMFLOAT3。正如我在上一课中提到的,direct3d正在从d3dx数学库转移到更流行的xna数学库。之前我们会使用D3DXVECTOR3。

之后,您可以看到我们的输入布局。使用D3D11_input_ELEMENT_DESC结构的数组定义输入布局。D3D11_INPUT_ELEMENT_DESC如下所示:

typedef struct D3D11_INPUT_ELEMENT_DESC
{
   LPCSTR                       SemanticName;
   UINT                         SemanticIndex;
   DXGI_FORMAT                  Format;
   UINT                         InputSlot;
   UINT                         AlignedByteOffset;
   D3D11_INPUT_CLASSIFICATION   InputSlotClass;
   UINT                         InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;

每个成员如下所述:

  • SemanticName :这只是一个要与元素关联的字符串。此字符串将用于将顶点结构中的元素映射到顶点着色器中的元素。
  • SemanticIndex :这基本上只是语义名称后面的一个数字,用作索引。例如,如果我们在顶点结构中有两个纹理元素,而不是创建两个不同的纹理语义名称,我们可以只使用两个不同索引。如果顶点着色器代码中的语义名称后面没有索引,则默认为索引0。例如,在着色器代码中,我们的语义名称是“POSITION”,实际上与“POSITION0”相同。
  • Format :这只是我们的顶点结构中组件的格式。它必须是DXGI_FORMAT枚举类型的成员。在本课中,我们有一个描述位置的三维矢量,因此我们可以使用DXGI_FORMAT:DXGI_FORMAT_R32B32_FLOAT 。如果您需要其他格式,可以在msdn上找到它们。稍后我们将使用其他的。
  • InputSlot :Direct3D允许我们使用16个不同的元素槽(0-15),您可以通过这些槽放置顶点数据。如果我们的顶点结构有一个位置和颜色,我们可以将两个元素放在同一个输入槽中,或者我们可以将位置数据放在第一个槽中,将颜色数据放在第二个槽中。我们只需要使用一个,但如果你愿意,你可以进行实验。
  • AlignedByteOffset :这是您所描述的元素的字节偏移量。在单个输入槽中,如果我们有位置和颜色,位置可能是0,因为它从顶点结构的开头开始,而颜色需要是顶点位置的大小,即12个字节(请记住,我们的顶点位置格式是DXGI_format_R32B32_FLOAT,它是96位,位置中的每个组件32位。一个字节中有8位,因此96/8==12)。
  • InputSlotClass :现在我们只能使用D3D10_INPUT_PER_VERTEX_DATA。其他选项用于实例化,这是我们稍后将了解的高级技术。
  • InstanceDataStepRate :这也仅用于实例化,因此我们现在将指定0
    171539778997

定义输入布局后,我们创建一个全局变量来保存输入布局数组的大小。我们这样做是为了以后我们不必记住不断更新创建输入布局的函数。

struct Vertex    //Overloaded Vertex Structure
{
    Vertex(){}
    Vertex(float x, float y, float z)  : pos(x,y,z){}

    XMFLOAT3 pos;
};

D3D11_INPUT_ELEMENT_DESC layout[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
};
UINT numElements = ARRAYSIZE(layout);

清理

void CleanUp()
{
    //Release the COM Objects we created
    SwapChain->Release();
    d3d11Device->Release();
    d3d11DevCon->Release();
    renderTargetView->Release();
    triangleVertBuffer->Release();
    VS->Release();
    PS->Release();
    VS_Buffer->Release();
    PS_Buffer->Release();
    vertLayout->Release();
}

初始化场景

这是我们初始化场景的地方。这就是我们在游戏过程中会改变的东西,但在整个场景中不会改变的地方。这节课上几乎所有的新内容都在这里。我将一次解释一部分。

bool InitScene()
{
    //Compile Shaders from shader file
    hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_5_0", 0, 0, 0, &VS_Buffer, 0, 0);
    hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_5_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.0f, 0.5f, 0.5f ),
        Vertex( 0.5f, -0.5f, 0.5f ),
        Vertex( -0.5f, -0.5f, 0.5f ),
    };

    D3D11_BUFFER_DESC vertexBufferDesc;
    ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );

    vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 3;
    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, &triangleVertBuffer);

    //Set the vertex buffer
    UINT stride = sizeof( Vertex );
    UINT offset = 0;
    d3d11DevCon->IASetVertexBuffers( 0, 1, &triangleVertBuffer, &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;

    //Set the Viewport
    d3d11DevCon->RSSetViewports(1, &viewport);

    return true;
}

编译着色器

我们将通过创建着色器开始初始化场景。我们将从名为“Effects.fx”的效果文件编译着色器。我们可以使用函数D3DX11CompileFromFile)来完成此操作:

HRESULT WINAPI D3DX11CompileFromFile(
            LPCSTR pSrcFile,
            CONST D3D10_SHADER_MACRO* pDefines, 
            LPD3D10INCLUDE pInclude,
            LPCSTR pFunctionName, 
            LPCSTR pProfile, 
            UINT Flags1, 
            UINT Flags2, 
            ID3DX11ThreadPump* pPump, 
            ID3D10Blob** ppShader, 
            ID3D10Blob** ppErrorMsgs, 
            HRESULT* pHResult);
  • pSrcFile :着色器文件名。
  • pDefines :一个数组宏指针。这里设为NULL.
  • pInclude :这是一个指向include接口的指针。如果着色器在文件中使用#include,则不能在此处放置NULL,但着色器没有include,因此我们将其设置为NULL。
  • pFunctionName :着色器文件中的函数名称。
  • pProfile :要使用的着色器的版本。Direct3D 11支持着色器版本5.0。然而,在我的笔记本电脑上,我需要将其设置为“vs_4_0”和“ps_4_0“。
  • Flags1 :编译标志,我们将其设置为NULL。
  • Flags2 :效果标志。我们还将其设置为NULL。
  • pPump :这与多线程有关。我们设置NULL,这样函数在完成之前不会返回。
  • ppShader :这是返回的着色器。它不是实际的着色器,更像是包含着色器和有关着色器的信息的缓冲区。然后我们将使用这个缓冲区来创建实际的着色器。
  • ppErrorMsgs :这将返回编译着色器时发生的错误和警告的列表。这些错误和警告与您在调试器底部看到的相同。
  • pHResult :这是返回的HRESULT。我们这样做是为了“hr=”这个函数,但你也可以把“&hr”作为这个参数来做同样的事情。
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_5_0", 0, 0, 0, &VS_Buffer, 0, 0);
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_5_0", 0, 0, 0, &PS_Buffer, 0, 0);

创建着色器

创建顶点着色器和像素着色器使用的函数分别如下:

HRESULT CreateVertexShader( 
  [in]        const void *pShaderBytecode,
  [in]        SIZE_T BytecodeLength,
  [in]        ID3D11ClassLinkage *pClassLinkage,
  [in, out]   ID3D11VertexShader **ppVertexShader) = 0;
);

HRESULT CreatePixelShader( 
  [in]        const void *pShaderBytecode,
  [in]        SIZE_T BytecodeLength,
  [in]        ID3D11ClassLinkage *pClassLinkage,
  [in, out]   ID3D11PixelShader **ppPixelShader) = 0;
);
  • pShaderBytecode :编译后的着色器字节流缓冲区指针
  • BytecodeLength :字节流长度
  • pClassLinkage :指向类链接接口的指针。我们将把它设置为NULL。
  • ppVertexShader :顶点着色器返回
  • ppPixelShader :像素着色器返回
hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);

设置着色器

现在我们已经编译并创建了着色器,我们需要将它们设置为当前管道着色器。如果要设置顶点着色器,我们可以通过调用ID3D11DeviceContext::VSSetShader来实现,如果要设置像素着色器,则可以调用IID3D11DeviceContext:VSSetShadow(稍后我们将学习设置其他着色器,如几何体着色器)。

大多数时候,应用程序将为不同的几何体集使用不同的着色器集,例如,稍后我们将在绘制skybox时使用单独的像素着色器。因此,您将在运行时设置着色器,而不是仅在场景设置功能中设置着色器。请记住,direct3d是一个“状态机”,它将保持当前状态和设置,直到以后更改为止,所以不要期望direct3d在代码中设置着色器后将其设置回默认值,在渲染内容之前,您需要始终设置正确的着色器。这也适用于渲染状态和其他事情。我们稍后也将讨论渲染状态。

void  VSSetShader( 
  [in]   ID3D11VertexShader *pVertexShader,
  [in]   (NumClassInstances)  ID3D11ClassInstance *const *ppClassInstances,
  [in]   UINT NumClassInstances);
);

void PSSetShader( 
  [in]   ID3D11PixelShader *pPixelShader,
  [in]   (NumClassInstances)  ID3D11ClassInstance *const *ppClassInstances,
  [in]   UINT NumClassInstances);
);

参数如下:

  • pVertexShader :顶点着色器指针
  • pPixelShader :像素着色器指针
  • ppClassInstances :仅当着色器使用类接口时才使用此选项。设置为NULL。
  • NumClassInstances :这是ppClassInstances中数组中的类实例数。我们设置为0,因为没有。
d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);

0 篇笔记 写笔记

D3D11像素着色器
这段像素着色器的代码实现了从YUV图像到RGB图像的转换,并保留了原始图像的alpha通道。让我们逐行解释代码:float4 yuva = {txY.Sample(samLinear, input.Tex).r, txU.Sample(samLinear, input.Tex).r, txV.S......
着色器shader分类信介绍-GLSL、HLSL和CG
画面通过显卡渲染出来呈现在屏幕上,肯定少不了对于显卡的调用和控制。但如果我们每次操作都需要直接对显卡内部的核心、显存之类的进行沟通则太过于复杂了。所以为了解决这种问题,需要对显卡内部的底层指令进行一些封装,把他们转化为较为简洁的API接口,这样我们只需要实现些接口,显卡会自动进行调用,就可以免去复杂......
顶点着色器VertexShader
什么是顶点着色器?顶点着色器是一组指令代码,这组指令代码在顶点被渲染时执行。同一时间内,只能激活一个顶点着色器。每个源顶点着色器最多拥有128条指令(DirextX8.1),而在DirectX9,则可以达到256条。为什么大家要使用顶点着色器?顶点着色器可以提高渲染场景速度(直接由显卡自动调用......
像素着色器PixelShader
什么是像素着色器?像素着色器是针对逐个像素进行的。在光栅化阶段,一个三角形在其所覆盖的每个像素处使用插值来计算相应顶点的各个属性,然后把插值后的顶点传递给像素着色器。像素着色器也是一组指令,这组指令在顶点中像素被渲染时执行。在每个执行时间,都会有很多像素被渲染。(像素的数目依靠屏幕的分辨率决定)......
04.开始绘制2
顶点结构与输入布局我们制作的所有3D对象都将由具有属性(如颜色)的点组成,这些属性称为顶点。我们必须制作自己的顶点结构。这是一个重载的顶点结构(因此我们可以轻松动态地创建和编辑顶点),只有一个位置。注意XMFLOAT3。正如我在上一课中提到的,direct3d正在从d3dx数学库转移到更流行的xna......
3.4 顶点着色器-简介
渲染管道中的第一个可编程着色器阶段是顶点着色器。如上所述,可编程着色器阶段执行用HTSL编写的自定义函数。在顶点着色器阶段的情况下,顶点着色器程序是为输入装配程序生成的顶点流中的每个顶点调用一次的函数。每个输入顶点都作为顶点着色器程序的参数接收,并且处理后的顶点作为函数的结果返回。每个顶点着色器调用......
3.4.1顶点着色器管道输入
由于顶点着色器直接位于管道中的输入装配程序之后,因此它自然会从那里接收输入。配置输入装配程序的输入布局所做的所有工作都旨在使创建的顶点与顶点着色器阶段的当前程序所期望的格式相匹配。这就是为什么在创建ID3DllInputl_ayout对象时需要将编译的着色器字节代码作为输入,以确保组装的顶点与执行顶......
D3D11的着色器资源视图和资源视图有什么区别
在Direct3D 11中,着色器资源视图(Shader Resource View,SRV)和渲染目标视图(Render Target View,RTV)是两个不同的概念。着色器资源视图(SRV):主要用途是将资源(如纹理、缓冲区等)绑定到着色器阶段(如像素着色器、顶点着色器等)。可以用来......
gs_texture_2d成员函数
2d纹理可创建的类型是多样的。有是2d的,也有的是2d-cube的。有的是需要绑定的是渲染目标视图,有的是渲染着色器资源视图。其它的一些配置参数多样。 InitTexture(data);//根据纹理数据创建纹理 InitResourceView();//创建着色器资源视图 ......
3.4.2顶点着色器状态配置
作为可编程着色器阶段,顶点着色器实现通用着色器核心功能。这意味着它提供了一组标准的资源接口方法,允许应用程序向着色器程序提供对所需资源的访问。与所有管道操作一样,所有可以更改顶点着色器阶段状态的方法都属于ID3DllDeviceContext接口。我们将查看这些可用资源中的每一个,并了解它们在顶点着......
3.4.3顶点着色器阶段处理
我们现在知道顶点着色器可以从输入装配程序接收哪些数据作为输入数据,以及哪些资源可以被主机应用程序绑定。顶点绘冲区常量缓冲区着色器资源视图我们还知道,顶点着色器程序提供了对单个顶点的自定义处理,而与调用管道的拓扑无关。那么,在顶点着色器程序中执行哪些类型的操作呢?某些类型的操作更适合这个阶段的组......
3.4.4顶点着色器管道输出
在决定在输出顶点结构中包括哪些信息时,需要考虑如何使用管道的其余部分。图3.18显示了渲染管道的框图。顶点着色器阶段之后是一组曲面细分阶段(外壳着色器、曲面细分器和域着色器阶段),然后是几何体着色器,然后是光栅化器阶段。根据顶点着色器和光栅化器阶段之间这些阶段中的哪一个处于活动状态,必须满足不同的......
3.11像素着色器
光栅化器将基本体转换为片段后,片段将传递到像素着色器阶段。像素着色器阶段是渲染管道中的最后一个可编程着色器阶段。它通过调用其像素着色器程序来单独处理每个片段。每个像素着色器调用都是独立运行的——在被处理的单个片段之间不可能进行直接通信。像素着色器完成后,结果是处理后的输出片段,该片段被传递到输出合......
3.11.1像素着色器管道输出
像素着色器阶段从光栅化器阶段接收其输入片段。这意味着像素着色器程序将使用的输入属性也由光栅化器生成。我们已经在光栅化器部分看到,它基于被光栅化的基元内片段的采样位置生成插值属性数据,该位置通常是像素的中心(尽管有时来自其他采样位置)。我们还看到,可以在像素着色器程序中指定各种插值修改器关键字,该程序......
3.11.2像素着色器状态配置
在清楚了解像素着色器程序可以接收哪些数据后,我们现在将考虑应用程序可以使用哪些类型的状态配置。像素着色器阶段是一个可编程阶段,这意味着它可以访问我们在各个管道阶段看到的标准通用着色器核心功能。再一次,我们不会在这里重复任何代码列表,因为它们本质上与我们在顶点着色器部分中看到的相同。下面列出了这些常见......
作者信息
站长漫谈
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!