Irrlicht 3D Engine 笔记系列 之 教程6- 2D Graphics

作者:i_dovelemon

日期:2015 / 7 / 1

来源: CSDN

主题:2D Graphics, Irrlicht

教程翻译

本篇教程将要向大家展示如何使用Irrlicht引擎绘制2D图形。绘制2D图形能够让我们制作一个2D游戏或者绘制一些漂亮的用户界面和HUD出来。

和以前一样,包含一些头文件,使用irr命名空间,并且通知连接器链接lib文件:

#include <irrlicht.h>
#include "driverChoice.h"

using namespace irr;

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif

首先,我们让用户选择设备驱动的类型,然后启动引擎,设置一个标题,获取视频设备的指针。

int main()
{
    // ask user for driver
    video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (driverType==video::EDT_COUNT)
        return 1;

    // create device

    IrrlichtDevice *device = createDevice(driverType,
        core::dimension2d<u32>(512, 384));

    if (device == 0)
        return 1; // could not create selected driver.

    device->setWindowCaption(L"Irrlicht Engine - 2D Graphics Demo");

    video::IVideoDriver* driver = device->getVideoDriver();

在本教程中所有需要使用到的2d图形,都保存在纹理文件2ddemo.png中(可以在引擎文件夹中找到)。由于我们希望绘制带有colorkey的sprite,所以,我们需要加载这个纹理,然后通知引擎,如何根据colorkey来使纹理的哪一个部分透明掉。

在本教程中,我们不直接的告知引擎要把哪个颜色透明掉,而是通知引擎把和某个位置的颜色值一样的像素透明掉。同样,我们也能够通过直接指定颜色,来将纹理中的特定颜色透明掉。需要注意的是makeColorKeyTexture函数仅仅是根据给定的颜色值,为具有该颜色的像素设置alpha通道,从而使其透明。

    video::ITexture* images = driver->getTexture("../../media/2ddemo.png");
    driver->makeColorKeyTexture(images, core::position2d<s32>(0,0));

为了能够绘制文本,我们需要先加载字体。首先,我们使用引擎内置的字体来绘制。然后加载另外一个外部的字体。同时我们还需要指定在纹理的什么位置存在着我们想要绘制的图片。

    gui::IGUIFont* font = device->getGUIEnvironment()->getBuiltInFont();
    gui::IGUIFont* font2 =
        device->getGUIEnvironment()->getFont("../../media/fonthaettenschweiler.bmp");

    core::rect<s32> imp1(349,15,385,78);
    core::rect<s32> imp2(387,15,423,78);

准备一个好的2D过滤器,用来对纹理尽心过滤采样等。

    driver->getMaterial2D().TextureLayer[0].BilinearFilter=true;
    driver->getMaterial2D().AntiAliasing=video::EAAM_FULL_BASIC;

好了,所有的工作,都准备完毕了,现在我们在绘制循环中绘制所有的内容。在本教程中,我们仅仅绘制2d图形,但是我们同样可以在beginscene和endscene之间添加其他绘制3D图形的函数调用。

    while(device->run() && driver)
    {
        if (device->isWindowActive())
        {
            u32 time = device->getTimer()->getTime();

            driver->beginScene(true, true, video::SColor(255,120,102,136));

首先,我们绘制3个sprite。函数的最后一个参数,表示我们是否使用纹理像素中的alpha通道值。倒数第二个参数用于给定一个颜色值,通过这个值我们能够对图形2d图形进行二次着色,并且改变纹理整体的透明度。如果值为(255,255,255,255)那么纹理将保持不变。最后一个sprite使用基于时间来改变的r通道进行绘制。

            // draw fire & dragons background world
            driver->draw2DImage(images, core::position2d<s32>(50,50),
                core::rect<s32>(0,0,342,224), 0,
                video::SColor(255,255,255,255), true);

            // draw flying imp
            driver->draw2DImage(images, core::position2d<s32>(164,125),
                (time/500 % 2) ? imp1 : imp2, 0,
                video::SColor(255,255,255,255), true);

            // draw second flying imp with colorcylce
            driver->draw2DImage(images, core::position2d<s32>(270,105),
                (time/500 % 2) ? imp1 : imp2, 0,
                video::SColor(255,(time) % 255,255,255), true);

绘制文本非常的简单。下面的代码已经能够自我解释了。

            // draw some text
            if (font)
                font->draw(L"This demo shows that Irrlicht is also capable of drawing 2D graphics.",
                    core::rect<s32>(130,10,300,50),
                    video::SColor(255,255,255,255));

            // draw some other text
            if (font2)
                font2->draw(L"Also mixing with 3d graphics is possible.",
                    core::rect<s32>(130,20,300,60),
                    video::SColor(255,time % 255,time % 255,255));

接下来,我们绘制一个Irrlicht引擎的Logo。由于我们使用了过滤器,所以稍微的对纹理进行缩放操作。

            driver->enableMaterial2D();
            driver->draw2DImage(images, core::rect<s32>(10,10,108,48),
                core::rect<s32>(354,87,442,118));
            driver->enableMaterial2D(false);

最后,在鼠标的位置绘制一个半透明的矩形出来。

            core::position2d<s32> m = device->getCursorControl()->getPosition();
            driver->draw2DRectangle(video::SColor(100,255,255,255),
                core::rect<s32>(m.X-20, m.Y-20, m.X+20, m.Y+20));

            driver->endScene();
        }
    }

    device->drop();

    return 0;
}

