【DX11地形篇】14-程序纹理映射

参考教程

Tutorial 13: Procedural Terrain Texturing

学习记录

  这篇文章中我们介绍 Procedural terrain texturing ,本篇代码基于上一篇,仅有少量改动。

  原教程中对于这篇描述如下:

  Procedural parameters are usually calculated in our shaders based on input textures or the terrain data itself. One of the most popular parameters is to use the height of the pixel being rendered and apply a texture using different height bands. In this way you can specify the ground texture to be below a certain height, then a rock texture for anything above that height, and finally a snow texture for anything in the final height range. Although this works the results are not entirely realistic.

  A more useful procedural parameter to use for determining which texture to apply is the use the slope of the current pixel. The slope can be easily calculated (one minus the Y normal) and has the properties of reflecting real world growth and deposition patterns. For example in this tutorial we use the slope to determine where the rock gets exposed, and everything less than that slope is covered with snow. This represents a real world pattern where anything with too much slope the snow will never accumulate on. Likewise this can be extended to growth patterns, erosion patterns, and so forth.

  其实就是选择性的对纹理进行贴图,我们这篇中的场景为雪山,在这里我们使用当前斜率来计算是否使用混合或者直接使用雪的纹理(当山体坡度大的时候没有积雪所以使用雪的纹理与地面纹理混合)。

  主要修改 terrain.ps,使其支持三个纹理并且使用其法线判断混合或者覆盖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
////////////////////////////////////////////////////////////////////////////////
// Filename: terrain.ps
////////////////////////////////////////////////////////////////////////////////


/////////////
// GLOBALS //
/////////////
Texture2D diffuseTexture1 : register(t0);
Texture2D normalTexture1 : register(t1);
Texture2D normalTexture2 : register(t2);

SamplerState SampleType : register(s0);

//////////////////////
// CONSTANT BUFFERS //
//////////////////////
cbuffer LightBuffer
{
float4 diffuseColor;
float3 lightDirection;
float padding;
};


//////////////
// TYPEDEFS //
//////////////
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
float4 color : COLOR;
};


////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 TerrainPixelShader(PixelInputType input) : SV_TARGET
{
float slope;
float3 lightDir;
float4 textureColor1;
float4 textureColor2;
float4 bumpMap;
float3 bumpNormal;
float lightIntensity;
float4 material1;
float4 material2;
float blendAmount;
float4 color;


// Calculate the slope of this point.
slope = 1.0f - input.normal.y;

// Invert the light direction for calculations.
lightDir = -lightDirection;

// Setup the first material.
textureColor1 = diffuseTexture1.Sample(SampleType, input.tex);
bumpMap = normalTexture1.Sample(SampleType, input.tex);
bumpMap = (bumpMap * 2.0f) - 1.0f;
bumpNormal = (bumpMap.x * input.tangent) + (bumpMap.y * input.binormal) + (bumpMap.z * input.normal);
bumpNormal = normalize(bumpNormal);
lightIntensity = saturate(dot(bumpNormal, lightDir));
material1 = saturate(textureColor1 * lightIntensity);

// Setup the second material.
textureColor2 = float4(1.0f, 1.0f, 1.0f, 1.0f); // Snow color.
bumpMap = normalTexture2.Sample(SampleType, input.tex);
bumpMap = (bumpMap * 2.0f) - 1.0f;
bumpNormal = (bumpMap.x * input.tangent) + (bumpMap.y * input.binormal) + (bumpMap.z * input.normal);
bumpNormal = normalize(bumpNormal);
lightIntensity = saturate(dot(bumpNormal, lightDir));
material2 = saturate(textureColor2 * lightIntensity);

// Determine which material to use based on slope.
if(slope < 0.2)
{
blendAmount = slope / 0.2f;
color = lerp(material2, material1, blendAmount);
}
if(slope >= 0.2)
{
color = material1;
}

return color;

}

  其他的修改则只是为了支持新的 terrain.ps ,我们修改 TerrainShaderClass 使其支持三张纹理的渲染,同时修改 ShaderManagerClass 的对应函数。最后在 AoolicationClass 里读入新的纹理,读入的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Load texture 0
CHAR rock01d[] = "./data/rock01d.tga";
result = m_TextureManager->LoadTexture(m_Direct3D->GetDevice(), m_Direct3D->GetDeviceContext(), rock01d , 0);
if (!result) {
return false;
}

// Load texture 1
CHAR rock01n[] = "./data/rock01n.tga";
result = m_TextureManager->LoadTexture(m_Direct3D->GetDevice(), m_Direct3D->GetDeviceContext(), rock01n , 1);
if (!result) {
return false;
}

// Load texture 2
CHAR snow01n[] = "./data/snow01n.tga";
result = m_TextureManager->LoadTexture(m_Direct3D->GetDevice(), m_Direct3D->GetDeviceContext(), snow01n , 2);
if (!result) {
return false;
}

  最后,调用新的渲染方法:

1
2
// Render the cell buffers using the terrain shader.
result = ShaderManager->RenderTerrainShader(Direct3D->GetDeviceContext(), m_Terrain->GetCellIndexCount(i), worldMatrix, viewMatrix,projectionMatrix, TextureManager->GetTexture(0), TextureManager->GetTexture(1), TextureManager->GetTexture(2),m_Light->GetDirection(), m_Light->GetDiffuseColor());

  最终效果:

1

  源代码:DX11TerrainTutorial-ProceduralTerrainTexturing

0%