位置: IT常识 - 正文

【Visual C++】游戏开发四十九 浅墨DirectX教程十七 三维天空的实现(《visual c++游戏编程基础》)

编辑:rootadmin
本系列文章由zhmxy555(毛星云)编写,转载请注明出处。文章链接:http://blog.csdn.net/zhmxy555/article/details/8685546作者:毛星云(浅墨)邮箱

推荐整理分享【Visual C++】游戏开发四十九 浅墨DirectX教程十七 三维天空的实现(《visual c++游戏编程基础》),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:游戏microsoft visual c++ runtime,visual c 游戏开发,visual c 游戏设计,visual c 游戏设计,visual c 游戏设计,《visual c++游戏编程基础》,visual c++经典游戏程序设计,visual c++经典游戏程序设计,内容如对您有帮助,希望把文章链接给更多的朋友!

本系列文章由zhmxy555(毛星云)编写,转载请注明出处。文章链接:http://blog.csdn.net/zhmxy555/article/details/8685546作者:毛星云(浅墨)邮箱:happylifemxy@163.com

这篇文章里,浅墨准备跟大家一起探讨一下三维天空的几种实现方式,然后在几种方式之中选择最常用的一种进行重点突破,用一个C++类把这种三维天空的实现方式封装起来。这样以后要使用三维天空来辅助绘制某个游戏场景的话,准备好天空的纹理图,然后简单地敲几行代码,调用一下这个天空类中我们亲手写出来的函数就搞定了。先放一张程序截图:

程序源码在文章末尾有给出下载地址。

一、游戏行业所用编程语言的认知

上面讲到了类的封装,目前市面上的高性能三维游戏引擎其实就是在做这样的工作,把各种功能封装在一个个C++类中。浅墨经常收到怀揣游戏开发梦想的初学者们的邮件,询问进行游戏开发到底学什么语言最合适。浅墨在这里集中跟大家讲一下得了。

大家都知道,撇开C语言不谈,C++在目前高级编程语言中执行效率和性能首屈一指。大家也知道,三维游戏的画面渲染有着非常高的性能需求。就光这一条对性能的要求,什么C#,什么java等等,全都只有在一旁抹鼻子哭了。

所以,事实如此,现在市面上所有画质精美的单机游戏作品(鬼泣5,上古卷轴5,刺客信条3,仙剑奇侠传5前传,古剑奇谭等等……),所有的大型网络游戏(Dota2,英雄联盟,魔兽世界,龙之谷,剑灵等等等……),所有高性能的三维游戏引擎(虚幻3,Unity3D,Cry Engine3等等……),以及一些高性能的2D游戏引擎(Cocos2d-x等等),都是用C++来开发的。

其实游戏引擎并没有那么神秘,说白了也就是那么回事,用类封装好功能的C++代码而已。C++写出来的游戏引擎自然能跨平台。Unreal Engine3、Unity3D、Cocos2d-x等游戏引擎就是绝好的例子。

学好C++,你可以亲手写出Unity3D,亲手写出 Cocos2d-x,让大家都叫你大神,大家都用你写的游戏引擎做游戏,等着你什么时候心情好了更新一下给引擎加更多功能;而不是只会盲目跟风,今天大家说Unity3D火,就都去学Unity3D,明天大家说Cocos2d-x热门,就来学学Cocos2d-x。你学游戏引擎,学的只是人家某引擎作者某C++大神按心情来定的函数调用方式,学的只是如何调用一些别人写好的一些类,一些API函数。这样在别人规定给你的一些rule中固步自封,大家觉得有技术含量么?

我们是时候该该想一想了,为什么现在全球范围内优秀的三维引擎就是没有我们国产引擎的影子。

所以,无论是哪个平台,Windows也好,iOS也好,Android也罢,如果你真正想在游戏开发领域有所作为,混出个名堂,请学C++,请学计算机图形学,请了解计算机图形API(OpenGL或者DirectX),而不是在跟风某种“热门”的游戏引擎的大潮中随波逐流,在某种移动平台的游戏开发中迷信某某引擎,乐不思蜀,固步自封。