好了,这就是本教程的全部了。

重点内容解析

IVideoDriver继承树

在上面的教程中,我们可以看到加载纹理,对纹理进行操作,最终绘制纹理都是通过IVideoDriver的指针来进行的。所以,很有必要对IVideoDriver做一番基础的研究。

首先,我们需要知道,IVideoDriver仅仅是一个接口,那么它到底派生了多杀个类,并且在本程序中使用的是哪一个了?Irrlich是如何决定要使用哪一个派生类的了?

通过VS2010的查看工具,我们能够看到IVideoDriver具有如下的继承树:

图1 IVideoDriver继承树

从图中可以看出IVideoDriver接口是用来给用户使用的接口,在这个接口之上派生了一个CNullDriver类,这个类定义了一些VideoDriver共有的函数功能实现。然后在CNullDriver的基础上,再次的继承了5个不同的VideoDriver,分别为:

  • CBurningVideoDriver
  • CD3D8Driver
  • CD3D9Driver
  • COpenGLDriver
  • CSoftwareDrive

这几个VideoDriver,分别基于不同的设备驱动来实现的。对于一个CBurningVideoDriver,暂时不知道基于什么设备驱动实现,貌似是优化的软件渲染设备。至于后面的CD3D8Driver就是基于DirectX8的渲染设备,CD3D9Driver就是基于DirectX9的渲染设备;COpenGLDriver就是基于OpenGL的渲染设备了;CSoftwareDriver就是基于软件实现的渲染设备。

上面展示的是IVideoDriver的整体继承结构图。接下来,我们详细的看看IVideoDriver的作用。

IVideoDriver的用途

打开IVideoDriver接口的文件,里面有如下一段话:

//! Interface to driver which is able to perform 2d and 3d graphics functions.

/** This interface is one of the most important interfaces of

the Irrlicht Engine: All rendering and texture manipulation is done with

this interface. You are able to use the Irrlicht Engine by only

invoking methods of this interface if you like to, although the

irr::scene::ISceneManager interface provides a lot of powerful classes

and methods to make the programmer‘s life easier.

*/

这段话的意思是说:IVideoDriver接口用于进行2D和3D图形操作的接口。这个接口是Irrlich引擎中最重要的接口之一:所有的渲染和纹理操作都是通过这个接口实现的。我们只有通过这个接口来使用Irrlich引擎的渲染功能,同时ISceneManager接口也提供了大量的强有力的函数来使我们的工作更加的容易。

从这段话就可以看出,IVideoDriver的主要功能就是给用户提供接口,进行2D和3D渲染以及纹理操作等。算是对底层图形API的封装层面。通过这个接口,能够使我们以一种统一的方式对底层的图形API进行快速的操作,加快我们开发的效率。而关于这个接口里面提供的诸多函数,将在后面的教程中像大家一一的解释。

引擎如何选择创建哪种VideoDriver?

为了了解这个问题,我们需要跟踪程序的执行过程,明确在什么地方对VideoDriver进行创建的。在跟踪了程序执行路径之后,得到如下的函数:

