位置: IT常识 - 正文

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

发布时间:2024-01-21
本系列文章由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) 风中之炎 博客园(爬虫失败的原因)

  • 小型微利企业所得税减免政策
  • 车险发票不含车船税怎么记账
  • 主营业务成本的数据从哪里来的
  • 小规模企业多交增值税
  • 工程的管理费收入怎么算
  • 接收抵债资产税费
  • 企业归还借款给个人
  • 无形资产使用费计入什么科目
  • 房租合同印花税计算方法
  • 收购发票怎么做凭证
  • 事业单位收到借款分录
  • 公司厨房用品专用发票怎么处理?
  • 对公受托理财赎回分录
  • 外资企业银行贷款限制
  • 通行费进项抵扣条件
  • 待处理财产损益借贷方向
  • 印花税应税凭证填是还是否
  • 农业企业销售林木违法吗
  • 个税合理避税的意义
  • 企业所得税预缴计算方法
  • 建筑劳务公司人员结构
  • 纳税退税申请表的基本情况如何写
  • 成本和费用属于资产吗
  • 培训费开发票明细为会议费如何做账?
  • 注销未分配利润怎么处理账务
  • 其他流动负债有利息吗
  • 应收账款周转天数和应收账款周转率的关系
  • 什么车不用交保险
  • php实现的中秋博饼游戏之绘制骰子图案功能示例
  • 电脑耳机插上还是外放,重启就可以
  • 鸿蒙系统怎么开启OTG
  • gnu/linux
  • PHP:curl_pause()的用法_cURL函数
  • 康沃尔郡的大学
  • php中文出现乱码
  • 如何根据科目余额表编制财务报表
  • 违法汽车查询
  • 哪些服务可以开具经纪代理服务发票
  • 个人能去税务局开劳务费发票吗
  • 外贸企业申报出口退税资料
  • 服务费减免税款怎么算
  • 将原生html改成vue
  • 增值税发票税率1%
  • 个人所得税数据怎么导入新电脑
  • 百旺税控盘会自动清卡吗
  • 小规模纳税人做工资没交社保
  • 金税三期个税申报
  • 研发费用的台账由谁做
  • 商标 入账
  • 帮对方代垫运费计入什么科目
  • 赠品不开票怎么办
  • 微信怎么帮别人代缴社保
  • 房子装修费要交税吗
  • 正确使用显微镜的七个步骤
  • mysql 全量备份
  • mac怎么共享wifi密码给iphone
  • 在基于Xen的CentOS系统VPS上配置PPTP VPN的教程
  • fedora打不开
  • cosplay步骤
  • mac osx 10.8
  • 双系统电脑怎么装系统
  • igfxem module是什么程序
  • win1020h2版本是正式版吗
  • win81无线网络没有了
  • linux命令git
  • win7屏幕调节不见了
  • win7旗舰版升级win10教程
  • win10不能玩qq堂没反应
  • 做网页需要域名吗
  • 怎么做小地图图片呢
  • js字符串的操作方法
  • python怎么写链表
  • shell 非
  • JavaScript的Number对象的toString()方法
  • 国税局税务大厅电话
  • 曲靖市税务局领导班子
  • 农村医保网上如何查询
  • 税务稽查追溯时间是什么意思
  • 四川税务网上报税
  • 新版ukey税盘怎么设置密码
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号