咳,扯远了,而且有些小愤青了,也原谅浅墨,浅墨没有歧视其他编程语言的意思。浅墨只是想表达,无论是哪个平台(Windows,Play Station,Xbox,Android,iOS,WindowsPhone, WUII),在三维或者高性能游戏开发领域,确实就是C++的天下。

如果大家对游戏引擎的概念不太了解,还请看浅墨写过的关于游戏引擎的导论:

【Visual C++】游戏开发笔记三十五 站在巨人的肩膀上:游戏引擎导论

二、三维天空技术阐述

回到正题来吧,讲今天的主题三维天空的实现。

不要看游戏世界中的天空好像是无边无际的,其实我们都被骗了。

在计算机的三维世界中,三维天空的绘制肯定不可能像现实生活中的天空一样,一望无际绵延无尽,往往是通过一种假象来现实的。这种假象与古代人所说的“天圆地方”有着异曲同工之妙。反正就是一个足够大的容器一样的东西把我们罩在里面,让我们像井底之蛙一样以为这就是整个世界,世界就这么大,天空就这么大。而这个足以罩住我们所置身的游戏世界的容器,可以是一个立方体,也可以是半球,甚至是一个足够大的平面。

目前描述三维天空的技术主要包括三种类型:

1.平面型天空(Sky Plane),仅用一个平面放到玩家头顶。这种方案太弱了,太容易被玩家们看穿,真实感太低,技术含量也太低。但是对于并不太注意远景的场景,用天空平面也不失为一种办法。在这种情况下,用纯色的雾来覆盖整个远景,使得远处充满神秘,遮一下羞也效果凑合。

2.天空穹庐(Sky Dome),放到玩家头顶上的是一个曲面,通常都会为一个半球。就像这样:

这种方案其实真实性最强,但是不是目前使用最广泛的方案,它涉及到天空无缝衔接的素材匮乏等的问题。

3.天空盒(Sky Box),即放到场景的是一个立方体。它是目前使用最广泛的三维天空模拟技术,网络上素材丰富,所以这次就用教大家用天空盒来模拟三维天空。天空盒经常是由24个顶点、六个面组成的立方体(或者直接从做好的X模型文件载入天空盒),并经常会随着视点的移动而移动,来刻画极远处玩家无法达到位置的天空。

天空盒对于我们来说并不是困难的事情,但是真正要在游戏中使得天空“好看”,那么,还需要有着漂亮的天空纹理素材图,可以在网上搜罗(下文有讲如何搜索),也可以拜托给美工童鞋们。

另外,在高级一些的应用中,天空盒的纹理可能同时会用来生成Cube Map,并用之来做水面倒影、云影、反光等很眩的特效,大家先有一个这方面的概念就好。

三. 天空盒的设计

本篇文章的核心知识登场。

1,准备天空盒纹理素材

天空盒的纹理自然就是我们这个天空盒子立方体每个面的纹理了,至少5个面,最多6个面,因为底面处是我们所在的土地,是地形,也就不用渲染为天空了。

这5个面可以分别单独成文件,像这样:

这5张纹理需要满足的条件是:按照规定的几个面拼接起来,能构成一幅360度并包含顶部的无缝衔接的全景图:

另外,有些游戏引擎设定了需要把5个面按某种方式连起来和成一幅图来使用,就像这样的天空盒素材:

互联网上关于天空盒的纹理素材资源很丰富,大家google/百度就可以找打很多资源的下载点。

建议用关键 skybox texture或者skybox download来google。

另外,如果想原创天空盒纹理的话,可以用DirectX SDK 中自带的DirectX Texture tool工具完成。

2 天空盒类的设计

好了,开始我们的本职工作,写代码吧。

【Visual C++】游戏开发四十九 浅墨DirectX教程十七 三维天空的实现(《visual c++游戏编程基础》)