<span style="font-family:Microsoft YaHei;font-size:14px;">//! create the driver
void CIrrDeviceWin32::createDriver()
{
	switch(CreationParams.DriverType)
	{
	case video::EDT_DIRECT3D8:
		#ifdef _IRR_COMPILE_WITH_DIRECT3D_8_

		VideoDriver = video::createDirectX8Driver(CreationParams, FileSystem, HWnd);

		if (!VideoDriver)
		{
			os::Printer::log("Could not create DIRECT3D8 Driver.", ELL_ERROR);
		}
		#else
		os::Printer::log("DIRECT3D8 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
		#endif // _IRR_COMPILE_WITH_DIRECT3D_8_

		break;

	case video::EDT_DIRECT3D9:
		#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_

		VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);

		if (!VideoDriver)
		{
			os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);
		}
		#else
		os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
		#endif // _IRR_COMPILE_WITH_DIRECT3D_9_

		break;

	case video::EDT_OPENGL:

		#ifdef _IRR_COMPILE_WITH_OPENGL_
		switchToFullScreen();

		VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this);
		if (!VideoDriver)
		{
			os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
		}
		#else
		os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);
		#endif
		break;

	case video::EDT_SOFTWARE:

		#ifdef _IRR_COMPILE_WITH_SOFTWARE_
		switchToFullScreen();

		VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
		#else
		os::Printer::log("Software driver was not compiled in.", ELL_ERROR);
		#endif

		break;

	case video::EDT_BURNINGSVIDEO:
		#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
		switchToFullScreen();

		VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
		#else
		os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);
		#endif
		break;

	case video::EDT_NULL:
		// create null driver
		VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
		break;

	default:
		os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
		break;
	}
}</span>

从这个函数就可以看出,创建VideoDriver的决定是根据CreationParams.DriverType的值来决定的,而这个值是由用户在创建Device的时候指定的,对于本教程来说该值为:EDT_DIRECT3D9。

ITexture继承树

本教程中,还是用到了另外一个比较重要的接口:ITexture。从名字中可以看出,这个接口是用于表示纹理的接口。我们同样的对该接口以及接口的继承树了解下。下面是它的继承树结构图:

图2 ITexture继承树

从上图可以看出,在Irrlich引擎中创建了6种不同的纹理类型,分别为:

  • CD3D8Texture
  • CD3D9Texture
  • COpenGLTexture
  • CSoftwareTexture
  • CSoftwareTexture2
  • SDummyTexture

ITexture的用途

打开ITexture的头文件,看下它的描述:

//! Interface of a Video Driver dependent Texture.

/** An ITexture is created by an IVideoDriver by using IVideoDriver::addTexture

or IVideoDriver::getTexture. After that, the texture may only be used by this

VideoDriver. As you can imagine, textures of the DirectX and the OpenGL device

will, e.g., not be compatible. An exception is the Software device and the

NULL device, their textures are compatible. If you try to use a texture

created by one device with an other device, the device will refuse to do that

and write a warning or an error message to the output buffer.

*/

翻译出来就是:依赖于VideoDriver的纹理接口。一个ITexture对象是通过IVideoDriver接口中的addTexture或者getTexture来创建出来的。创建完毕之后,这个纹理就只能够被这个VideoDriver所使用。你可以想象出来,DirectX的纹理格式和OpenGL的纹理格式肯定是不一样的。一个特殊的情况是NULLDriver和SoftwareDriver,他们的纹理格式是兼容的。如果你将另外一个VideoDriver创建的ITexture给其他的VideoDriver使用,程序将会保存,并且给出错误信息。

从这个描述就可以明白,上面提供的纹理,实际上是和具体的VideoDriver绑定在一起的。而一个ITexture主要的就是对具体VideoDriver的Texture格式进行了封装操作而已。

关于ITexture接口中的函数内容,将在后续教程给出。

结束语

引擎的研究非一日之功,切不可急功近利,患得患失。做技术的人,要耐得住寂寞,深入到技术源头中去学习先人们伟大的智慧结晶!!!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 03:12:40

Irrlicht 3D Engine 笔记系列 之 教程6- 2D Graphics的相关文章

Irrlicht 3D Engine 笔记系列之 教程4 - Movement

作者: i_dovelemon 日期: 2014 / 12 / 16 来源: CSDN 主题: Event Receiver, Animator, Framerate independent movement and framerate dependent movement 引言 从今天開始,博主将进行对3D Engine的学习.而且,在博客中将自己学习的心得一一分享给大家.希望可以对大家有所帮助.也希望可以找到志同道合的同伴一起学习3D 游戏引擎方面的知识. 为什么选择Irrlicht? 在非

