【DX11地形篇】8-天空球

参考教程

Tutorial 7: Sky Domes

学习记录

  这篇文章中我们介绍天空的绘制,使用 SkyDome 实现。原理就是绘制球体,我们的场景都在球体里面,从场景的位置看向上方就可以看到球的内部面,所以需要我们关闭或者反转背面剔除,然后渲染球体。本篇代码基于上一篇,新增 SkydomeClassSkydomeShaderClass 类。

  SkyDomeClass 其实就是球体模型的类,类似于 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
////////////////////////////////////////////////////////////////////////////////
// Class name: SkyDomeClass
////////////////////////////////////////////////////////////////////////////////
class SkyDomeClass
{
private:
struct ModelType
{
float x, y, z;
float tu, tv;
float nx, ny, nz;
};

struct VertexType
{
XMFLOAT3 position;
};

public:
SkyDomeClass();
SkyDomeClass(const SkyDomeClass&);
~SkyDomeClass();

bool Initialize(ID3D11Device*);
void Shutdown();
void Render(ID3D11DeviceContext*);

int GetIndexCount();
XMFLOAT4 GetApexColor();
XMFLOAT4 GetCenterColor();

private:
bool LoadSkyDomeModel(char*);
void ReleaseSkyDomeModel();

bool InitializeBuffers(ID3D11Device*);
void ReleaseBuffers();
void RenderBuffers(ID3D11DeviceContext*);

private:
ModelType* m_model;
int m_vertexCount, m_indexCount;
ID3D11Buffer *m_vertexBuffer, *m_indexBuffer;
XMFLOAT4 m_apexColor, m_centerColor;
};

  其实现也是很简单,使用 LoadSkyDomeModel 加载模型文件,然后 InitializeBuffers 创建缓冲等等。

  SkyDomeShaderClass 是简单的渲染类,声明如下:

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
////////////////////////////////////////////////////////////////////////////////
// Class name: SkyDomeShaderClass
////////////////////////////////////////////////////////////////////////////////
class SkyDomeShaderClass
{
private:
struct MatrixBufferType
{
XMMATRIX world;
XMMATRIX view;
XMMATRIX projection;
};

struct ColorBufferType
{
XMFLOAT4 apexColor;
XMFLOAT4 centerColor;
};

public:
SkyDomeShaderClass();
SkyDomeShaderClass(const SkyDomeShaderClass&);
~SkyDomeShaderClass();

bool Initialize(ID3D11Device*, HWND);
void Shutdown();
bool Render(ID3D11DeviceContext*, int, XMMATRIX, XMMATRIX, XMMATRIX, XMFLOAT4, XMFLOAT4);

private:
bool InitializeShader(ID3D11Device*, HWND, CHAR*, CHAR*);
void ShutdownShader();
void OutputShaderErrorMessage(ID3D10Blob*, HWND, CHAR*);

bool SetShaderParameters(ID3D11DeviceContext*, XMMATRIX, XMMATRIX, XMMATRIX, XMFLOAT4, XMFLOAT4);
void RenderShader(ID3D11DeviceContext*, int);

private:
ID3D11VertexShader* m_vertexShader;
ID3D11PixelShader* m_pixelShader;
ID3D11InputLayout* m_layout;
ID3D11Buffer* m_matrixBuffer;

ID3D11Buffer* m_colorBuffer;
};

  其所对应的 skydome.vsskydome.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
96
97
98
99
100
101
////////////////////////////////////////////////////////////////////////////////
// Filename: skydome.vs
////////////////////////////////////////////////////////////////////////////////


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


//////////////
// TYPEDEFS //
//////////////
struct VertexInputType
{
float4 position : POSITION;
};

struct PixelInputType
{
float4 position : SV_POSITION;
float4 domePosition : TEXCOORD0;
};


////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType SkyDomeVertexShader(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);

// Send the unmodified position through to the pixel shader.
output.domePosition = input.position;

return output;
}

////////////////////////////////////////////////////////////////////////////////
// Filename: skydome.ps
////////////////////////////////////////////////////////////////////////////////


