当前位置: 首页 > news >正文

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接口也提供了大量的强有力的函数来使我们的工作更加的easy。
从这段话就行看出。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接口中的函数内容,将在兴许教程给出。

结束语

引擎的研究非一日之功,切不可急功近利,患得患失。

做技术的人,要耐得住寂寞。深入到技术源头中去学习先人们伟大的智慧结晶!!

相关文章:

  • 支撑起整个互联网时代的 7 款开源软件
  • 【Windows 10 应用开发】如何防止应用程序被截屏
  • gradle.org
  • c# 可空类型
  • jQuery的选择器总结
  • 流程管理软件示例:构建闭环的隐患管理
  • dubbo请求调用过程分析
  • AC日记——魔法森林 洛谷 P2387
  • Nginx/LVS/HAProxy负载均衡软件的优缺点详解
  • WebRTC学习资料大全
  • 分布式文件系统 IPFS
  • 第一章、shell脚本基础
  • JAVASE学习笔记:第十章 SWing经常使用控件类(二)
  • DDD中分层架构
  • ssl证书生成方法
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • 10个确保微服务与容器安全的最佳实践
  • ES6核心特性
  • golang 发送GET和POST示例
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript HTML DOM
  • JavaScript中的对象个人分享
  • Promise面试题2实现异步串行执行
  • React+TypeScript入门
  • TypeScript实现数据结构(一)栈,队列,链表
  • 订阅Forge Viewer所有的事件
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 前端代码风格自动化系列(二)之Commitlint
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 我的zsh配置, 2019最新方案
  • 责任链模式的两种实现
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 数据可视化之下发图实践
  • (HAL库版)freeRTOS移植STMF103
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (汇总)os模块以及shutil模块对文件的操作
  • (四)Android布局类型(线性布局LinearLayout)
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)c++ std::pair 与 std::make
  • (转)德国人的记事本
  • ./和../以及/和~之间的区别
  • .aanva
  • .form文件_一篇文章学会文件上传
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .net core 依赖注入的基本用发
  • .NET Reactor简单使用教程
  • .net Stream篇(六)
  • .Net 路由处理厉害了
  • .NET(C#) Internals: as a developer, .net framework in my eyes