Irrlicht 3D Engine 笔记系列 之 教程5- User Interface

作者:i_dovelemon 日期:2014 / 12 / 18 来源:CSDN 主题:GUI 引言 今天,博主学习了第五个教程.这个教程讲解了如何使用Irrlicht内置的一个基础模块,GUI模块,来开发一些GUI程序.作为Irrlicht的重要基础模块,博主有必要对此进行一些代码跟踪和深入的了解.详细的教程过程请看官网. 设备选择 以前在使用Ogre的时候,它的程序运行之初都会问你需要使用的是哪一种API.那么在Irrlicht引擎中是否有同样的功能了?答案是肯定,在Irrlicht的dri

Irrlicht 3D Engine 笔记系列 之 自己定义Animator

作者: i_dovelemon 日期: 2014 / 12 / 17 来源: CSDN 主题: Custom Animator, Referenced count 引言 在昨天的文章<Irrlicht 3D Engine 笔记系列 之 教程4 - Movement>中,博主向大家保证会在今天向大家实际操作怎样扩展Irrlicht引擎的Animator特性.假设读者对Irrlicht的Animator的特性不是非常了解的话,请先了解下前面的那篇文章,本片文章是在上次文章的基础上进行的. Cust

Irrlicht 3D Engine 笔记系列 之 自定义Animator

作者: i_dovelemon 日期: 2014 / 12 / 17 来源: CSDN 主题: Custom Animator, Referenced count 引言 在昨天的文章<Irrlicht 3D Engine 笔记系列 之 教程4 - Movement>中,博主向大家保证会在今天向大家实际操作如何扩展Irrlicht引擎的Animator特性.如果读者对Irrlicht的Animator的特性不是很了解的话,请先了解下前面的那篇文章,本片文章是在上次文章的基础上进行的. Custo

《zw版&#183;Halcon-delphi系列原创教程》 2d照片-3d逆向建模脚本

<zw版·Halcon-delphi系列原创教程> 2d照片-3d逆向建模脚本 3D逆向建模,是逆向工程的核心要素.       3D逆向建模,除了目前通用的3D点云模式,通过2D图像实现快速3D建模,也是目前的重要手段.       2D图像的3D逆向建模,目前常用的有两种模式,一个是左右视距(或多角度取景)图片叠加处理,google的卫星地图3D化,就是这个模式.       另外一种,就是本文要介绍的3D定标模式(handeye??模式),就是在现场先拍摄一张标准3D定标图片,获取定位参

Unreal Engine 4 系列教程 Part 1:入门

.katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > .katex-html { display: block; } .katex-display > .katex > .katex-html > .tag { position: absolute; right: 0px; } .katex { font: 1.21em/1.2 KaTeX_M

C#温故知新:《C#图解教程》读书笔记系列

一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种特性.新版本除了精心修订旧版内容外,还全面涵盖了C# 5.0的新增特性,比如异步编程.调用者信息.case表达式.带参数的泛型构造函数.支持null类型运算等.通过本书,读者能够快速.深入地理解C#,为自己的编程生涯打下良好的基础. 本书是C#入门的经典好书,适合对C#感兴趣的所有读者.Daniel

《zw版&#183;Halcon-delphi系列原创教程》 Halcon分类函数001&#183;3D函数

<zw版·Halcon-delphi系列原创教程> Halcon分类函数001·3D函数 为方便阅读,在不影响说明的前提下,笔者对函数进行了简化: :: 用符号“**”,替换:“procedure” :: 用大写字母“X”,替换:“IHUntypedObjectX” :: 省略了字符:“const”.“OleVariant” [示例] 说明 函数: procedure AddNoiseWhiteContourXld( const Contours: IHUntypedObjectX; out

C#刨根究底:《你必须知道的.NET》读书笔记系列

一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP-王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心得和感悟,将技术问题以生动易懂的语言展开,层层深入,以例说理.全书主要,包括了.NET基础知识及其深度分析,以.NET Framework和CLR研究为核心展开.NET本质论述,涵盖了.NET基本知识几乎所有的重点内容.全书分为5个部分,第1部分讲述.NET与面向对象,从底层实现角度分析了.NET如何实现面向