天空盒

news/2024/10/21 4:07:11/

天空盒

就是围绕摄像机的360°的风景照。实质其实就是围绕着摄像机的立方体,而摄像机就在这个立方体的里面。可以用来模拟无限的天空,山脉等现象。

为什么要使用天空盒

在3D游戏中,一般来说要渲染的东西会比较多,而使用天空盒会节约部分渲染的时间;而且如果不采用“天空盒”技术,或者其他技术,而直接进行渲染天空,地面以及周围场景,那么可能会因为距离把握不当,造成“露馅”。

除了在游戏中使用“天空盒”技术较多,在一些二次元动画中也会经常使用到,如MMD(miku miku dance)。

                   

                   

天空盒的结构

就如同一个立方体一样

                         

显然可知,该立方体共有8个顶点,6个面,因此最多需要6张纹理图,这6张纹理图分别覆盖该立方体的不同面。

//SkyBox's FVFstruct SKYBOXVERTEX{float x, y, z;float u, v;};
#define D3DFVF_SKYBOX	D3DFVF_XYZ|D3DFVF_TEX1
class CSkyModel{public:CSkyModel(LPDIRECT3DDEVICE9 pDevice);virtual ~CSkyModel();//Data types & constantsenum ModelType{k_box,k_hemisphere,k_sphere,k_dome};bool	Init_SkyBox(float Length);					//Initialize the sky boxbool	Load_SkyTextureFromFile(wchar_t *pFrontTextureFile, wchar_t *pBackTextureFile, wchar_t *pLeftTextureFile, \wchar_t *pRightTextureFile, wchar_t *pTopTextureFile, wchar_t *pBottomTextureFile);void	Render_SkyBox(D3DXMATRIX *pMatWorld, bool bRenderFrame);			//the first parameter is the sky box's world matrix,//the second parameter is doing or not doing render the line (ÊÇ·ñäÖȾ³öÏß¿ò)bool	Init_Floor(float length);void	Render_Floor(bool bRenderFrame);private:ModelType m_type;LPD3DXMESH m_pMesh;D3DXHANDLE m_hUVSettings;LPDIRECT3DDEVICE9			m_pd3dDevice;			//D3D Device objectLPDIRECT3DVERTEXBUFFER9		m_pVertexBuffer;		//the vertex buffer objectLPDIRECT3DVERTEXBUFFER9		m_pFloorVerBuffer;		//the floor's vertex bufferLPDIRECT3DTEXTURE9			m_pTexture[6];float						m_Length;				//the length of skybox};

首先是定义天空盒的顶点格式,x,y,z分别代表坐标位置,u,v代表纹理坐标。

然后再定义其灵活顶点格式。

在类中,我声明了关于立方体长度的变量,以及存储6个纹理的数组;也声明了关于天空盒的类型,是天空盒还是天空球,或还是其他类型。在Demo中只实现了天空盒一种,且用旋转的方式进行模拟天空移动。

该类的定义:


//
//Name: CSkyModel Class
//
CSkyModel::CSkyModel(LPDIRECT3DDEVICE9 pDevice)
{m_pd3dDevice = pDevice;m_pVertexBuffer = NULL;for (size_t i = 0; i != 6; i++){m_pTexture[i] = NULL;}m_Length = 0.0f;
}CSkyModel::~CSkyModel()
{SAFE_RELEASE(m_pd3dDevice);SAFE_RELEASE(m_pVertexBuffer);SAFE_RELEASE(m_pFloorVerBuffer);for (size_t i = 0; i != 6; ++i){SAFE_RELEASE(m_pTexture[i]);}
}bool CSkyModel::Init_SkyBox(float Length)
{m_Length = Length;//1.创建。创建顶点缓存m_pd3dDevice->CreateVertexBuffer(24 * sizeof(SKYBOXVERTEX), 0,D3DFVF_SKYBOX, D3DPOOL_MANAGED, &m_pVertexBuffer, 0);//用一个结构体把顶点数据先准备好SKYBOXVERTEX vertices[] ={//前面的四个顶点{ -m_Length / 2, 0.0f,    m_Length / 2, 0.0f, 1.0f, },{ -m_Length / 2, m_Length / 2,   m_Length / 2, 0.0f, 0.0f, },{ m_Length / 2, 0.0f,    m_Length / 2, 1.0f, 1.0f, },{ m_Length / 2, m_Length / 2,   m_Length / 2, 1.0f, 0.0f, },//背面的四个顶点{ m_Length / 2, 0.0f,   -m_Length / 2, 0.0f, 1.0f, },{ m_Length / 2, m_Length / 2,  -m_Length / 2, 0.0f, 0.0f, },{ -m_Length / 2, 0.0f,   -m_Length / 2, 1.0f, 1.0f, },{ -m_Length / 2, m_Length / 2,  -m_Length / 2, 1.0f, 0.0f, },//左面的四个顶点{ -m_Length / 2, 0.0f,   -m_Length / 2, 0.0f, 1.0f, },{ -m_Length / 2, m_Length / 2,  -m_Length / 2, 0.0f, 0.0f, },{ -m_Length / 2, 0.0f,    m_Length / 2, 1.0f, 1.0f, },{ -m_Length / 2, m_Length / 2,   m_Length / 2, 1.0f, 0.0f, },//右面的四个顶点{ m_Length / 2, 0.0f,   m_Length / 2, 0.0f, 1.0f, },{ m_Length / 2, m_Length / 2,  m_Length / 2, 0.0f, 0.0f, },{ m_Length / 2, 0.0f,  -m_Length / 2, 1.0f, 1.0f, },{ m_Length / 2, m_Length / 2, -m_Length / 2, 1.0f, 0.0f, },//上面的四个顶点{ m_Length / 2, m_Length / 2, -m_Length / 2, 1.0f, 0.0f, },{ m_Length / 2, m_Length / 2,  m_Length / 2, 1.0f, 1.0f, },{ -m_Length / 2, m_Length / 2, -m_Length / 2, 0.0f, 0.0f, },{ -m_Length / 2, m_Length / 2,  m_Length / 2, 0.0f, 1.0f, },//bottom{-m_Length / 2,0,m_Length / 2,0,0},{-m_Length / 2,0,-m_Length / 2,0,1},{m_Length / 2,0,m_Length / 2,1,0},{m_Length / 2,0,-m_Length / 2,1,1},};//准备填充顶点数据void *pVertices;//Lockm_pVertexBuffer->Lock(0, 0, (void**)&pVertices, 0);//access 把结构体中的数据直接拷到顶点缓冲区中memcpy(pVertices, vertices, sizeof(vertices));//UnLockm_pVertexBuffer->Unlock();//Floorfloat _length = 5000.0f;this->Init_Floor(_length);return true;
}bool CSkyModel::Init_Floor(float tLength)
{//1.创建。创建顶点缓存m_pd3dDevice->CreateVertexBuffer(4 * sizeof(SKYBOXVERTEX), 0,D3DFVF_SKYBOX, D3DPOOL_MANAGED, &m_pFloorVerBuffer, 0);//用一个结构体把顶点数据先准备好SKYBOXVERTEX vertices[] ={//底部{ -tLength,0.0f,-tLength,0.0f,30.0f },{ -tLength,0.0f,tLength,0.0f,0.0f },{ tLength,0.0f,-tLength,30.0f,30.0f },{ tLength,0.0f,tLength,30.0f,0.0f },};//准备填充顶点数据void *pVertices;//Lockm_pFloorVerBuffer->Lock(0, 0, (void**)&pVertices, 0);//access 把结构体中的数据直接拷到顶点缓冲区中memcpy(pVertices, vertices, sizeof(vertices));//UnLockm_pVertexBuffer->Unlock();return true;
}bool CSkyModel::Load_SkyTextureFromFile(wchar_t *pFrontTextureFile, wchar_t *pBackTextureFile, wchar_t *pLeftTextureFile, \wchar_t *pRightTextureFile, wchar_t *pTopTextureFile, wchar_t *pBottomTextureFile)
{//从文件加载五张纹理D3DXCreateTextureFromFileW(m_pd3dDevice, pFrontTextureFile, &m_pTexture[0]);  //前面D3DXCreateTextureFromFileW(m_pd3dDevice, pBackTextureFile, &m_pTexture[1]);  //后面D3DXCreateTextureFromFileW(m_pd3dDevice, pLeftTextureFile, &m_pTexture[2]);  //左面D3DXCreateTextureFromFileW(m_pd3dDevice, pRightTextureFile, &m_pTexture[3]);  //右面D3DXCreateTextureFromFileW(m_pd3dDevice, pTopTextureFile, &m_pTexture[4]);  //上面D3DXCreateTextureFromFileW(m_pd3dDevice, pBottomTextureFile, &m_pTexture[5]); //底部return TRUE;
}//--------------------------------------------------------------------------------------
// Name: SkyBoxClass::RenderSkyBox()
// Desc: 绘制出天空盒,可以通过第二个参数选择是否绘制出线框
//--------------------------------------------------------------------------------------
void CSkyModel::Render_SkyBox(D3DXMATRIX *pMatWorld, bool bRenderFrame)
{m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);  //将纹理颜色混合的第一个参数的颜色值用于输出m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);   //纹理颜色混合的第一个参数的值就取纹理颜色值m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);m_pd3dDevice->SetTransform(D3DTS_WORLD, pMatWorld);  //设置世界矩阵m_pd3dDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(SKYBOXVERTEX));    //把包含的几何体信息的顶点缓存和渲染流水线相关联  m_pd3dDevice->SetFVF(D3DFVF_SKYBOX);  //设置FVF灵活顶点格式//一个for循环,将6个面绘制出来for (int i = 0; i != 6; i++){m_pd3dDevice->SetTexture(0, m_pTexture[i]);m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2);}//对是否渲染线框的处理代码if (bRenderFrame)  //如果要渲染出线框的话{m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //把填充模式设为线框填充//一个for循环,将5个面的线框绘制出来for (int i = 0; i != 6; i++){m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2);	//绘制顶点 }m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);	//把填充模式调回实体填充}
}void CSkyModel::Render_Floor(bool bRenderFrame)
{m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);D3DXMATRIX matWorld;D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f);m_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);m_pd3dDevice->SetStreamSource(0, m_pFloorVerBuffer, 0, sizeof(SKYBOXVERTEX));m_pd3dDevice->SetFVF(D3DFVF_SKYBOX);m_pd3dDevice->SetTexture(0, m_pTexture[5]);m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);//对是否渲染线框的处理代码if (bRenderFrame)  //如果要渲染出线框的话{m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //把填充模式设为线框填充m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);	//绘制顶点 m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);	//把填充模式调回实体填充}
}

