Irrlicht学习笔记(7.2)--Collision

说明

接着上一个例子,
创建一个布告板用于显示拾取位置
加入拾取功能

实现:可以拾取地图的三角形,
加入三个模型,被拾取后模型高亮

1布告板

布告板通常用于爆炸,火焰等特效
此处初始化一个默认的布告板,然后设置它的属性:

初始化
创建
只需要:
scene::IBillboardSceneNode* bill = smgr->addBillboardSceneNode();//可以设置参数,这里使用默认值
设置属性:
材质属性,材质,灯光,关闭z缓存(显示在上方),ID

使用:
只需要设置位置:
bill->setPosition(pos);


2加入三个模型

模型是带动画的

先声明一个动画网格场景节点,
用于初始化三个模型
scene::IAnimatedMeshSceneNode* node=0;
举一个例子
//加载模型:faerie.md2
node = smgr->addAnimatedMeshSceneNode(
smgr->getMesh("../media/faerie.md2"),0,IDFlag_IsPickable|IDFlag_IsHighlightable);
设置属性
node->setPositoin(core::vector3df(-70,-15,-120));
node->setMD2Animation(scene::EMAT_POINT);
设置材质
video::SMaterial material;
material.setTexture(0,driver->getTexture("../media/faerie2.bmp"));
material.Lighting=true;
node->getMaterial(0)= material;
为当前节点添加三角形选择器
selector=smgr->createTriangleSelector(node);
node->setTriangleSelector(selector);


3使用

要求:
在鼠标拾取到模型后,模型高亮,
拾取到任何三角形,三角形将绘制轮廓

设置灯光,用于通用照明
scene::ILightSceneNode* light =smgr->addLightSceneNode(0,core::vector3df(-60,100,400),
    video::SColor(1,1,1,1),600);

声明一个节点,用于保存高亮节点
scene::ISceneNode* highlightSceneNode =0;
获得


程序

#include <iostream>
#include <irrlicht.h>

using namespace irr;


#ifdef _IRR_WINDOWS_
#pragma comment(lib, "irrlicht.lib")
//#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

