位置: 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) 风中之炎 博客园(爬虫失败的原因)

  • 电子设备租赁费专票税率
  • 什么时候要计提坏账准备
  • 增值税发票综合服务平台密码
  • 小规模纳税人印花税最新政策2023
  • 三个案例看清增值税即征即退?
  • 个人转让著作权免税吗
  • 两个公司发工资怎么交个税
  • 收到原材料发票的会计分录
  • 待摊费用属于企业的费用
  • 外经证错了已经交了税怎么办
  • 不能抵扣进项税额的发票类型
  • 入资款印花税怎么计算
  • 经营性应收项目和经营性应付项目
  • 暂估入库必须次日入库吗
  • 已报废的固定资产
  • 出口退税进项税额转出是什么意思
  • 案例分析工程发票进项高于销项怎么抵扣?
  • 小规模纳税人设备税率
  • 房租发票进项税额抵扣
  • 资产总额季初和季末
  • 计提本季度所得税会计分录
  • 电子发票没有纳税人识别号可以报销吗
  • 汇兑损益怎么入账
  • 七彩虹主板 wol
  • 高新企业研发费用占销售收入的比例
  • linux 网络故障
  • 债券利息收入属于什么会计科目
  • 仓储费用结算方式有哪些
  • 补交社保如何做账务处理
  • 苹果推送最新系统怎么关
  • php生成随机字符串源,且不会重复出现
  • php如何防止xss攻击
  • php imagettftext
  • 深入解析Laravel5.5中的包自动发现Package Auto Discovery
  • 退回的企业所得税怎么做账
  • 公司客户招待费用标准
  • background-size 之 背景图的尺寸设置
  • 用支付宝支付的游戏
  • Android ImageView使用详解(系列教程三)
  • 股息和未分配利润的区别
  • 微擎框架可以干什么
  • 资产负债表没有期末数
  • 减资的程序
  • 异地工作人员管理
  • 开基本户一定要法人身份证吗
  • 浅析学校德育的个体智能发展功能
  • div不规则排版
  • 企业所得税报表查询怎么查
  • 大货车怎样申请报废
  • 计提的费用收到发票时候怎么做账
  • 应付账款从质保金扣除
  • 收到发票未抵扣,收票方也可以开红字信息表吗?
  • 当月已经认证的发票可以取消认证吗
  • 暂估入库后发票整单折扣
  • 材料采购发生的共同费用可以按什么作为分配基础
  • 运费开什么发票
  • 公司有主营业务收入没有主营业务成本
  • MySql insert插入操作的3个小技巧分享
  • mysql数据库的基本原理
  • win8系统打开软件很慢
  • windowsxp
  • ubuntu20.04设置
  • .exe是什么软件
  • xp系统怎么打开启动项
  • win7系统自带网卡吗?
  • 正版win10怎么用
  • win7系统如何添加打印机
  • 5个小技巧让你成长
  • 图形学实验报告总结
  • ExtJS4如何自动生成控制grid的列显示、隐藏的checkbox
  • Quick cocos2dx-Lua(V3.3R1)学习笔记(8) ---- 事件篇之单点触摸事件,让我们用精灵模仿一个按钮吧
  • nodejs xhr
  • linux shell -s
  • jquery lt
  • django实时刷新日志前端
  • unity2d序列帧
  • jq拖拽功能
  • 西安市国家税务局稽查局
  • 税务局六大攻坚
  • 税务鉴定收费标准
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设