/////////////
// GLOBALS //
/////////////
cbuffer ColorBuffer
{
float4 apexColor;
float4 centerColor;
};


//////////////
// TYPEDEFS //
//////////////
struct PixelInputType
{
float4 position : SV_POSITION;
float4 domePosition : TEXCOORD0;
};


////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 SkyDomePixelShader(PixelInputType input) : SV_TARGET
{
float height;
float4 outputColor;


// Determine the position on the sky dome where this pixel is located.
height = input.domePosition.y;

// The value ranges from -1.0f to +1.0f so change it to only positive values.
if(height < 0.0)
{
height = 0.0f;
}

// Determine the gradient color by interpolating between the apex and center based on the height of the pixel in the sky dome.
outputColor = lerp(centerColor, apexColor, height);

return outputColor;
}

  最后我们在 ZoneClass 里添加 SkyDome 的对象,在 ShaderManagerClass 里添加 SkyDomeShaderClass 对象,并在渲染地形之前进行渲染(注意我们渲染的时候会关闭背面剔除和 Z-Buffer),部分渲染代码如下:

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
bool ZoneClass::Render(D3DClass* Direct3D, ShaderManagerClass* ShaderManager , TextureManagerClass* TextureManager)
{
XMMATRIX worldMatrix, viewMatrix, projectionMatrix, baseViewMatrix, orthoMatrix;
bool result;
XMFLOAT3 cameraPosition;

// Generate the view matrix based on the camera's position.
m_Camera->Render();

// Get the world, view, and projection matrices from the camera and d3d objects.
Direct3D->GetWorldMatrix(worldMatrix);
m_Camera->GetViewMatrix(viewMatrix);
Direct3D->GetProjectionMatrix(projectionMatrix);
m_Camera->GetBaseViewMatrix(baseViewMatrix);
Direct3D->GetOrthoMatrix(orthoMatrix);

// Get the position of the camera.
cameraPosition = m_Camera->GetPosition();

// Clear the buffers to begin the scene.
Direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

// Turn off back face culling and turn off the Z buffer.
Direct3D->TurnOffCulling();
Direct3D->TurnZBufferOff();

// Translate the sky dome to be centered around the camera position.
worldMatrix = XMMatrixTranslation(cameraPosition.x, cameraPosition.y, cameraPosition.z);

// Render the sky dome using the sky dome shader.
m_SkyDome->Render(Direct3D->GetDeviceContext());
result = ShaderManager->RenderSkydomeShader(Direct3D->GetDeviceContext(), m_SkyDome->GetIndexCount(), worldMatrix, viewMatrix,
projectionMatrix, m_SkyDome->GetApexColor(), m_SkyDome->GetCenterColor());
if(!result)
{
return false;
}

// Reset the world matrix.
Direct3D->GetWorldMatrix(worldMatrix);

// Turn the Z buffer back and back face culling on.
Direct3D->TurnZBufferOn();
Direct3D->TurnOnCulling();

if (m_wireFrame) {
Direct3D->EnableWireframe();
}

// Render the terrain grid using the texture shader.
m_Terrain->Render(Direct3D->GetDeviceContext());
result = ShaderManager->RenderTerrainShader(Direct3D->GetDeviceContext(), m_Terrain->GetIndexCount(), worldMatrix, viewMatrix,
projectionMatrix, TextureManager->GetTexture(0), TextureManager->GetTexture(1), m_Light->GetDirection(), m_Light->GetDiffuseColor());
if(!result)
{
return false;
}

if (m_wireFrame) {
Direct3D->DisableWireframe();
}

// Render the user interface.
if(m_displayUI)
{
result = m_UserInterface->Render(Direct3D, ShaderManager, worldMatrix, baseViewMatrix, orthoMatrix);
if(!result)
{
return false;
}
}

// Present the rendered scene to the screen.
Direct3D->EndScene();

return true;
}

  最终效果:

2

  源代码:DX11TerrainTutorial-SkyDomes

0%