enum
{
	//这个IsceneNode ID致命这个场景节点不能被getSceneNodeAndCollisionPointFromRay()拾取
	ID_IsNotPickable = 0,
	//这个标记表面能被拾取
	IDFlag_IsPickable = 1 << 0,
	//这个标记表面节点被拾取后高亮显示,
	//这个例子中地图不能高亮,而角色能高亮
	IDFlag_IsHighlightable = 1 << 1
};
int main(int argc, char** argv)
{
	IrrlichtDevice *device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(720, 455), 32, false, true, false, 0);

	if (!device)
		return 1;
	device->setWindowCaption(L"quake3 map");

	video::IVideoDriver *driver = device->getVideoDriver();
	scene::ISceneManager *smgr = device->getSceneManager();
	gui::IGUIEnvironment *guiev = device->getGUIEnvironment();


	//为了显示quake3 map,我们要加载它,而其被压缩在map-20kdm2.pk3中,
	//所以先将压缩包加载到文件系统
	//实际调用device->getFileArchive(filename,true,true,EFAT_ZIP);
	device->getFileSystem()->addZipFileArchive("../media/map-20kdm2.pk3");

	//将地图当作一帧动画加载
	scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp");
	scene::IMeshSceneNode* q3node = 0;//与例子2不一样,eg2是ISceneNode

	if (q3levelmesh)
	{
		q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0), 0, IDFlag_IsPickable);
		//node = smgr->addMeshSceneNode(mesh->getMesh(0));
	}


	scene::ITriangleSelector* selector = 0;
	//通过irr::scene::ISceneNode 层的方法对node进行属性调整
	//位置:irr::scene::ISceneNodeirr::scene::ISceneNode::setPosition()
	//旋转:irr::scene::ISceneNode::setRotation()
	//缩放:irr::scene::ISceneNode::setScale();
	if (q3node)
	{
		q3node->setPosition(core::vector3df(-1350, -130, -1400));
		//	node->setRotation(core::vector3df(0, 0, 0));
		//	node->setScale(core::vector3df(1, 1, 1));
		selector = smgr->createOctreeTriangleSelector(
			q3node->getMesh(), q3node, 128);
		q3node->setTriangleSelector(selector);
	}

	SKeyMap keyMap[5];
	keyMap[0].Action = EKA_MOVE_FORWARD;
	keyMap[0].KeyCode = KEY_KEY_W;
	keyMap[1].Action = EKA_MOVE_BACKWARD;
	keyMap[1].KeyCode = KEY_KEY_S;
	keyMap[2].Action = EKA_STRAFE_LEFT;
	keyMap[2].KeyCode = KEY_KEY_A;
	keyMap[3].Action = EKA_STRAFE_RIGHT;
	keyMap[3].KeyCode = KEY_KEY_D;
	keyMap[4].Action = EKA_JUMP_UP;
	keyMap[4].KeyCode = KEY_SPACE;
	//camera = sceneManager->addCameraSceneNodeFPS(0, 100, 500, -1, keyMap, 8);
	scene::ICameraSceneNode* camera =
		smgr->addCameraSceneNodeFPS(
		0, 100, .3, ID_IsNotPickable, keyMap, 5, true, 3.0);
	camera->setTarget(core::vector3df(-70, 30, -60));

	if (selector)
	{
		scene::ISceneNodeAnimator* anim =
			smgr->createCollisionResponseAnimator(
			selector, camera, core::vector3df(30, 50, 30),
			core::vector3df(0, -10, 0), core::vector3df(0, 30, 0));
		selector->drop();
		camera->addAnimator(anim);
		anim->drop();
	}


	//万事俱备,只需要添加一台摄像机,
	//maya型的摄像机:irr::scene::ISceneManager::addCameraSceneNodeMaya()
	//FPS:irr::scene::ISceneManager::addCameraSceneNodeFPS()
	//smgr->addCameraSceneNodeFPS();

	//隐藏鼠标:irr::IrrlichtDevice::ICursorControl
	device->getCursorControl()->setVisible(false);

	scene::IBillboardSceneNode* bill = smgr->addBillboardSceneNode();
	bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
	bill->setMaterialTexture(0, driver->getTexture("../media/particle.bmp"));
	bill->setMaterialFlag(video::EMF_LIGHTING, false);
	bill->setMaterialFlag(video::EMF_ZBUFFER, false);
	bill->setSize(core::dimension2d<f32>(20, 20));
	bill->setID(ID_IsNotPickable);

	scene::IAnimatedMeshSceneNode* node = 0;
	node = smgr->addAnimatedMeshSceneNode(
		smgr->getMesh("../media/faerie.md2"),
		0, IDFlag_IsPickable | IDFlag_IsHighlightable);
	node->setPosition(core::vector3df(-70, -15, -120));
	node->setScale(core::vector3df(2, 2, 2));
	node->setMD2Animation(scene::EMAT_POINT);
	node->setAnimationSpeed(20.0);
	video::SMaterial material;
	material.setTexture(0, driver->getTexture("../media/faerie2.bmp"));
	material.Lighting = true;
	node->getMaterial(0) = material;

	selector = smgr->createTriangleSelector(node);
	node->setTriangleSelector(selector);
	selector->drop();

	node = smgr->addAnimatedMeshSceneNode(
		smgr->getMesh("../media/dwarf.x"),
		0, IDFlag_IsPickable | IDFlag_IsHighlightable);
	node->setPosition(core::vector3df(-70, -66, 0));
	node->setRotation(core::vector3df(0, -90, 0));
	node->setAnimationSpeed(20.0f);
	selector = smgr->createTriangleSelector(node);
	node->setTriangleSelector(selector);
	selector->drop();

	node = smgr->addAnimatedMeshSceneNode(
		smgr->getMesh("../media/ninja.b3d"),
		0, IDFlag_IsPickable | IDFlag_IsHighlightable);
	node->setScale(core::vector3df(10, 10, 10));
	node->setPosition(core::vector3df(-70, -66, -60));
	node->setRotation(core::vector3df(0, 90, 0));
	node->setAnimationSpeed(10);
	node->getMaterial(0).NormalizeNormals = true;

	selector = smgr->createTriangleSelector(node);
	node->setTriangleSelector(selector);
	selector->drop();

	material.setTexture(0, 0);
	material.Lighting = false;

	//通用照明灯光
	scene::ILightSceneNode* light = smgr->addLightSceneNode(0, core::vector3df(-60, 100, 400),
		video::SColorf(1.0, 1.0, 1.0, 1.0), 600);
	light->setID(ID_IsNotPickable);

	scene::ISceneNode* highlightSceneNode = 0;
	scene::ISceneCollisionManager* collMan = smgr->getSceneCollisionManager();

	material.Wireframe = true;

	int lastFPS = -1;
	while (device->run())
	{
		if (device->isWindowActive())
		{
			driver->beginScene(true, true, video::SColor(255, 100, 101, 140));

			smgr->drawAll();
			guiev->drawAll();

			//将高亮节点重置
			if (highlightSceneNode)
			{
				highlightSceneNode->setMaterialFlag(video::EMF_LIGHTING, true);
				highlightSceneNode = 0;
			}

			//设置射线:摄像机到视线外1000距离处
			//可以创建一个从鼠标点击处产生的射线:
			//ISceneCollisionManager::getRayFromScreenCoordinates()
			core::line3d<f32> ray;
			ray.start = camera->getPosition();
			ray.end = ray.start + (camera->getTarget() - ray.start).normalize()*1000.0f;
			
			core::vector3df intersection;//跟踪当前交点
			core::triangle3df hitTriangle;//显示拾取到的三角形用

			//通过这个函数获得被拾取的节点,
			//同时获取焦交点,被拾取的三角形
			scene::ISceneNode* selectedSceneNode =
				collMan->getSceneNodeAndCollisionPointFromRay(
				ray,//
				intersection,
				hitTriangle,
				IDFlag_IsPickable,//id,
				0);//从这个节点开始遍历,


			if (selectedSceneNode)
			{
				bill->setPosition(intersection);


				//在绘制执行自己的绘制程序前,重置变换矩阵
				driver->setTransform(video::ETS_WORLD, core::matrix4());
				driver->setMaterial(material);
				driver->draw3DTriangle(hitTriangle, video::SColor(0, 255, 0, 0));//绘制出被击中的三角形

				//处理能被高亮的节点
				if ((selectedSceneNode->getID()&IDFlag_IsHighlightable) == IDFlag_IsHighlightable)
				{
					highlightSceneNode = selectedSceneNode;
					highlightSceneNode->setMaterialFlag(video::EMF_LIGHTING, false);//事实上就是关闭其光照属性,
				}
			}
			driver->endScene();

			int fps = driver->getFPS();
			if (lastFPS != fps)
			{
				core::stringw str = L"quake3 map [";
				str += driver->getName();
				str += "]FPS.",
					str += fps;
				device->setWindowCaption(str.c_str());
				lastFPS = fps;
			}
		}
		else
			//闲置,一直渲染占用过多cpu资源
			device->yield();
	}
	device->drop();

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值