我们今天的任务是写一个封装了天空盒渲染功能的类,我们给这个类取名为SkyBoxClass。

我们来看下这个类中有哪些内容。

最开始国际惯例,LPDIRECT3DDEVICE9类型的设备接口指针m_pd3dDevice自然不能少。

然后这个类中需要处理24个带纹理坐标的顶点来构成一个立方体盒子,自然少不了FVF灵活顶点格式和一个DIRECT3DVERTEXBUFFER接口的指针。

接着还要有五个纹理对象,分别储存5个面上的纹理图,所以一个LPDIRECT3DTEXTURE9类型的m_pTexture[5]自然也少不了。最后,还需要定义一个float类型的m_Length表示天空盒的边长。结构体和成员变量就是这些了,我们再来看一下需要有哪些成员函数。

首先构造函数析构函数我们写出来,接着再写三个函数就够了,它们分别是初始化天空盒顶点的InitSkyBox函数,加载纹理的LoadSkyTextureFromFile函数,渲染天空盒的RenderSkyBox函数。

SkyBoxClass类的轮廓就是这样了,那么把上面我们的思路实现成代码就是如下,即贴出SkyBoxClass.h中全部代码:

//=============================================================================// Name: SkyBoxClass.h//Des: 一个封装了三维天空盒系统的类的头文件// 2013年 3月24日 Create by 浅墨//=============================================================================#pragma once#include "D3DUtil.h"//为天空盒类定义一个FVF灵活顶点格式struct SKYBOXVERTEX{floatx,y,z;floatu,v;};#define D3DFVF_SKYBOX D3DFVF_XYZ|D3DFVF_TEX1class SkyBoxClass{private:LPDIRECT3DDEVICE9m_pd3dDevice;//D3D设备对象LPDIRECT3DVERTEXBUFFER9m_pVertexBuffer;//顶点缓存对象LPDIRECT3DTEXTURE9m_pTexture[5];//5个纹理接口对象floatm_Length;//天空盒边长public:SkyBoxClass( LPDIRECT3DDEVICE9 pDevice );//构造函数virtual ~SkyBoxClass(void);//析构函数public:BOOLInitSkyBox( float Length ); //初始化天空盒函数BOOLLoadSkyTextureFromFile(wchar_t *pFrontTextureFile, wchar_t *pBackTextureFile,wchar_t *pLeftTextureFile, wchar_t *pRightTextureFile,wchar_t *pTopTextureFile); //从文件加载天空盒五个方向上的纹理VOIDRenderSkyBox( D3DXMATRIX *pMatWorld, BOOL bRenderFrame ); //渲染天空盒,根据第一个参数设定天空盒世界矩阵,第二个参数选择是否渲染出线框};三、 天空盒类的实现

类的框架勾勒出来了,接下来就很简单,分别在类的cpp文件中实现类成员函数就好了。

Ⅰ.构造函数的实现

首先是类构造函数,蛮简单,直接对着看类定义中有哪些变量,分别赋初值就行。除了Direct3D设备对象赋值成通过函数形参传进来的设备对象指针pDevice之外,其他的参数根据类型统统取NULL或者0.0f:

//-------------------------------------------------------------------------------------------------// Desc: 构造函数//-------------------------------------------------------------------------------------------------SkyBoxClass::SkyBoxClass( LPDIRECT3DDEVICE9 pDevice ){//给各个参数赋初值m_pVertexBuffer=NULL;m_pd3dDevice=pDevice;for(int i=0; i<5; i++)m_pTexture[i] = NULL;m_Length = 0.0f;}

Ⅱ. 顶点初始化函数InitSkyBox的实现

接下来要实现的就是最关键的顶点初始化函数InitSkyBox。首先,通过形参把天空盒的边长传给代表边长的成员函数m_Length。接着就是我们熟悉的顶点缓存使用四步曲的二、三两步——创建顶点缓存、访问顶点缓存了。

