DirectX学习 Tutorial 7

在上一个教程中,我们为项目引入了照明。 现在我们将通过向我们的立方体添加纹理来构建它。 此外,我们将介绍常量缓冲区的概念,并解释如何使用缓冲区通过最小化带宽使用来加速处理。

本教程的目的是修改中心立方体以将纹理映射到其上。

纹理映射

纹理映射是指2D图像在3D几何体上的投影。 我们可以把它想象成包装礼物,将装饰纸放在一个平淡无奇的盒子上。 为此,我们必须指定几何体表面上的点如何与2D图像对应。

诀窍是正确地将模型的坐标与纹理对齐。 对于复杂模型,很难手动确定纹理的坐标。 因此,3D建模包通常将导出具有相应纹理坐标的模型。 由于我们的示例是一个立方体,因此很容易确定匹配纹理所需的坐标。 纹理坐标在顶点处定义,然后针对曲面上的各个像素进行插值。

从纹理和采样器状态创建着色器资源

纹理是从文件中检索并用于创建着色器资源视图的2D图像,以便可以从着色器中读取它。

hr = D3DX11CreateShaderResourceViewFromFile( g_pd3dDevice, L"seafloor.dds", NULL, NULL, 
         &g_pTextureRV, NULL );

我们还需要创建一个采样器状态来控制着色器如何处理过滤,MIP和寻址。 在本教程中,我们将启用简单的采样器状态,以启用线性过滤和换行寻址。 要创建采样器状态,我们将使用ID3D11Device :: CreateSamplerState()。

    // Create the sample state
    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory( &sampDesc, sizeof(sampDesc) );
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
    hr = g_pd3dDevice->CreateSamplerState( &sampDesc, &g_pSamplerLinear );

定义坐标

在我们将图像映射到立方体之前,我们必须首先在立方体的每个顶点上定义纹理坐标。 由于图像可以是任何大小,因此使用的坐标系已标准化为[0,1]。 纹理的左上角对应于(0,0),右下角对应于(1,1)。

在这个例子中,我们将整个纹理分布在立方体的每一侧。 这简化了坐标的定义,没有混淆。 但是,完全可以指定要在所有六个面上拉伸的纹理,尽管定义点更加困难,并且它会显得拉伸和扭曲。

首先,我们更新了用于定义顶点的结构,以包含纹理坐标。

struct SimpleVertex
{
    XMFLOAT3 Pos;
    XMFLOAT2 Tex;
};

接下来,我们将输入布局更新为着色器以包括这些坐标。

// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

由于输入布局已更改,因此还必须修改相应的顶点着色器输入以匹配添加。

struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD;
};

最后,我们准备在我们在教程4中定义的顶点中包含纹理坐标。注意第二个参数输入是包含纹理坐标的D3DXVECTOR2。 立方体上的每个顶点都对应于纹理的一角。 这将创建一个简单的映射,其中每个顶点得到(0,0)(0,1)(1,0)或(1,1)作为坐标。

// Create vertex buffer
SimpleVertex vertices[] =
{
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
};

当我们对纹理进行采样时,我们需要使用下面几何体的材质颜色对其进行调制。

将纹理绑定为着色器资源

纹理和采样器状态是我们在前面的教程中看到的常量缓冲区之类的对象。 在着色器可以使用它们之前,需要使用ID3D11DeviceContext :: PSSetSamplers()和ID3D11DeviceContext :: PSSetShaderResources()API进行设置。

    g_pImmediateContext->PSSetShaderResources( 0, 1, &g_pTextureRV );
    g_pImmediateContext->PSSetSamplers( 0, 1, &g_pSamplerLinear );

应用纹理

要在几何体顶部映射纹理,我们将在像素着色器中调用纹理查找功能。 函数Sample将执行2D纹理的纹理查找,然后返回采样的颜色。 下面显示的像素着色器调用此函数并将其乘以底层网格颜色(或材质颜色),然后输出最终颜色。

当我们将资源视图g_pTextureRV绑定到它时,txDiffuse是存储我们从上面的代码传入的纹理的对象。
samLinear将在下面描述; 它是纹理查找的采样器规范。
input.Tex是我们在源中指定的纹理的坐标。

// Pixel Shader
float4 PS( PS_INPUT input) : SV_Target
{
    return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
}

我们必须记住的另一件事是通过顶点着色器传递纹理坐标。 如果不这样做,数据在到达像素着色器时就会丢失。 在这里,我们只需将输入的坐标复制到输出中,然后让硬件处理剩下的部分。

// Vertex Shader
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Tex = input.Tex;
        
    return output;
}

常量缓冲区

