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

七、OSG学习笔记-碰撞检测

前一章节:

六、OSG学习笔记-漫游(操作器)-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_36323170/article/details/145515189?spm=1001.2014.3001.5502

主要用来判断空间里两个物体的交点

场景显示原理:

场景中物体是否发生交点,需要遍历 node 节点,如下图:

一、实现简单的碰撞检测

代码:OsgStudy/Hits · CuiQingCheng/OsgStudy - 码云 - 开源中国

代码如下:

#include<windows.h>
#include<iostream>

#include<osgViewer/Viewer>
#include<osgDB/ReadFile>

#include<osg/Geode>
#include<osg/Geometry>
#include<osg/ShapeDrawable>

#include<osgUtil/IntersectionVisitor>
#include<osgUtil/LineSegmentIntersector>

// 画线
osg::ref_ptr<osg::Geode> CreateLine(const osg::Vec3& start, const osg::Vec3& end)
{
	osg::ref_ptr<osg::Geode> gNode = new osg::Geode;
	osg::ref_ptr<osg::Geometry> gy = new osg::Geometry;
	osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array; // 存放点集

	gNode->addDrawable(gy.get());
	gy->setVertexArray(coords);
	coords->push_back(start);
	coords->push_back(end);
	gy->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, 2));

	return gNode;
}

// 画圆
osg::ref_ptr<osg::Geode> CreateSphere(const osg::Vec3 &center)
{
	osg::ref_ptr<osg::Geode> gNode = new osg::Geode;
	gNode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(center, 0.2)));
	return gNode;
}

// 画盒子
osg::ref_ptr<osg::Geode>  CreateBox()
{
	osg::ref_ptr<osg::Geode> gnode = new osg::Geode;
	gnode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 10.0, 10.0, 10.0)));// 这里中心点为 (0,0,0)
	//gnode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 0.1, 0.1, 20.0)));// 这里中心点为 (0,0,0)
	return gnode;
}


int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(100, 100, 1500, 1000);
	osg::ref_ptr<osg::Group> group = new osg::Group;
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("glider.osg");
	osg::Vec3 start = osg::Vec3(-10, 7, 15);
	osg::Vec3 end = osg::Vec3(5, -4, -12);


	osgUtil::LineSegmentIntersector::Intersections intersections;
	// 用于定义线段相交检测器。
	osg::ref_ptr<osgUtil::LineSegmentIntersector> lineIv = new osgUtil::LineSegmentIntersector(start, end);
	// 用于遍历场景图并执行相交检测。
	osg::ref_ptr<osgUtil::IntersectionVisitor> iv = new osgUtil::IntersectionVisitor(lineIv);

	group->addChild(node.get());
	group->addChild(CreateBox());
	group->accept(*iv.get());
	group->addChild(CreateLine(start, end));

	// 如果有碰撞,则输出所有交点
	if (lineIv->containsIntersections())
	{
		intersections = lineIv->getIntersections();
		for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersections.begin(); iter != intersections.end(); ++iter)
		{
			std::cout << (iter)->getWorldIntersectPoint().x() << " " << (iter)->getWorldIntersectPoint().y() << " " << (iter)->getWorldIntersectPoint().z()<< std::endl;
			group->addChild(CreateSphere((iter)->getWorldIntersectPoint()));
		}
	}

	viewer->setSceneData(group.get());
	return viewer->run();
}

代码执行效果:

二、上楼梯算法(碰撞检测应用)

上楼梯:

示例代码:

OsgStudy/TravelPlus · CuiQingCheng/OsgStudy - 码云 - 开源中国

Travel.h

#pragma once
#include<windows.h>
#include<iostream>

#include<osg/Node>
#include<osgViewer/Viewer>
#include<osgViewer/ViewerEventHandlers>
#include<osgDB/ReadFile>
#include<osgGA/TrackballManipulator>

// 图元库
#include<osg/Geode>
#include<osg/ShapeDrawable>

#include<osg/Matrix>
#include<osg/MatrixTransform>
#include<osg/PositionAttitudeTransform>

// 回调
#include<osg/AnimationPath>

#include<osgGA/GUIEventAdapter>
#include <osgGA/StandardManipulator>
// 自定义操作器类

#include "../NodeMatrix/NodeMatrix.h"