我们在纹理映射第一讲中就给出了立方体表面贴纹理的24个顶点需要怎么写,我们这里的思路基本和之前讲的相同,而与D3D实现的普通立方体贴图不同的一点是,大部分情况下我们视点都包容在天空盒内部,因此,天空盒的顶点顺序应当是正好与我们之前讲的普通立方体的顶点顺序相反。所以,InitSkyBox函数的实现代码就是这样:

//-------------------------------------------------------------------------------------------------// Name: SkyBoxClass::InitSkyBox( )// Desc: 天空盒初始化函数,顶点缓冲区的赋值//-------------------------------------------------------------------------------------------------BOOL SkyBoxClass::InitSkyBox( float Length ){m_Length=Length;//1.创建。创建顶点缓存m_pd3dDevice->CreateVertexBuffer( 20 * 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, },};//准备填充顶点数据void* pVertices;//2.加锁m_pVertexBuffer->Lock( 0, 0, (void**)&pVertices, 0 );//3.访问。把结构体中的数据直接拷到顶点缓冲区中memcpy( pVertices, vertices, sizeof(vertices) );//4.解锁m_pVertexBuffer->Unlock();return TRUE;}Ⅲ.纹理载入函数LoadSkyTextureFromFile的写法

接下来看看纹理载入函数LoadSkyTextureFromFile的写法,实在是非常非常简单。

给5个文件路径给他,传进来调用5次D3DXCreateTextureFromFile函数载入纹理到m_pTexture[]数组中就好了:

//-------------------------------------------------------------------------------------------------// Name: SkyBoxClass::LoadSkyTextureFromFile( )// Desc: 天空盒纹理加载函数//-------------------------------------------------------------------------------------------------BOOL SkyBoxClass::LoadSkyTextureFromFile(wchar_t *pFrontTextureFile, wchar_t *pBackTextureFile,wchar_t *pLeftTextureFile, wchar_t *pRightTextureFile,wchar_t *pTopTextureFile){//从文件加载五张纹理D3DXCreateTextureFromFile( m_pd3dDevice , pFrontTextureFile, &m_pTexture[0] ); //前面D3DXCreateTextureFromFile( m_pd3dDevice , pBackTextureFile, &m_pTexture[1] ); //后面D3DXCreateTextureFromFile( m_pd3dDevice , pLeftTextureFile, &m_pTexture[2] ); //左面D3DXCreateTextureFromFile( m_pd3dDevice , pRightTextureFile, &m_pTexture[3] ); //右面D3DXCreateTextureFromFile( m_pd3dDevice , pTopTextureFile, &m_pTexture[4] ); //上面return TRUE;}

Ⅳ. 渲染函数RenderSkyBox

再看看作用为渲染天空盒RenderSkyBox函数。其中我们用到了讲解纹理映射的时候没有讲到的纹理阶段混合操作,这里我们顺便讲一下。

纹理映射的本质实际上就是从纹理中获取颜色值,然后应用到物体表面上。而以后我们会接触到的多次纹理映射就是混合多层纹理的颜色,然后应用到物体表面。而为了处理上的方便,Direct3D将颜色的RGB通道和Alpha通道分开来进行处理,具体的操作方法就是通过纹理阶段状态(Texture Stage State)的设置。

其实也就是一个函数IDirect3DDevice9::SetTextureStageState的用法,在MSDN中查到这个函数原型如下:

HRESULT SetTextureStageState([in] DWORD Stage,[in] D3DTEXTURESTAGESTATETYPE Type,[in] DWORD Value);

■ 第一个参数,DWORD类型的Stage,指定当前设置的纹理层为第几层(有效值0~7)

■ 第二个参数,D3DTEXTURESTAGESTATETYPE类型的Type,填将要设置的纹理渲染状态,在枚举类型D3DTEXTURESTAGESTATETYPE中任意取值。先看完第三个参数,然后一起看一下这个D3DTEXTURESTAGESTATETYPE枚举类型。

