【DX11地形篇】7-颜色映射

参考教程

Tutorial 5: Color Mapped Terrain

学习记录

  这篇文章中我们主要介绍地形的颜色渲染,本篇没有新的类增加,主要修改内容在 TerrainClass

  和地形纹理贴图不一样的是,我们使用纹理贴图的时候是基于地形的单个网格,而颜色映射则是对整个地形图的着色,和高度图类似。我们首先需要一张颜色的贴图(256 * 256),如下:

1

  我们将在 TerrainClass 中从这张图中读取出颜色数据,然后赋值给顶点,最后着色的时候使用网格的自身纹理和颜色贴图混合。部分代码如下:

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
bool TerrainClass::LoadSetupFile(CHAR* filename) {
int stringLength;
std::ifstream fin;
char input;

// Initialize the string that will hold the terrain file name.
stringLength = 256;
m_terrainFilename = new char[stringLength];
if(!m_terrainFilename)
{
return false;
}

// Initialize the string that will hold the terrain file name.
m_colorMapFilename = new char[stringLength];
if(!m_colorMapFilename)
{
return false;
}

// Open the setup file. If it could not open the file then exit.
fin.open(filename);
if(fin.fail())
{
return false;
}

// Read up to the terrain file name.
fin.get(input);
while(input != ':')
{
fin.get(input);
}

// Read in the terrain file name.
fin >> m_terrainFilename;

// Read up to the color map file name.
fin.get(input);
while(input != ':')
{
fin.get(input);
}

// Read in the color map file name.
fin >> m_colorMapFilename;

// Read up to the value of terrain height.
fin.get(input);
while(input != ':')
{
fin.get(input);
}

// Read in the terrain height.
fin >> m_terrainHeight;

// Read up to the value of terrain width.
fin.get(input);
while (input != ':')
{
fin.get(input);
}

// Read in the terrain width.
fin >> m_terrainWidth;

// Read up to the value of terrain height scaling.
fin.get(input);
while (input != ':')
{
fin.get(input);
}

// Read in the terrain height scaling.
fin >> m_heightScale;

// Close the setup file.
fin.close();

return true;

}

bool TerrainClass::LoadColorMap()
{
int error, imageSize, i, j, k, index;
FILE* filePtr;
unsigned long long count;
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
unsigned char* bitmapImage;


// Open the color map file in binary.
error = fopen_s(&filePtr, m_colorMapFilename, "rb");
if(error != 0)
{
return false;
}

// Read in the file header.
count = fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
if(count != 1)
{
return false;
}

// Read in the bitmap info header.
count = fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
if(count != 1)
{
return false;
}

// Make sure the color map dimensions are the same as the terrain dimensions for easy 1 to 1 mapping.
if((bitmapInfoHeader.biWidth != m_terrainWidth) || (bitmapInfoHeader.biHeight != m_terrainHeight))
{
return false;
}

// Calculate the size of the bitmap image data. Since this is non-divide by 2 dimensions (eg. 257x257) need to add extra byte to each line.
imageSize = m_terrainHeight * ((m_terrainWidth * 3) + 1);

// Allocate memory for the bitmap image data.
bitmapImage = new unsigned char[imageSize];
if(!bitmapImage)
{
return false;
}

// Move to the beginning of the bitmap data.
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);

// Read in the bitmap image data.
count = fread(bitmapImage, 1, imageSize, filePtr);
if(count != imageSize)
{
return false;
}

// Close the file.
error = fclose(filePtr);
if(error != 0)
{
return false;
}

// Initialize the position in the image data buffer.
k=0;

// Read the image data into the color map portion of the height map structure.
for(j=0; j<m_terrainHeight; j++)
{
for(i=0; i<m_terrainWidth; i++)
{
// Bitmaps are upside down so load bottom to top into the array.
index = (m_terrainWidth * (m_terrainHeight - 1 - j)) + i;

m_heightMap[index].b = (float)bitmapImage[k] / 255.0f;
m_heightMap[index].g = (float)bitmapImage[k + 1] / 255.0f;
m_heightMap[index].r = (float)bitmapImage[k + 2] / 255.0f;

k += 3;
}

// Compensate for extra byte at end of each line in non-divide by 2 bitmaps (eg. 257x257).
k++;
}

// Release the bitmap image data.
delete [] bitmapImage;
bitmapImage = 0;

// Release the color map filename now that is has been read in.
delete [] m_colorMapFilename;
m_colorMapFilename = 0;

return true;
}

  之后我们修改 Terrain.vsTerrain.ps ,新增 COLOR 属性,并且在 Terrain.ps 中混合 colortextureColor

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
////////////////////////////////////////////////////////////////////////////////
// Filename: terrain.vs
////////////////////////////////////////////////////////////////////////////////


/////////////
// GLOBALS //
/////////////
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
};


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

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


////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType TerrainVertexShader(VertexInputType input)
{
PixelInputType output;


// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;

// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);

// Store the texture coordinates for the pixel shader.
output.tex = input.tex;

// Calculate the normal vector against the world matrix only.
output.normal = mul(input.normal, (float3x3)worldMatrix);

// Normalize the normal vector.
output.normal = normalize(output.normal);

// Calculate the tangent vector against the world matrix only and then normalize the final value.
output.tangent = mul(input.tangent, (float3x3)worldMatrix);
output.tangent = normalize(output.tangent);

// Calculate the binormal vector against the world matrix only and then normalize the final value.
output.binormal = mul(input.binormal, (float3x3)worldMatrix);
output.binormal = normalize(output.binormal);

output.color = float4(input.color , 1.0f);

return output;
}

////////////////////////////////////////////////////////////////////////////////
// Filename: terrain.ps
////////////////////////////////////////////////////////////////////////////////


/////////////
// GLOBALS //
/////////////
Texture2D shaderTexture : register(t0);
Texture2D normalTexture : register(t1);

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
{
float4 textureColor;
float3 lightDir;
float4 bumpMap;
float3 bumpNormal;
float lightIntensity;
float4 color;


// Sample the pixel color from the texture using the sampler at this texture coordinate location.
textureColor = shaderTexture.Sample(SampleType, input.tex);

// Mix the textureColor and input color
textureColor = textureColor * input.color * 2.2;

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

// Calculate the amount of light on this pixel using the normal map.
bumpMap = normalTexture.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));

// Determine the final amount of diffuse color based on the diffuse color combined with the light intensity.
color = saturate(diffuseColor * lightIntensity);

// Multiply the texture pixel and the final diffuse color to get the final pixel color result.
color = (color + 0.3) * textureColor;

return color;
}

  记得修改着色器代码的时候同步更新对应渲染类的代码。

  最终效果:

2

  源代码:DX11TerrainTutorial-TerrainColorMap

0%