// 导入静态库
#ifdef _DEBUG
#pragma comment (lib, "../x64/Debug/NodeMatrix.lib")
#else
#pragma comment (lib, "../x64/Release/NodeMatrix.lib")
#endif // DEBUG

class TravelManipulator : public osgGA::CameraManipulator
{
public:
	TravelManipulator();
	~TravelManipulator(); 

public:
	// 实现得到和设置矩阵的接口
	/** 设置当前视口 using a 4x4 Matrix.*/
	void setByMatrix(const osg::Matrixd& matrix) override;

	/** 设置当前视口 using a 4x4 Matrix.*/
	void setByInverseMatrix(const osg::Matrixd& matrix) override;

	/** 得到当前矩阵 4x4 Matrix.*/
	osg::Matrixd getMatrix() const override;

	/** 得到当前逆矩阵 used as a model view matrix.*/
	osg::Matrixd getInverseMatrix() const override;

	// 响应事件
	bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us )override;

	// 设置步长
	void setStep(int iStep);

	// 获得步长
	int getStep() const;

	// 设置到某一点
	void setPosition(osg::Vec3d pos);

	// 得到当前坐标
	osg::Vec3d getPosition();

	// 设置进行碰撞检测节点
	void setNode(osg::Node* node);

	void setAuto(bool bauto);

private:
	// 改变位置
	void ChangePosition(const osg::Vec3d& delta);

private:
	// 进行碰撞检测节点
	osg::Node* m_node{NULL};
	// 当前物体
	NodeMatrix* m_nCurrentNode{ NULL };

	// 视点
	osg::Vec3d m_vPosition;

	// 朝向
	osg::Vec3 m_vRotation;

	// 移动步长
	int m_vStep;

	// 旋转步长
	float m_vRotateStep;

	// 记录坐标
	int m_iLeftX;
	int m_iLeftY;

	// 鼠标左键是否按下
	bool m_bLeftDown{ false };

	bool m_bAuto{ false };
};

Travel.cpp

#include "Travel.h"
#include <osgGA/GUIEventAdapter>

#include<osgUtil/IntersectionVisitor>
#include<osgUtil/LineSegmentIntersector>

TravelManipulator::TravelManipulator(  )
{
	m_vPosition = osg::Vec3(0, 0, 10);

	// 围绕X轴转转90度
	m_vRotation = osg::Vec3(osg::PI_2, 0, 0);
	m_vStep = 2;
	m_vRotateStep = 0.0;
}

TravelManipulator::~TravelManipulator()
{
}

void TravelManipulator::setByMatrix(const osg::Matrixd& matrix)
{
}

void TravelManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{
}

osg::Matrixd TravelManipulator::getMatrix() const
{
	osg::Matrixd mat;
	mat.makeTranslate(m_vPosition);
	osg::Matrixd retMat = osg::Matrixd::rotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1],  osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS) * mat;
	return retMat;
}

osg::Matrixd TravelManipulator::getInverseMatrix() const
{
	osg::Matrixd mat;
	mat.makeTranslate(m_vPosition);
	osg::Matrixd retMat = osg::Matrixd::rotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS) * mat;
	return osg::Matrixd::inverse(retMat);
}