■ 第三个参数,DWORD类型的Value,表示所设置的状态值,它是根据第二个参数来决定具体取什么值的。

下面就来一起看一下D3DTEXTURESTAGESTATETYPE枚举类型的定义:

typedef enum D3DTEXTURESTAGESTATETYPE {D3DTSS_COLOROP = 1,D3DTSS_COLORARG1 = 2,D3DTSS_COLORARG2 = 3,D3DTSS_ALPHAOP = 4,D3DTSS_ALPHAARG1 = 5,D3DTSS_ALPHAARG2 = 6,D3DTSS_BUMPENVMAT00 = 7,D3DTSS_BUMPENVMAT01 = 8,D3DTSS_BUMPENVMAT10 = 9,D3DTSS_BUMPENVMAT11 = 10,D3DTSS_TEXCOORDINDEX = 11,D3DTSS_BUMPENVLSCALE = 22,D3DTSS_BUMPENVLOFFSET = 23,D3DTSS_TEXTURETRANSFORMFLAGS = 24,D3DTSS_COLORARG0 = 26,D3DTSS_ALPHAARG0 = 27,D3DTSS_RESULTARG = 28,D3DTSS_CONSTANT = 32,D3DTSS_FORCE_DWORD = 0x7fffffff} D3DTEXTURESTAGESTATETYPE, *LPD3DTEXTURESTAGESTATETYPE;

大家可以看到这个枚举中的参数非常多,我们重点看一下前两个参数。

■ D3DTSS_COLOROP:指定纹理颜色的混合方法,对应的Value值(SetTextureStageState第三个参数)在D3DTEXTUREOP枚举类型中取值。我们把几种常用的列出来就好了。Value值取D3DTOP_DISABLE表示禁用当前纹理层颜色输出;Value值取D3DTOP_SELECTARG1或者D3DTOP_SELECTARG2,分别表示将颜色混合阶段的第一个或者第二个参数的颜色值或者alpha值输出。Value值取D3DTOP_MODULATE表示将颜色混合阶层的第一个和第二个颜色相乘并输出。

■ D3DTSS_COLORAG1:取这个值的话表示对纹理颜色混合阶段的第一个参数进行操作,而它的Value值在D3DTA常量中取值,默认值为D3DTA_TEXTURE,表示这个纹理阶段的参数就取纹理的颜色。

然后我们看一看RenderSkyBox函数中用到的两句关于纹理阶段状态的代码:

m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); //将纹理颜色混合的第一个参数的颜色值用于输出m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); //纹理颜色混合的第一个参数的值就取纹理颜色值

第一句SetTextureStageState中我们表示要将纹理颜色混合的第一个参数的颜色值用于输出,然后第二句马上就把第一个参数的颜色值取为纹理颜色值了,这样我们颜色混合后的值就是纹理的颜色值。

解决了纹理颜色混合的问题,后面就好解决了,设置世界矩阵,关联顶点和渲染流水线,设置顶点格式,接着一个for循环设置纹理并渲染,最后再判断一下是否要绘制出线框,一气呵成。实现代码就是这样:

//--------------------------------------------------------------------------------------// Name: SkyBoxClass::RenderSkyBox()// Desc: 绘制出天空盒,可以通过第二个参数选择是否绘制出线框//--------------------------------------------------------------------------------------void SkyBoxClass::RenderSkyBox( D3DXMATRIX *pMatWorld, BOOL bRenderFrame ){m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); //将纹理颜色混合的第一个参数的颜色值用于输出m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); //纹理颜色混合的第一个参数的值就取纹理颜色值m_pd3dDevice->SetTransform( D3DTS_WORLD, pMatWorld ); //设置世界矩阵m_pd3dDevice->SetStreamSource(0,m_pVertexBuffer, 0, sizeof(SKYBOXVERTEX)); //把包含的几何体信息的顶点缓存和渲染流水线相关联m_pd3dDevice->SetFVF(D3DFVF_SKYBOX); //设置FVF灵活顶点格式//一个for循环,将5个面绘制出来for(int i =0; i<5; 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<5; i++){m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i*4, 2);//绘制顶点}m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);//把填充模式调回实体填充}}

