学习了三维的地形系统之后,该抬头看看天空啦。下面学习一下传说中的三维天空系统。其实三维天空的实现比地形系统简单得多,我们只需要用一点点小伎俩,就可以蒙混大多数人。
一.简介
我们在玩游戏的时候,尤其是野外的大场景中,要想更逼真离不开三维天空系统。要用程序来模拟无边无际的天空是不可能的,而聪明的前辈们自然也想到了用“天圆地方”这种古代人们对于天空的认识来作为三维天空设计思想。即用一个足够大的面罩住我们,只要这个罩足够大,在里面看天空就和真实的天空没什么区别啦。而基于这种思想的天空设计方案中,最常用的就是天空盒。所谓天空盒,就是用一个立方体,罩住玩家所在的世界空间,天空盒常常是24个点,6个面,也可以是5个面,地面用三维地形,就不需要天空盒来覆盖了。
而要做出天空的效果,我们就必须要去找到一些天空的纹理素材,找到几张无缝拼接的图片,作为纹理贴图,这样我们看起来才不会穿帮。
二.天空盒类的设计
天空盒其实比较简单,就是一个立方体,然后在立方体的内侧进行纹理贴图即可。要注意的就是纹理贴图的顺序不要搞错,不然一眼就会被发现。
和之前的地形系统一样,都需要保存设备指针,系统内部自己设定顶点,然后根据参数初始化天空盒的大小,以及设置纹理贴图。使用时,我们只需要设定这几个参数就可以创建出各式各样的天空系统啦!
.h文件
/*!
* \file SkyBox.h
*
* \author puppet_master
* \date 七月 2015
*
* 三维天空盒的封装
*/
#ifndef __SKYBOX_H_
#define __SKYBOX_H_
#pragma once
struct SkyBoxVertex
{
float x, y, z; //定点位置
float u, v; //纹理位置
};
#define D3DFVF_SKYBOX D3DFVF_XYZ | D3DFVF_TEX1
class CSkyBox
{
private:
LPDIRECT3DDEVICE9 m_pDevice; //设备指针
LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer;//定点缓冲区指针
LPDIRECT3DTEXTURE9 m_pTexture[5]; //纹理对象指针
float m_fLength; //天空盒宽度
public:
CSkyBox(LPDIRECT3DDEVICE9 pDevice);
virtual ~CSkyBox(void);
//初始化天空盒
bool InitSkyBox(float length);
//加载纹理
bool InitSkyBoxTexture(LPSTR szFrontTexture, LPSTR szBackTexture, LPSTR szLeftTexture, LPSTR szRightTexture, LPSTR szTopTexture);
//渲染天空盒
void RenderSkyBox(D3DXMATRIX *matWorld, bool bRenderFrame = false);
};
#endif
.cpp文件
#include "stdafx.h"
#include "SkyBox.h"
CSkyBox::CSkyBox(LPDIRECT3DDEVICE9 pDevice)
{
m_pDevice = pDevice;
m_pVertexBuffer = NULL;
for (int i = 0; i < 5; i++)
m_pTexture[i] = NULL;
m_fLength = 0.0f;
}
CSkyBox::~CSkyBox(void)
{
SAFE_RELEASE(m_pVertexBuffer);
for (int i = 0; i < 5; i++)
{
SAFE_RELEASE(m_pTexture[i]);
}
}
bool CSkyBox::InitSkyBox(float length)
{
m_fLength = length;
//创建定点缓冲区
m_pDevice->CreateVertexBuffer(20 * sizeof(SkyBoxVertex), 0, D3DFVF_SKYBOX, D3DPOOL_MANAGED, &m_pVertexBuffer, 0);
SkyBoxVertex vertices[] =
{
//前面的顶点
{-m_fLength / 2, 0.0f, m_fLength / 2, 0.0f, 1.0f,},
{-m_fLength / 2, m_fLength / 2, m_fLength / 2, 0.0f, 0.0f,},
{m_fLength / 2, 0.0f, m_fLength / 2, 1.0f, 1.0f,},
{m_fLength / 2, m_fLength / 2, m_fLength / 2, 1.0f, 0.0f,},
//后面的顶点
{m_fLength / 2, 0.0f, -m_fLength / 2, 0.0f, 1.0f,},
{m_fLength / 2, m_fLength / 2, -m_fLength / 2, 0.0f, 0.0f,},
{-m_fLength / 2, 0.0f, -m_fLength / 2, 1.0f, 1.0f,},
{-m_fLength / 2, m_fLength / 2, -m_fLength / 2, 1.0f, 0.0f,},
//左面的顶点
{-m_fLength / 2, 0.0f, -m_fLength / 2 , 0.0f, 1.0f,},
{-m_fLength / 2, m_fLength / 2, -m_fLength / 2, 0.0f, 0.0f,},
{-m_fLength / 2, 0.0f, m_fLength / 2, 1.0f, 1.0f,},
{-m_fLength / 2, m_fLength / 2, m_fLength / 2, 1.0f, 0.0f,},
//右面的顶点
{m_fLength / 2, 0.0f, m_fLength / 2, 0.0f, 1.0f,},
{m_fLength / 2, m_fLength / 2, m_fLength / 2, 0.0f, 0.0f,},
{m_fLength / 2, 0.0f, -m_fLength / 2, 1.0f, 1.0f,},
{m_fLength / 2, m_