bool TravelManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
{
	osgViewer::Viewer* view = dynamic_cast<osgViewer::Viewer*>(&us);
	if (view)
	{
		m_node = view->getSceneData();
	}
	switch (ea.getEventType())
	{
	case osgGA::GUIEventAdapter::KEYDOWN:
	{
		if ((ea.getKey() == 'w') || (ea.getKey() == 'W') || (ea.getKey() == osgGA::GUIEventAdapter::KEY_Up))
		{
			osg::Vec3d delta = osg::Vec3d(m_vStep * cosf(osg::PI_2 + m_vRotation._v[2]), m_vStep * sinf(osg::PI_2 + m_vRotation._v[2]), 0);
			ChangePosition(delta);
			return true;
		}
		else if ((ea.getKey() == 's') || (ea.getKey() == 'S') || (ea.getKey() == osgGA::GUIEventAdapter::KEY_Down))
		{
			osg::Vec3d delta = osg::Vec3d(-m_vStep * cosf(osg::PI_2 + m_vRotation._v[2]), -m_vStep * sinf(osg::PI_2 + m_vRotation._v[2]), 0);
			ChangePosition(delta);
			return true;
		}
		else if ((ea.getKey() == 'a') || (ea.getKey() == 'A'))
		{
			osg::Vec3d delta = osg::Vec3d(m_vStep * sinf(osg::PI_2 + m_vRotation._v[2]), m_vStep * cosf(osg::PI_2 + m_vRotation._v[2]), 0);
			ChangePosition(delta);
			return true;
		}
		else if ((ea.getKey() == 'd') || (ea.getKey() == 'D'))
		{
			osg::Vec3d delta = osg::Vec3d(-m_vStep * sinf(osg::PI_2 + m_vRotation._v[2]), -m_vStep * cosf(osg::PI_2 + m_vRotation._v[2]), 0);
			ChangePosition(delta);
			return true;
		}
		else if (ea.getKey() ==  osgGA::GUIEventAdapter::KEY_Left)
		{
			m_vRotation[2] += 0.2;
			return true;
		}
		else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
		{
			m_vRotation[2] -= 0.2;
			return true;
		}
		else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Home)
		{
			m_vPosition += osg::Vec3d(0, 0, m_vStep);
			//ChangePosition(osg::Vec3d(0, 0, m_vStep));
			return true;
		}
		else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_End)
		{
			m_vPosition += osg::Vec3d(0, 0, -m_vStep);
			//ChangePosition(osg::Vec3d(0, 0, -m_vStep));
			return true;
		}
	}
		break;
	case osgGA::GUIEventAdapter::PUSH: // 鼠标按下
	{
		if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
		{
			m_iLeftX = ea.getX();
			m_iLeftY = ea.getY();
			m_bLeftDown = true;
		}
		return false;
	}
		break;
	case osgGA::GUIEventAdapter::DRAG: // 鼠标拖动
	{
		if (m_bLeftDown)
		{
			int delX = ea.getX() - m_iLeftX;
			m_iLeftX = ea.getX();
			double dx = osg::DegreesToRadians(0.01 * delX);
			m_vRotation[2] += dx;
			int delY = ea.getY() - m_iLeftY;
			m_iLeftY = ea.getY();
			m_vRotation[0] -= osg::DegreesToRadians(0.012 * delY);
			if (m_vRotation[0] > osg::PI)
			{
				m_vRotation[0] = osg::PI;
			}
			else if (m_vRotation[0] < 0)
			{
				m_vRotation[0] = 0;
			}
		}
	}
		break;
	case osgGA::GUIEventAdapter::RELEASE: // 鼠标释放
	{
		if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
		{
			m_bLeftDown = false;
		}
	}
		break;
	default:
		break;
	}
	return false;
}

void TravelManipulator::setStep(int iStep)
{
	m_vStep = iStep;
}

int TravelManipulator::getStep() const
{
	return m_vStep;
}

void TravelManipulator::setPosition(osg::Vec3d pos)
{
	m_vPosition = pos;
}

osg::Vec3d TravelManipulator::getPosition()
{
	return m_vPosition;
}

void TravelManipulator::setNode(osg::Node* node)
{
	if (!m_bAuto)
	{
		m_node = node;
	}
}

void TravelManipulator::setAuto(bool bauto)
{
	m_bAuto = bauto;
}