Ⅴ.析构函数

最后再实现一下析构函数,看有什么COM接口对象,SAFE_RELEASE就行了:

//-------------------------------------------------------------------------------------------------// Desc: 析构函数//-------------------------------------------------------------------------------------------------SkyBoxClass::~SkyBoxClass(void){SAFE_RELEASE( m_pVertexBuffer );for(int i=0; i<5; i++){SAFE_RELEASE( m_pTexture[i] );}}

这样,一个封装了天空盒的SkyBoxClass类就被我们实现出来了,可以看到,非常简单,只需要填写好六个面的24个顶点,最后为每个面贴上纹理就可以了。

四,天空盒类的使用

别看这个SkyBoxClass天空盒类写起来还有些小麻烦,但是用起来非常方便。

Ⅰ.首先,定义一个SkyBoxClass类的指针:

SkyBoxClass* g_pSkyBox=NULL; //天空盒类的指针实例

Ⅱ.然后,在初始化阶段拿着天空类的指针对象pSkyBox到处“指”,创建并初始化天空:

//创建并初始化天空对象g_pSkyBox = new SkyBoxClass( g_pd3dDevice );g_pSkyBox->LoadSkyTextureFromFile(L"GameMedia\\frontsnow1.jpg",L"GameMedia\\backsnow1.jpg",L"GameMedia\\leftsnow1.jpg",L"GameMedia\\rightsnow1.jpg", L"GameMedia\\topsnow1.jpg");//从文件加载前、后、左、右、顶面5个面的纹理图g_pSkyBox->InitSkyBox(20000); //设置天空盒的边长

这里的GameMedia\\topsnow1.jpg表示在工程文件夹下的GameMedia文件夹中的topsnow1.jpg图片。

Ⅲ.最后,就是在Render函数中依然是拿着天空类的指针对象pSkyBox指一下RenderSkyBox函数,进行渲染。

不过在渲染之前需要给RenderSkyBox函数准备一个合适的世界矩阵,我们这里为了把天空盒调到适当的地方先是创建了一个平移矩阵matTransSky,然后让天空盒可以不停地缓慢移动,创建了一个随系统时间随Y轴旋转的matRotSky矩阵。接着把这两个矩阵相乘,结果等于最终的matSky矩阵,然后就可以把matSky作为参数,调用RenderSkyBox函数了。

//绘制天空D3DXMATRIX matSky,matTransSky,matRotSky;D3DXMatrixTranslation(&matTransSky,0.0f,-3500.0f,0.0f);D3DXMatrixRotationY(&matRotSky, -0.000005f*timeGetTime()); //旋转天空网格, 简单模拟云彩运动效果matSky=matTransSky*matRotSky;g_pSkyBox->RenderSkyBox(&matSky, false);五、详细注释的源代码欣赏

本篇文章配套的源代码在之前的基础上又增加了两个文件,也就是实现天空类的源文件和头文件。全部文件列表如下:

我们依旧只贴出核心代码main.cpp,其他的众多文件大家下源代码回去看就好了。

