1.说明
这个例程涉及:如何创建一个定制场景节点.
适用于:如果要使用irrlicht不支持的渲染技术的情况下.
比如:你可以通过它写一个基于渲染器的室内入口和高级地形场景节点
(原文是:an indoor portal based renderer or an advanced terrain scene
node)
node)
.....通过定制场景节点可以扩展irrlicht引擎并适应个性需求.
2.编写定制的:CSampleSceneNode
目标:要定制场景节点绘制一个旋转的四面体.
CSampleSceneNode需要继承irr::scene::ISceneNode类,并且重写一些方法.
1)需要新增的参数包括:
core::aabbox3d<f32> Box;//包围盒
video::S3DVertex Vertices[4];//四个顶点
video::SMaterial Material;//材质
2)在构造函数中,初始初始化上述三个参数,还需要额外的:
scene::ISceneNode* parent,//指向父节点的指针
scene::ISceneManager* mgr,//指向场景管理器的指针,内部用SceneManager保存
s32 id.//唯一的id
3) 1)处新增参数的参数设置:
(1)Material
material有很多参数,可以用.来设置,因为参数都为public,要是用某个功能一般需要开启相应状态,
所有状态参数参数都可以通过方法irr::video::SMaterial::setFlag(EMF_*_*,bool value)来设置,irr::video::SMagerial::getFlag(E_MATERIAL_FLAG flag)来获得.
比如这里要使物体可见(关闭灯光,因为没有设置灯)且渲染成面:
Material.Wirefram = false;//默认为false,也可以:Material.setFlag(EMF_WIREFRAM,false);
Material.Lighting = false;//默认为true,也可以:Material.setFlag(EMF_LIGHTING,false);
(2)Vertex
参数列表:
core::vector3df Pos;//坐标
core::vector3df Normal;//法向量
SColor Color;//颜色
core::vector2d<f32> Tcoords;//纹理坐标
需要通过构造函数为参数初始化值,然后通过 = 复制到已经有的对象.
比如:
Vertices[0] = video::S3DVertex(
x,y,z,//Pos
nx,ny,nz,//Normal
video::SColor(a,r,g,b),//Color
tu,tv//Tcoord
);
irr::video::S3DVertex内部提供有一些有用的方法,比如位置比较,判断
(3)Box(irr::core::aabbox3d<T>)
参数列表:
vector3d<T> MinEdge;
vector3d<T> MaxEdge;
原理:输入一群点,找到一个立方体盒子使它包围所有的点.立方体由上述参数保存.
可以通过(2)的方法设置一个包围盒.
但这个模版类内部提供了大量实用的方法用于设置和使用包围盒.
设置包围盒的核心函数:
void addInternalPoint(T x,T y ,T z);
还有一些判断点,线,面与包围盒的关系的方法.
这里我们用如下方法设置包围盒,先用一个点初始化,再把其他店插入包围盒,其内部自动处理.
Box.reset(Vertices[0].Pos);
for(s32 i=1;i<4;i++)
Box.addInternalPoint(Vertices[i].Pos);4)注册
我们要达到的目标是通过这个定制场景节点绘制一个四面体,那么就需要场景管理器sgmr->drawAll()自动调用场景节点的绘制方法.
因此需要提前注册(irr::scene::ISceneNode::OnRegisterSceneNode()),这也就是告诉smgr,绘制的时候请调用我们的定制节点的irr::scene::ISceneNode::render()方法.
同时绘制是有顺序的,我们也可以设置我们的场景节点的优先顺序,这可以在注册的时候进行.
要用到的注册函数(irr::scene::ISceneManager内):
virtual u32 registerNodeForRendering(ISceneNode* node,//一般为this
E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC
/*第二个参数用于设置渲染顺序的,参数为:
*irr::scene::E_SCENE_NODE_RENDER_PASS中的一个(enum)
*/
) = 0;
//重写OnRegisterSceneNode方法,官方格式.
virtual void OnRegisterScene()
{
if(IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();//这个方法内部实现的是为所有子节点注册,
//当内部调用这个回调函数的时候会调用registerNodeForRendering(this);
}
5)重写定制节点的render方法
三步:设置材质,获得变换矩阵,绘制.
video::IVideoDriver是Irrlicht中非常重要的接口,所有跟渲染和纹理操纵都是通过这个接口完成.
它管理了我们使用的渲染器,场景绘制需要通过它完成.
重写render方法:
virtual void render()
{
u16 indices[] = {0,2,3,/*第一个面*/
2,1,3,/*第二个面*/
1,0,3,/*第三个面*/
2,0,1/*第四个面*/};
video::IVideoDriver* driver = SceneManager->getVideoDriver();//保存在smgr中的driver
driver->setMaterial(Material);//启用当前材质,内部根据渲染器不同
//设置变换
driver->setTransform(video::ETS_WORLD,/*view, world, projection*/
AbsoluteTransformation/*scene::ISceneNode内:
core::matrix AbsoluteTransformation,保存矩阵用*/
);
//绘制
dirver->drawVertexPrimitiveList(
&Vertices[0],/*最多65535个顶点*/
4,/*顶点总数*/
&indices[0],/*绘制顶点的顺序表*/
4,/* 图元数量*/
v video::EVT_STANDARD,/*顶点格式*/
scene::EPT_TRIANGLES,/*绘制的图元种类*/
EIT_16BIT/*indices的数据类型*/
);
}6)三个附加的方法
获得包围盒,获得材质总数,获得材质句柄
virtual const aabbox3df& getBoundingBox() const
{
return Box;
}
virtual u32 getMaterialCount() const
{
return 1;
}
virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}
3.在主程序中加入定制部分:
1)添加节点对象
方法很简单,就是创建一个定制场景节点对象.
比如:
CSampleSceneNode *myNode = new CSampleSceneNode(
smgr->getRootSceneNode(),
smgr,
123
);
Irrlicht引擎会管理我们的节点.
为了更规范,我们需要释放引用:
myNode->drop();
myNode = 0;2)加入动画
为我们的myNode加入一个动画:旋转.
步骤:
(1).创建一个动画
(2).为myNode加入此动画
动画类:scene::ISceneNodeAnimator
(1)创建旋转动画:
通过场景管理器的接口创建.
scene::ISceneManager::createRotationAnimation(core::vector3df(rx,ry,rz));
参数代表每秒每个方向旋转多少度.
注意:vector3d可以用来表示旋转角度,X:pitch,Y:yaw,Z:roll.这个不是跟坐标系的xyz一一对应的.
(2)为myNode绑定一个动画
myNode->addAnimator(anim);
函数内部:
将anim推入Animators链表中(core::list<ISceneNodeAnimator*> Animators;),
然后anim->grab();(irr::IReferenceCounted引用计数器)攥取对象,
之后(函数外部)必须调用anim->drop().
4.全部代码
#include <irrlicht.h>
using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib,"Irrlicht.lib")
#endif
class CSampleSceneNode :public scene::ISceneNode
{
/*成员:包围盒,四个顶点,材质*/
core::aabbox3d<f32> Box;
video::S3DVertex Vertices[4];
video::SMaterial Material;
public:
/*构造函数:父节点,场景管理器的指针,场景节点的id*/
CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr,
s32 id) :scene::ISceneNode(parent, mgr, id)
{
//Material.Wireframe = false;
Material.Lighting = false;
Vertices[0] = video::S3DVertex(0, 0, 10, 1, 1, 0,
video::SColor(255, 0, 255, 255), 0, 1);
Vertices[1] = video::S3DVertex(10, 0, -10, 1, 0, 0,
video::SColor(255, 255, 0, 255), 1, 1);
Vertices[2] = video::S3DVertex(0, 20, 0, 0, 1, 1,
video::SColor(255, 255, 255, 0), 1, 0);
Vertices[3] = video::S3DVertex(-10, 0, -10, 0, 0, 1,
video::SColor(255, 0, 255, 0), 0, 0);
//包围盒初始化,这个是必须的,用于自动裁剪,
//如果不想设置的话,需要在关闭包围盒;
//irr::scene::ISceneNode::setAutomaticCulling(irr::scene::EAC_OFF);
Box.reset(Vertices[0].Pos);
for (s32 i = 1; i < 4; i++)
Box.addInternalPoint(Vertices[i].Pos);
}
//注册场景节点,
virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//重载渲染函数
virtual void render()
{
u16 indices[] = { 0, 2, 3, 2, 1, 3, 1, 0, 3, 2, 0, 1 };
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(Material);//启用当前材质
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->drawVertexPrimitiveList(&Vertices[0], 4, &indices[0], 4, video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
}
//添加一些额外的方法
virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}
virtual u32 getMaterialCount() const
{
return 1;
}
virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}
};
int main()
{
IrrlichtDevice *device = createDevice(video::EDT_OPENGL,
core::dimension2d<u32>(720, 455), 16, false, false, false, 0);
if (!device)
return 1;
device->setWindowCaption(L"CustomSceneNode ");
video::IVideoDriver *driver = device->getVideoDriver();
scene::ISceneManager *smgr = device->getSceneManager();
CSampleSceneNode *myNode = new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
scene::ISceneNodeAnimator* anim =
smgr->createRotationAnimator(core::vector3df(0.8f, 0.5f, 0.1f));
if (anim)
{
myNode->addAnimator(anim);
anim->drop();
anim = 0;
}
myNode->drop();
myNode = 0;
smgr->addCameraSceneNode(0, core::vector3df(0, -40, 0), core::vector3df(0, 0, 0));
u32 frames = 0;
while (device->run())
{
driver->beginScene(true, true, video::SColor(0, 100, 100, 100));
smgr->drawAll();
driver->endScene();
if (++frames == 100)
{
core::stringw str = L"CustomeSceneNode [";
str += driver->getName();
str += L"] FPS: ";
str += (s32)driver->getFPS();
device->setWindowCaption(str.c_str());
frames = 0;
}
}
device->drop();
return 0;
}

本文介绍如何在Irrlicht引擎中创建定制场景节点以扩展其功能,包括编写定制节点类、设置材质与包围盒、注册节点及添加动画等步骤。

2514

被折叠的 条评论
为什么被折叠?