void TravelManipulator::ChangePosition(const osg::Vec3d& delta)
{
	// 源点m_vPosition与目的点 new pos;
	osg::Vec3d newPos = m_vPosition + delta;
	osg::Vec3d start = osg::Vec3d(newPos.x(), newPos.y(), newPos.z() + 2);// z轴高度设置为移动后高度1米
	osg::Vec3d end = osg::Vec3d(newPos.x(), newPos.y(), newPos.z() - 1000);

	osg::Vec3d start1 = osg::Vec3d(m_vPosition.x(), m_vPosition.y(), m_vPosition.z() + 2);
	osg::Vec3d end1 = osg::Vec3d(newPos.x(), newPos.y(), newPos.z() + 2);
	osg::ref_ptr<osgUtil::IntersectionVisitor> iv = new osgUtil::IntersectionVisitor;
	// 竖直直线
	osg::ref_ptr<osgUtil::LineSegmentIntersector> ls = new osgUtil::LineSegmentIntersector(start, end);
	// 水平直线
	osg::ref_ptr<osgUtil::LineSegmentIntersector> ls2 = new osgUtil::LineSegmentIntersector(start1, end1);
	// 直线组
	osg::ref_ptr<osgUtil::IntersectorGroup> lg = new osgUtil::IntersectorGroup;

	lg->addIntersector(ls.get());
	lg->addIntersector(ls2.get());

	// 存放交点集合
	osgUtil::LineSegmentIntersector::Intersections intersections;

	iv->setIntersector(lg.get());
	m_node->accept(*(iv.get()));
	long height = 0;
	
	if (ls->containsIntersections() && (!ls2->containsIntersections()))
	{ // 存在交点
		//取出交点
		intersections = ls->getIntersections();
		osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersections.begin();
		height = iter->getWorldIntersectPoint().z();
		// 遍历找到最高点
		for (; iter != intersections.end(); ++iter)
		{
			if (height < iter->getWorldIntersectPoint().z())
			{
				height = iter->getWorldIntersectPoint().z();
			}
		}
	}
	else {
		//不许走
		return;
	}
	m_vPosition += delta;
	m_vPosition.set(osg::Vec3d(m_vPosition.x(), m_vPosition.y(), height+1));

	if (NULL != m_nCurrentNode)
	{
		m_nCurrentNode->toPosition(m_vPosition);
	}

}

main.cpp

#include "Travel.h"

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	// 获取WindowingSystemInterface实例
	osg::ref_ptr<osg::GraphicsContext::WindowingSystemInterface> wsi = osg::GraphicsContext::getWindowingSystemInterface();
	if (!wsi)
	{
		std::cerr << "无法获取窗口系统接口。" << std::endl;
		return 1;
	}
	// 获取主显示器的屏幕设置
	unsigned int screenNum = 0; // 主显示器的屏幕编号通常为0
	osg::GraphicsContext::ScreenSettings settings;
	wsi->getScreenSettings(screenNum, settings);
	// 获取屏幕的宽度和高度
	unsigned int width = settings.width;
	unsigned int height = settings.height;
	viewer->setUpViewInWindow(0, 0, width, height);

	viewer->addEventHandler(new osgViewer::WindowSizeHandler);

	osg::ref_ptr<NodeMatrix> nm = new NodeMatrix;
	nm->addsChild(osgDB::readNodeFile("ceep.ive"));
	
	viewer->setSceneData(nm.get());

	// 加入操作器
	osgGA::CameraManipulator* pCameraPlator = new TravelManipulator();
	viewer->setCameraManipulator(pCameraPlator);
	return viewer->run();
}


http://www.kler.cn/a/540920.html

相关文章:

  • elasticsearch安装插件analysis-ik分词器(深度研究docker内elasticsearch安装插件的位置)
  • 基于html2canvas实现将dom导出为图片,实现截屏效果
  • 《ARM64体系结构编程与实践》学习笔记(四)
  • 利用 Python 爬虫获取按关键字搜索淘宝商品的完整指南
  • CSGHub高效管理|解锁DeepSeek R1蒸馏模型 :高效推理的新选择
  • 视频采集卡接口
  • 顺丰java面试题_顺丰java开发面试分享,顺丰java面试经面试题
  • HAL库外设宝典:基于CubeMX的STM32开发手册(持续更新)
  • Spring Boot 中的日志配置
  • Java从入门到精通 第三版 读书笔记
  • 11. k8s二进制集群之容器运行时
  • 基于布谷鸟算法实现率定系数的starter
  • SPI通信及设备驱动
  • TCP长连接、HTTP短轮询、HTTP长轮询、HTTP长连接、WebSocket的区别
  • Wpf美化按钮,输入框,下拉框,dataGrid
  • 【AI学习】LLM的发展方向
  • Qt:Qt Creator项目创建
  • CEF132 编译指南 MacOS 篇 - 基础开发工具安装实战 (二)
  • 游戏引擎学习第93天
  • 【Java】多线程和高并发编程(三):锁(下)深入ReentrantReadWriteLock
  • C++ decltype 规则推导
  • 能够复刻人类意识并实现永生的虚拟生态系统
  • (一)Axure制作移动端登录页面
  • pgsql最快的数据导入BeginBinaryImport
  • P3413 SAC#1 - 萌数
  • 中国城商行信贷业务数仓建设白皮书(第五期:智能决策体系构建)