//*****************************************************************************************////【Visual C++】游戏开发笔记系列配套源码四十九 浅墨DirectX教程十七 三维天空系统的实现// VS2010版// 2013年 3月24日 Create by 浅墨////*****************************************************************************************//*****************************************************************************************// Desc: 宏定义部分//*****************************************************************************************#define SCREEN_WIDTH932//为窗口宽度定义的宏,以方便在此处修改窗口宽度#define SCREEN_HEIGHT700//为窗口高度定义的宏,以方便在此处修改窗口高度#define WINDOW_TITLE_T("【Visual C++】游戏开发笔记系列配套示例程序四十九 浅墨DirectX教程十七 三维天空系统的实现") //为窗口标题定义的宏//*****************************************************************************************// Desc: 头文件定义部分//*****************************************************************************************#include <d3d9.h>#include <d3dx9.h>#include <tchar.h>#include <time.h>#include "DirectInputClass.h"#include "CameraClass.h"#include "TerrainClass.h"#include "SkyBoxClass.h"//*****************************************************************************************// Desc: 库文件定义部分//*****************************************************************************************#pragma comment(lib,"d3d9.lib")#pragma comment(lib,"d3dx9.lib")#pragma comment(lib, "dinput8.lib") // 使用DirectInput必须包含的库文件,注意这里有8#pragma comment(lib,"dxguid.lib")#pragma comment(lib, "winmm.lib")//*****************************************************************************************// Desc: 全局变量
本文链接地址:https://www.jiuchutong.com/zhishi/303709.html 转载请保留说明!

上一篇:python怎么做出一个软件(python怎么做gui)