最后演示结果

                    

源代码

CSDN内进行下载  当前CSDN已改版,无法进行调整积分值,所以不是很推荐。

天空盒实现还有其他办法,不用手动进行设置立方体的大小,可以通过导入一个立方体的模型,如.X文件,然后通过HLSL进行顶点着色器的编写,也可以实现。

如果想多了解关于3D场景以及地形渲染可以参考

Real Time 3D Terrain Engines Using C++ And Dx9


http://www.ppmy.cn/news/254576.html

相关文章

cocos creator 接QQ小游戏小程序 AppBox 盒子广告sdk

cocos creator 接QQ小游戏小程序 AppBox 盒子广告sdk 基础库 1.7.1 版本开始支持广告盒子组件,开发者工具 0.1.28 版本开始支持调试 开发者工具版本太低是不会显示盒子的,而且不会提示你更新,需要自己去下 我再加个很重要的提示,因…

算法与游戏之AABB碰撞盒算法

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术…

小米游戏本如何关掉小米游戏盒子弹窗提醒

小米笔记本算是目前所有笔记本中性价比最高的,像我目前用的这个小米游戏本,八代i7 16g 1060,京东上是小米顶配,(工作需要不要说我壕)8.8k,性价比还是很高的(对比水果笔记本&#xff…

java游戏破解版盒子,37游戏盒子-37游戏盒子最新版 v4.0.0.4 官方版

37游戏盒子 37游戏盒子最新版是一款提供游戏下载辅助软件。37游戏盒子最新版内置海量游戏而且不断更新,让玩家不必到处找游戏。而且还会自动去检测游戏所需要的软件和硬件环境,玩家只需轻松一点,就可以实现游戏的下载、安装、运行全部过程。 …

云计算机怎么打游戏,云即玩游戏盒怎么用 云即玩游戏盒电脑版使用教程

云即玩游戏盒聚合主流模拟器支持,跨多个终端平台,并支持云电脑游戏,是一款功能齐全的综合性PC游戏盒子。本站电脑版游戏软件已更新采用了云即玩游戏盒,有些小伙伴还不清楚怎么用,以下就介绍云即玩游戏盒电脑版使用教程…

云计算机怎么打游戏,云即玩游戏盒该如何使用 云即玩游戏盒电脑版的使用方法...

云即玩游戏盒是一款基于跨终端设备的游戏内容分享软件,致力于回归游戏可玩性.玩家在畅玩经典的PC游戏资源的同时,还可以大屏、多开用电脑玩全部手机游戏;实现低配置电脑可玩高配大型端游大作,随时随地即点即玩,帮助Steam平台玩家用…

UG SolidWorks CATIA proe 三维

单臂机减速机发动机减速机淀粉加工机塑料瓶脱模机水平斯特林发动机(附工程图)发动机-发动机307数控机床遥控器BRC工业钢丝矫直机食物切割机线刷机设备螺杆冷却机鼓风机平台发动机-发动机农业机械-粮食清理机械机起重机剥皮机(附工程图&#x…

【JavaSE】Java(五十五):核心要点总结

文章目录 1. 为什么不允许静态方法访问非静态变量2. Java的内存模型3. 在Java中什么时候用重载什么时候用重写4. 举例说明什么情况下更倾向于用抽象类而不是接口5. 实例化对象有哪几种方式 1. 为什么不允许静态方法访问非静态变量 在Java中,静态方法属于类级别的方法…