在Direct3D 11中,应用程序可以使用常量缓冲区来设置着色器常量(着色器变量)。使用类似于C样式结构的语法声明常量缓冲区。常量缓冲区通过允许将着色器常量组合在一起并同时提交来减少更新着色器常量所需的带宽,而不是单独调用单独提交每个常量。

在前面的教程中,我们使用单个常量缓冲区来保存我们需要的所有着色器常量。但是,有效使用常量缓冲区的最佳方法是根据更新频率将着色器变量组织到常量缓冲区中。这允许应用程序最小化更新着色器常量所需的带宽。例如,本教程将常量分为三个结构:一个用于更改每个帧的变量,一个用于仅在窗口大小更改时更改的变量,另一个用于设置一次然后不更改的变量。

本教程的.fx文件中定义了以下常量缓冲区。

    cbuffer cbNeverChanges
    {
        matrix View;
    };
    
    cbuffer cbChangeOnResize
    {
        matrix Projection;
    };
    
    cbuffer cbChangesEveryFrame
    {
        matrix World;
        float4 vMeshColor;
    };

要使用这些常量缓冲区,您需要为每个缓冲区创建一个ID3D11Buffer对象。 然后,您可以调用ID3D11DeviceContext :: UpdateSubresource()来在需要时更新每个常量缓冲区,而不会影响其他常量缓冲区。

    //
    // Update variables that change once per frame
    //
    CBChangesEveryFrame cb;
    cb.mWorld = XMMatrixTranspose( g_World );
    cb.vMeshColor = g_vMeshColor;
    g_pImmediateContext->UpdateSubresource( g_pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );

 

不错的dx11入门教程 Tutorial 1: Setting up DirectX 11 with Visual Studio Tutorial 2: Creating a Framework and Window Tutorial 3: Initializing DirectX 11 Tutorial 4: Buffers, Shaders, and HLSL Tutorial 5: Texturing Tutorial 6: Diffuse Lighting Tutorial 7: 3D Model Rendering Tutorial 8: Loading Maya 2011 Models Tutorial 9: Ambient Lighting Tutorial 10: Specular Lighting Tutorial 11: 2D Rendering Tutorial 12: Font Engine Tutorial 13: Direct Input Tutorial 14: Direct Sound Tutorial 15: FPS, CPU Usage, and Timers Tutorial 16: Frustum Culling Tutorial 17: Multitexturing and Texture Arrays Tutorial 18: Light Maps Tutorial 19: Alpha Mapping Tutorial 20: Bump Mapping Tutorial 21: Specular Mapping Tutorial 22: Render to Texture Tutorial 23: Fog Tutorial 24: Clipping Planes Tutorial 25: Texture Translation Tutorial 26: Transparency Tutorial 27: Reflection Tutorial 28: Screen Fades Tutorial 29: Water Tutorial 30: Multiple Point Lights Tutorial 31: 3D Sound Tutorial 32: Glass and Ice Tutorial 33: Fire Tutorial 34: Billboarding Tutorial 35: Depth Buffer Tutorial 36: Blur Tutorial 37: Coming Soon... DirectX 10 Tutorials: Tutorial 1: Setting up DirectX 10 with Visual Studio Tutorial 2: Creating a Framework and Window Tutorial 3: Initializing DirectX 10 Tutorial 4: Buffers, Shaders, and HLSL Tutorial 5: Texturing Tutorial 6: Diffuse Lighting Tutorial 7: 3D Model Rendering Tutorial 8: Loading Maya 2011 Models Tutorial 9: Ambient Lighting Tutorial 10: Specular Lighting Tutorial 11: 2D Rendering Tutorial 12: Font Engine Tutorial 13: Direct Input Tutorial 14: Direct Sound Tutorial 15: FPS, CPU Usage, and Timers Tutorial 16: Frustum Culling Tutorial 17: Multitexturing and Texture Arrays Tutorial 18: Light Maps Tutorial 19: Alpha Mapping Tutorial 20: Bump Mapping Tutorial 21: Specular Mapping Tutorial 22: Render to Texture Tutorial 23: Fog Tutorial 24: Clipping Planes Tutorial 25: Texture Translation Tutorial 26: Transparency Tutorial 27: Reflection Tutorial 28: Screen Fades Tutorial 29: Water Tutorial 30: Multiple Point Lights Tutorial 31: 3D Sound Tutorial 32: Glass and Ice Tutorial 33: Fire Tutorial 34: Billboarding Tutorial 35: Depth Buffer Tutorial 36: Blur Tutorial 37: Coming Soon... DirectX 10 Terrain Tutorials: Tutorial 1: Grid and Camera Movement Tutorial 2: Height Maps Tutorial 3: Terrain Lighting Tutorial 4: Terrain Texturing Tutorial 5: Color Mapped Terrain Tutorial 6: Quad Trees Tutorial 7: Coming Soon... 。。。。。。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值