下一篇:当爬虫被拒绝时(Access Denied) 风中之炎 博客园(爬虫失败的原因)

  • 华为手机怎么将超级终端隐藏(华为手机怎么将联系人导入sim卡)

    华为手机怎么将超级终端隐藏(华为手机怎么将联系人导入sim卡)

  • soul无声连麦是什么(soul连麦怎么没有了)

    soul无声连麦是什么(soul连麦怎么没有了)

  • 腾讯课堂切换设备算时间吗(腾讯课堂切换设备后时长会清空吗)

    腾讯课堂切换设备算时间吗(腾讯课堂切换设备后时长会清空吗)

  • 红米8a有红外线遥控器功能吗(红米8a有红外线遥控器怎么用)

    红米8a有红外线遥控器功能吗(红米8a有红外线遥控器怎么用)

  • 苹果无缘无故温度过高(iphone提示温度过高)

    苹果无缘无故温度过高(iphone提示温度过高)

  • 硬盘容量和内存容量的区别(硬盘容量和内存容量多少合适)

    硬盘容量和内存容量的区别(硬盘容量和内存容量多少合适)

  • 苹果下载不了钉钉怎么回事(苹果下载不了钉钉怎么办)

    苹果下载不了钉钉怎么回事(苹果下载不了钉钉怎么办)

  • b站投稿视频误删怎样恢复(b站投稿视频误删了)

    b站投稿视频误删怎样恢复(b站投稿视频误删了)

  • oppo电话黑名单在哪里?(oppo电话黑名单在哪里解除)

    oppo电话黑名单在哪里?(oppo电话黑名单在哪里解除)

  • 手机分身密码忘了怎么办(手机分身密码忘记了怎么找回)

    手机分身密码忘了怎么办(手机分身密码忘记了怎么找回)

  • 手机隐藏文件怎么显示(手机隐藏文件怎么恢复显示)

    手机隐藏文件怎么显示(手机隐藏文件怎么恢复显示)

  • qq音乐怎么下载到桌面(qq音乐怎么下载歌曲)

    qq音乐怎么下载到桌面(qq音乐怎么下载歌曲)

  • word图片下方如何添加文字(word图片下方加文字是如何做出来的)

    word图片下方如何添加文字(word图片下方加文字是如何做出来的)

  • iphone5怎样录屏(苹果5怎么样录屏)

    iphone5怎样录屏(苹果5怎么样录屏)

  • 荣耀20怎么锁定后台(荣耀20怎么锁定手机屏幕)

    荣耀20怎么锁定后台(荣耀20怎么锁定手机屏幕)

  • 数字机顶盒怎么连接显示器(数字机顶盒怎么搜台)

    数字机顶盒怎么连接显示器(数字机顶盒怎么搜台)

  • 手机怎样定位另一个手机(手机怎样定位另一个人手机位置)

    手机怎样定位另一个手机(手机怎样定位另一个人手机位置)

  • 水果店收银系统怎么弄(水果店收银系统哪个好)

    水果店收银系统怎么弄(水果店收银系统哪个好)

  • 被限流了手机怎么处理(被限流了手机怎么解除)

    被限流了手机怎么处理(被限流了手机怎么解除)

  • 三星note9防水吗(三星note9防水胶怎么贴)

    三星note9防水吗(三星note9防水胶怎么贴)

  • 查对方qq绑定的手机号(查对方qq绑定的手机号网站)

    查对方qq绑定的手机号(查对方qq绑定的手机号网站)

  • qq帐号是什么(qq申请账号)

    qq帐号是什么(qq申请账号)

  • 快手怎么配自己唱的(快手怎么配自己喜欢的音乐)

    快手怎么配自己唱的(快手怎么配自己喜欢的音乐)

  • 租赁服务增值税税率
  • 红字专票进项税额如何做
  • 增值税降到16个点什么时候实行
  • 财政拨款收入年底结转到本期盈余
  • 国外包裹退回费用
  • 残疾人士有哪些
  • 外购无形资产的相关税费包括增值税吗
  • 公司收到虚开发票谁承担
  • 社会团体收费项目有哪些
  • 收取加盟费如何交税
  • 标书费收据丢失怎么办
  • 营改增之后餐饮业的税收政策
  • 教育经费税前扣除标准
  • 税务局申请发票
  • 递延年金现值计算公式解释
  • 税务利润表怎么填
  • 固定资产明细账有哪些
  • 政府补助的会计核算
  • 企业做账会计需要什么资质
  • 每月物业费怎么计算公式
  • 代开票扣了个人所得税怎么做账?
  • 国际工程物资采购网
  • 劳务成本属于费用项目吗
  • 企业在进行会计核算时选择一种不多计资产
  • 账务和申报表不一致
  • php实现的一致性是什么
  • 减免的税款还用做分录吗
  • 公司多缴税款了怎么办?可以退吗?
  • 电脑故障检测与维护方法
  • 酒店损益类科目包括哪些
  • css合并为单一边框
  • 高新技术企业加计5%
  • 一叶兰的养殖方法和注意事项有哪些
  • 从上魏斯巴赫山地列车的车站向外看,德国图林根 (© golero/iStock/Getty Images Plus)
  • 残保金政策建议
  • pytorch广播相乘
  • 劳务派遣开具发票
  • 火车票抵税申报表怎么填
  • 关税对企业有什么影响
  • 应收票据应付票据合并抵消吗
  • 小规模纳税人季度不超30万怎么做账
  • 会计备案报送期间
  • 免税收入和免征
  • 织梦怎么建站
  • 自产的货物用于在建工程增值税
  • 资产负债表期末余额是累计数吗
  • sql server 递归
  • 建筑业成本核算表格
  • 职工福利费的会计处理
  • 承租人转租房屋的后果
  • 核定征收所得税税率是多少
  • 当月暂估入账跨月怎么算
  • 机动车转让后未过户原车主要承担赔偿责任
  • 可供分配的利润分配顺序
  • 建筑服务红字发票需要填写备注吗
  • 弥补以前年度亏损后缴纳所得税
  • 粗纤维测定仪价格
  • 企业主要的工会是什么
  • 公司费用报销单样本
  • 汽车4s店有哪些功能
  • 保洁阿姨工资怎么扣税
  • win8局域网共享设置
  • Win10 Mobile 10549预览版怎么升级?
  • solaris的vi编辑
  • win10系统任务栏卡顿
  • imac如何删除客人用户
  • mac如何连接iphone
  • win10 自带
  • 双系统重装win11
  • windows电脑图片传到iphone
  • ssh用法及命令
  • 10分钟掌握心理学
  • android网络通信http
  • settimeout和setinterval在安卓机无效
  • 税务局收垃圾处置费
  • 举报纳税电话
  • 吉林税务发票自动查询系统网
  • 仓库需要交房产税吗
  • 济宁市税务局官网名称
  • 纳税服务基本情况总结
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设