bool PickEntity(Ogre::RaySceneQuery* mRaySceneQuery, Ogre::Ray &ray, Ogre::Entity **result, Ogre::uint32 mask ,Ogre::Vector3 &hitpoint, bool excludeInVisible,const Ogre::String& excludeobject, Ogre::Real max_distance)
{
mRaySceneQuery->setRay(ray);
mRaySceneQuery->setQueryMask(mask);
mRaySceneQuery->setQueryTypeMask(Ogre::SceneManager::ENTITY_TYPE_MASK);
mRaySceneQuery->setSortByDistance(true);
if (mRaySceneQuery->execute().size() <= 0) return (false);
// at this point we have raycast to a series of different objects bounding boxes.
// we need to test these different objects to see which is the first polygon hit.
// there are some minor optimizations (distance based) that mean we wont have to
// check all of the objects most of the time, but the worst case scenario is that
// we need to test every triangle of every object.
Ogre::Real closest_distance = max_distance;
Ogre::Vector3 closest_result;
Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults();
for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
{
// stop checking if we have found a raycast hit that is closer
// than all remaining entities
if ((closest_distance >= 0.0f) && (closest_distance < query_result[qr_idx].distance))
{
break;
}
// only check this result if its a hit against an entity
if ((query_result[qr_idx].movable != NULL) && (query_result[qr_idx].movable->getMovableType().compare("Entity") == 0))
{
// get the entity to check
Ogre::Entity *pentity = static_cast<Ogre::Entity*>(query_result[qr_idx].movable);
if(excludeInVisible)
if (!pentity->getVisible())
continue;
if(pentity->getName() == excludeobject)
continue;
// mesh data to retrieve
size_t vertex_count;
size_t index_count;
Ogre::Vector3 *vertices;
unsigned long *indices;
// get the mesh information
GetMeshInformationEx(pentity->getMesh(), vertex_count, vertices, index_count, indices,
pentity->getParentNode()->_getDerivedPosition(),
pentity->getParentNode()->_getDerivedOrientation(),
pentity->getParentNode()->_getDerivedScale());
//maybe there is a bug in GetMeshInformationEx(),when mesh is a line or a circle, the vertex_count is not multiple of 3
// if (index_count%3 != 0)
// {
// index_count-=index_count%3;
// }
// test for hitting individual triangles on the mesh
bool new_closest_found = false;
for (int i = 0; i < static_cast<int>(index_count); i += 3)
{
// check for a hit against this triangle
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]],
vertices[indices[i+1]], vertices[indices[i+2]], true, true);
// if it was a hit check if its the closest
if (hit.first)
{
if ((closest_distance < 0.0f) || (hit.second < closest_distance))
{
// this is the closest so far, save it off
closest_distance = hit.second;
new_closest_found = true;
}
}
}
// free the verticies and indicies memory
delete[] vertices;
delete[] indices;
// if we found a new closest raycast for this object, update the
// closest_result before moving on to the next object.
if (new_closest_found)
{
closest_result = ray.getPoint(closest_distance);
(*result) = pentity;
}
}
}
// return the result
if (closest_distance != max_distance)
{
hitpoint = closest_result;
return true;
}
else
{
// raycast failed
return false;
}
}
void GetMeshInformationEx(const Ogre::MeshPtr mesh,
size_t &vertex_count,
Ogre::Vector3* &vertices,
size_t &index_count,
unsigned long* &indices,
const Ogre::Vector3 &position,
const Ogre::Quaternion &orient,
const Ogre::Vector3 &scale)
{
bool added_shared = false;
size_t current_offset = 0;
size_t shared_offset = 0;
size_t next_offset = 0;
size_t index_offset = 0;
vertex_count = index_count = 0;
// Calculate how many vertices and indices we're going to need
for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
{
Ogre::SubMesh* submesh = mesh->getSubMesh( i );
// We only need to add the shared vertices once
if(submesh->useSharedVertices)
{
if( !added_shared )
{
vertex_count += mesh->sharedVertexData->vertexCount;
added_shared = true;
}
}
else
{
vertex_count += submesh->vertexData->vertexCount;
}
// Add the indices
index_count += submesh->indexData->indexCount;
}
// Allocate space for the vertices and indices
vertices = new Ogre::Vector3[vertex_count];
indices = new unsigned long[index_count];
added_shared = false;
// Run through the submeshes again, adding the data into the arrays
for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
{
Ogre::SubMesh* submesh = mesh->getSubMesh(i);
Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
{
if(submesh->useSharedVertices)
{
added_shared = true;
shared_offset = current_offset;
}
const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
// as second argument. So make it float, to avoid trouble when Ogre::Real will
// be comiled/typedefed as double:
// Ogre::Real* pReal;
float* pReal;
for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
{
posElem->baseVertexPointerToElement(vertex, &pReal);
Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);
vertices[current_offset + j] = (orient * (pt * scale)) + position;
}
vbuf->unlock();
next_offset += vertex_data->vertexCount;
}
Ogre::IndexData* index_data = submesh->indexData;
size_t numTris = index_data->indexCount / 3;
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;
if ( use32bitindexes )
{
for ( size_t k = 0; k < numTris*3; ++k)
{
indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset);
}
}
else
{
for ( size_t k = 0; k < numTris*3; ++k)
{
indices[index_offset++] = static_cast<unsigned long>(pShort[k]) + static_cast<unsigned long>(offset);
}
}
ibuf->unlock();
current_offset = next_offset;
}
}
使用时用如下代码即可(可能需要根据实际情况有所改动):
Entity* rayResult=NULL;
Vector3 hitPoint;
CEGUI::Point mousePos= CEGUI::MouseCursor::getSingleton().getPosition();
Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(e.state.width),mousePos.d_y/float(e.state.height));
RaySceneQuery* rayQuery=mSceneMgr->createRayQuery(Ray());
if (PickEntity(rayQuery,mouseRay,&rayResult,QF_moveable_object,hitPoint,true))
rayResult->getParentSceneNode(); //find a entity
以上源码参考Ogitor,为了配合自己的程序,稍有改动。
为了方便大家,所以贴出来,建议大家直接看Ogitor源码。
//暂时放着,代码没有测试过!
gre碰撞检测,精确到物体网格三角面
我们课程的期末项目是做一个蚊子吸血的三维游戏。由于蚊子的体积很小,并且蚊子需要在三维场景中穿梭飞行。因此常规的模型包围盒检测便显得有些不足。例如,场景中有一个台灯,从模型的包围盒看,台灯是一个长方体,如果按照这样来做碰撞检测,那么蚊子便无法从台灯的长长的弧形躯干形成的拱桥洞中飞过去,尽管看起来蚊子确实没有撞到台灯。这在现实中是让人无法接受的。
我曾经尝试了几种方法,一种是用从蚊子出发的指向各个方向的几条射线来检测碰撞,另一种是用一个球体包围蚊子,然后检测球体中的物体个数来检测碰撞。但最终都失败了,其本质的原因还是因为,这些碰撞只能检测到和模型包围盒的交点。
看来,必须要寻找更好的解决方案。
很幸运,我找到一个第三方的开源库,叫做 Minimal Ogre Collision 。可以在http://www.ogre3d.org/wiki/index.php/Minimal_Ogre_Collision上找到它。
我决定把其中最核心的一段代码挑出来,详细解读。
//ray,求交射线;result,与模型面片的交点;target,相交物体;closest_distance,距离最近交点的距离;queryMask,碰撞检测掩码
bool CollisionTools::raycast(const Ogre::Ray &ray, Ogre::Vector3 &result,Ogre::MovableObject* &target,float &closest_distance, const Ogre::uint32 queryMask)
{
target = NULL;
// 测试射线是否有效
if (mRaySceneQuery != NULL)
{
// 创建一个射线查询
mRaySceneQuery->setRay(ray);
mRaySceneQuery->setSortByDistance(true);//查询结果按距离排序
mRaySceneQuery->setQueryMask(queryMask);//设置掩码
// 执行查询
if (mRaySceneQuery->execute().size() <= 0)
{
return (false);
}
}
else
{
//LOG_ERROR << "Cannot raycast without RaySceneQuery instance" << ENDLOG;
return (false);
}
// 注意哦,到这里我们已经得到一系列按照包围盒检测到的模型了.
// 我们要找到第一个相交的物体.
// 这就意味着我们不必去检测后面的物体了,这样大大节省了时间
// 但是很遗憾,我们不得不遍历每一个物体的三角面,听起来是多么痛苦,必须得忍
//
//初始化最小距离为-1
closest_distance = -1.0f;
Ogre::Vector3 closest_result;
Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults();//取回刚才查询的结果,因为之前并没有保存
for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
{
// 如果下一个碰撞物体比这个还远,当然要无视啦
if ((closest_distance >= 0.0f) &&
(closest_distance < query_result[qr_idx].distance))
{
break;
}
// 我们只关心碰撞的东西是个物体
if ((query_result[qr_idx].movable != NULL) &&
(query_result[qr_idx].movable->getMovableType().compare("Entity") == 0))
{
// 取得被碰撞的物体
Ogre::MovableObject *pentity = static_cast<Ogre::MovableObject*>(query_result[qr_idx].movable);
// 顶点是顶点,索引是索引,不着急,往下看
size_t vertex_count;
size_t index_count;
Ogre::Vector3 *vertices;
Ogre::uint32 *indices;
// 下面的函数得到模型的详细信息
GetMeshInformation(((Ogre::Entity*)pentity)->getMesh(), vertex_count, vertices, index_count, indices,
pentity->getParentNode()->_getDerivedPosition(),
pentity->getParentNode()->_getDerivedOrientation(),
pentity->getParentNode()->_getDerivedScale());
// 再次注意了,下面求每一个三角面的交点,同样记录最近点
bool new_closest_found = false;
for (size_t i = 0; i < index_count; i += 3)
{
// 下面的函数求一条射线与三角面的交点,返回一个pair,《是否相交,距离交点距离》
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]],
vertices[indices[i+1]], vertices[indices[i+2]], true, false);//知道索引干嘛用的了吧,索引乃顶点之索引也
// 如果碰撞,检查是否是当前最小距离
if (hit.first)
{
if ((closest_distance < 0.0f) ||
(hit.second < closest_distance))
{
// 如果是则更新
closest_distance = hit.second;
new_closest_found = true;
}
}
}
// 释放刚才申请的内存,这种东西当然是在写申请的时候就要成对编写的了,正如同时写下{}
delete[] vertices;
delete[] indices;
//如果找到新的点,不要忘了更新相应信息
if (new_closest_found)
{
target = pentity;
closest_result = ray.getPoint(closest_distance);//最近点的计算,简单的线性方程
}
}
}
// 返回结果
if (closest_distance >= 0.0f)
{
// 成功了
result = closest_result;
return (true);
}
else
{
//失败了
return (false);
}
{
mRaySceneQuery->setRay(ray);
mRaySceneQuery->setQueryMask(mask);
mRaySceneQuery->setQueryTypeMask(Ogre::SceneManager::ENTITY_TYPE_MASK);
mRaySceneQuery->setSortByDistance(true);
if (mRaySceneQuery->execute().size() <= 0) return (false);
// at this point we have raycast to a series of different objects bounding boxes.
// we need to test these different objects to see which is the first polygon hit.
// there are some minor optimizations (distance based) that mean we wont have to
// check all of the objects most of the time, but the worst case scenario is that
// we need to test every triangle of every object.
Ogre::Real closest_distance = max_distance;
Ogre::Vector3 closest_result;
Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults();
for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
{
// stop checking if we have found a raycast hit that is closer
// than all remaining entities
if ((closest_distance >= 0.0f) && (closest_distance < query_result[qr_idx].distance))
{
break;
}
// only check this result if its a hit against an entity
if ((query_result[qr_idx].movable != NULL) && (query_result[qr_idx].movable->getMovableType().compare("Entity") == 0))
{
// get the entity to check
Ogre::Entity *pentity = static_cast<Ogre::Entity*>(query_result[qr_idx].movable);
if(excludeInVisible)
if (!pentity->getVisible())
continue;
if(pentity->getName() == excludeobject)
continue;
// mesh data to retrieve
size_t vertex_count;
size_t index_count;
Ogre::Vector3 *vertices;
unsigned long *indices;
// get the mesh information
GetMeshInformationEx(pentity->getMesh(), vertex_count, vertices, index_count, indices,
pentity->getParentNode()->_getDerivedPosition(),
pentity->getParentNode()->_getDerivedOrientation(),
pentity->getParentNode()->_getDerivedScale());
//maybe there is a bug in GetMeshInformationEx(),when mesh is a line or a circle, the vertex_count is not multiple of 3
// if (index_count%3 != 0)
// {
// index_count-=index_count%3;
// }
// test for hitting individual triangles on the mesh
bool new_closest_found = false;
for (int i = 0; i < static_cast<int>(index_count); i += 3)
{
// check for a hit against this triangle
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]],
vertices[indices[i+1]], vertices[indices[i+2]], true, true);
// if it was a hit check if its the closest
if (hit.first)
{
if ((closest_distance < 0.0f) || (hit.second < closest_distance))
{
// this is the closest so far, save it off
closest_distance = hit.second;
new_closest_found = true;
}
}
}
// free the verticies and indicies memory
delete[] vertices;
delete[] indices;
// if we found a new closest raycast for this object, update the
// closest_result before moving on to the next object.
if (new_closest_found)
{
closest_result = ray.getPoint(closest_distance);
(*result) = pentity;
}
}
}
// return the result
if (closest_distance != max_distance)
{
hitpoint = closest_result;
return true;
}
else
{
// raycast failed
return false;
}
}
void GetMeshInformationEx(const Ogre::MeshPtr mesh,
size_t &vertex_count,
Ogre::Vector3* &vertices,
size_t &index_count,
unsigned long* &indices,
const Ogre::Vector3 &position,
const Ogre::Quaternion &orient,
const Ogre::Vector3 &scale)
{
bool added_shared = false;
size_t current_offset = 0;
size_t shared_offset = 0;
size_t next_offset = 0;
size_t index_offset = 0;
vertex_count = index_count = 0;
// Calculate how many vertices and indices we're going to need
for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
{
Ogre::SubMesh* submesh = mesh->getSubMesh( i );
// We only need to add the shared vertices once
if(submesh->useSharedVertices)
{
if( !added_shared )
{
vertex_count += mesh->sharedVertexData->vertexCount;
added_shared = true;
}
}
else
{
vertex_count += submesh->vertexData->vertexCount;
}
// Add the indices
index_count += submesh->indexData->indexCount;
}
// Allocate space for the vertices and indices
vertices = new Ogre::Vector3[vertex_count];
indices = new unsigned long[index_count];
added_shared = false;
// Run through the submeshes again, adding the data into the arrays
for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
{
Ogre::SubMesh* submesh = mesh->getSubMesh(i);
Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
{
if(submesh->useSharedVertices)
{
added_shared = true;
shared_offset = current_offset;
}
const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
// as second argument. So make it float, to avoid trouble when Ogre::Real will
// be comiled/typedefed as double:
// Ogre::Real* pReal;
float* pReal;
for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
{
posElem->baseVertexPointerToElement(vertex, &pReal);
Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);
vertices[current_offset + j] = (orient * (pt * scale)) + position;
}
vbuf->unlock();
next_offset += vertex_data->vertexCount;
}
Ogre::IndexData* index_data = submesh->indexData;
size_t numTris = index_data->indexCount / 3;
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;
if ( use32bitindexes )
{
for ( size_t k = 0; k < numTris*3; ++k)
{
indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset);
}
}
else
{
for ( size_t k = 0; k < numTris*3; ++k)
{
indices[index_offset++] = static_cast<unsigned long>(pShort[k]) + static_cast<unsigned long>(offset);
}
}
ibuf->unlock();
current_offset = next_offset;
}
}
使用时用如下代码即可(可能需要根据实际情况有所改动):
Entity* rayResult=NULL;
Vector3 hitPoint;
CEGUI::Point mousePos= CEGUI::MouseCursor::getSingleton().getPosition();
Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(e.state.width),mousePos.d_y/float(e.state.height));
RaySceneQuery* rayQuery=mSceneMgr->createRayQuery(Ray());
if (PickEntity(rayQuery,mouseRay,&rayResult,QF_moveable_object,hitPoint,true))
rayResult->getParentSceneNode(); //find a entity
以上源码参考Ogitor,为了配合自己的程序,稍有改动。
为了方便大家,所以贴出来,建议大家直接看Ogitor源码。
//暂时放着,代码没有测试过!
gre碰撞检测,精确到物体网格三角面
我们课程的期末项目是做一个蚊子吸血的三维游戏。由于蚊子的体积很小,并且蚊子需要在三维场景中穿梭飞行。因此常规的模型包围盒检测便显得有些不足。例如,场景中有一个台灯,从模型的包围盒看,台灯是一个长方体,如果按照这样来做碰撞检测,那么蚊子便无法从台灯的长长的弧形躯干形成的拱桥洞中飞过去,尽管看起来蚊子确实没有撞到台灯。这在现实中是让人无法接受的。
我曾经尝试了几种方法,一种是用从蚊子出发的指向各个方向的几条射线来检测碰撞,另一种是用一个球体包围蚊子,然后检测球体中的物体个数来检测碰撞。但最终都失败了,其本质的原因还是因为,这些碰撞只能检测到和模型包围盒的交点。
看来,必须要寻找更好的解决方案。
很幸运,我找到一个第三方的开源库,叫做 Minimal Ogre Collision 。可以在http://www.ogre3d.org/wiki/index.php/Minimal_Ogre_Collision上找到它。
我决定把其中最核心的一段代码挑出来,详细解读。
//ray,求交射线;result,与模型面片的交点;target,相交物体;closest_distance,距离最近交点的距离;queryMask,碰撞检测掩码
bool CollisionTools::raycast(const Ogre::Ray &ray, Ogre::Vector3 &result,Ogre::MovableObject* &target,float &closest_distance, const Ogre::uint32 queryMask)
{
target = NULL;
// 测试射线是否有效
if (mRaySceneQuery != NULL)
{
// 创建一个射线查询
mRaySceneQuery->setRay(ray);
mRaySceneQuery->setSortByDistance(true);//查询结果按距离排序
mRaySceneQuery->setQueryMask(queryMask);//设置掩码
// 执行查询
if (mRaySceneQuery->execute().size() <= 0)
{
return (false);
}
}
else
{
//LOG_ERROR << "Cannot raycast without RaySceneQuery instance" << ENDLOG;
return (false);
}
// 注意哦,到这里我们已经得到一系列按照包围盒检测到的模型了.
// 我们要找到第一个相交的物体.
// 这就意味着我们不必去检测后面的物体了,这样大大节省了时间
// 但是很遗憾,我们不得不遍历每一个物体的三角面,听起来是多么痛苦,必须得忍
//
//初始化最小距离为-1
closest_distance = -1.0f;
Ogre::Vector3 closest_result;
Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults();//取回刚才查询的结果,因为之前并没有保存
for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
{
// 如果下一个碰撞物体比这个还远,当然要无视啦
if ((closest_distance >= 0.0f) &&
(closest_distance < query_result[qr_idx].distance))
{
break;
}
// 我们只关心碰撞的东西是个物体
if ((query_result[qr_idx].movable != NULL) &&
(query_result[qr_idx].movable->getMovableType().compare("Entity") == 0))
{
// 取得被碰撞的物体
Ogre::MovableObject *pentity = static_cast<Ogre::MovableObject*>(query_result[qr_idx].movable);
// 顶点是顶点,索引是索引,不着急,往下看
size_t vertex_count;
size_t index_count;
Ogre::Vector3 *vertices;
Ogre::uint32 *indices;
// 下面的函数得到模型的详细信息
GetMeshInformation(((Ogre::Entity*)pentity)->getMesh(), vertex_count, vertices, index_count, indices,
pentity->getParentNode()->_getDerivedPosition(),
pentity->getParentNode()->_getDerivedOrientation(),
pentity->getParentNode()->_getDerivedScale());
// 再次注意了,下面求每一个三角面的交点,同样记录最近点
bool new_closest_found = false;
for (size_t i = 0; i < index_count; i += 3)
{
// 下面的函数求一条射线与三角面的交点,返回一个pair,《是否相交,距离交点距离》
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]],
vertices[indices[i+1]], vertices[indices[i+2]], true, false);//知道索引干嘛用的了吧,索引乃顶点之索引也
// 如果碰撞,检查是否是当前最小距离
if (hit.first)
{
if ((closest_distance < 0.0f) ||
(hit.second < closest_distance))
{
// 如果是则更新
closest_distance = hit.second;
new_closest_found = true;
}
}
}
// 释放刚才申请的内存,这种东西当然是在写申请的时候就要成对编写的了,正如同时写下{}
delete[] vertices;
delete[] indices;
//如果找到新的点,不要忘了更新相应信息
if (new_closest_found)
{
target = pentity;
closest_result = ray.getPoint(closest_distance);//最近点的计算,简单的线性方程
}
}
}
// 返回结果
if (closest_distance >= 0.0f)
{
// 成功了
result = closest_result;
return (true);
}
else
{
//失败了
return (false);
}
}