快速光线和多边形相交
Fast Ray and Polygon Intersection
我正在编写我自己的小游戏,它应该有这里描述的可见性效果。我的世界由多边形组成,每个多边形都有一个边列表(按CW排序(。我现在想要(如文章中所述(将光线投射到多边形的边缘,找到交点并检索定义可见区域的多边形。
因此,我为Vectors、Points、Edges和Polygons编写了一个类,并调整了交集算法,使其能够与我的代码一起使用。
然后我测试了它,一切都很好,但当我在for循环中运行交集算法来模拟处理的大量边缘(从100开始,直到1000(时,fps急剧下降,100个边缘"仅"300fps(之前是3000(,我认为300个边缘下降到60以下。这对我来说似乎是一个很大的下降,因为我想在我的Lightsource中重用这段代码,然后我想我会很快想出处理300多个Edges的方法,它应该在功能较弱的处理器上快速运行(我得到了一个xeon e1230v3(。
我发现,只调用EdgeIntersection程序运行速度会快很多倍,但我肯定需要循环通过多边形中的边,所以这是不可能的。
我的源代码:
Vector.h/.cpp:具有两个浮点(X,Y(、getters&旋转设置器
Vertex.h/.cpp:具有位置向量的基点类,getters&setters和一个布尔值,用于指示它是否为交集顶点
Edge.h/.cpp具有起始/结束顶点、getters&setters和旋转函数(使用Vector.rerotate(((
多边形.h:
#pragma once
#include <vector>
#include "Edge.h"
namespace geo
{
class Polygon
{
private:
std::vector<Edge> edges;
public:
Polygon();
Polygon(std::vector<Edge> edges);
~Polygon();
std::vector<Edge> getEdges();
Edge getEdge(int index);
int getEdgeCount();
void setEdges(std::vector<Edge> edges);
void setEdge(Edge e, int index);
void addEdge(Edge e);
void removeEdge(int index);
};
}
Ray.h:
#pragma once
#include "Vertex.h"
class Ray
{
private:
geo::Vertex origin;
geo::Vector dir;
public:
Ray();
Ray(geo::Vertex origin, geo::Vector dir);
~Ray();
geo::Vertex getOrigin();
geo::Vector getDirection();
void setOrigin(geo::Vertex origin);
void setDirection(geo::Vector dir);
};
LightModule.h:
#pragma once
#include "Polygon.h"
#include "Ray.h"
class LightModule
{
private:
//List of blocking Polygons
std::vector<geo::Polygon>* blockingPolygons;
std::vector<Ray> rays;
geo::Polygon bounds;
geo::Polygon visible;
/*geo::Polygon blocked;*/
//HitDetection Class later
geo::Vertex getIntersection(Ray r, geo::Edge* e);
geo::Vertex getClosestIntersection(Ray r, geo::Polygon *p);
public:
LightModule();
LightModule(std::vector<geo::Polygon>* blockingPolygons);
~LightModule();
//Set the Blocking Polygons
void setBlockingPolygons(std::vector<geo::Polygon>* blockingPolygons);
geo::Vertex callCI(Ray r, geo::Polygon* p);
geo::Vertex callI(Ray r, geo::Edge* e);
//Cast Rays towards Vertecies and store them in rays
void updateRays();
//Update Visibility Polygon
void updateVisible();
//Return Visibility Polygon
geo::Polygon* getVisible();
};
LightMModule.cpp:
#include "LightModule.h"
LightModule::LightModule()
{
rays.clear();
}
LightModule::LightModule(std::vector<geo::Polygon>* blockingPolygons)
{
this->blockingPolygons = blockingPolygons;
rays.clear();
}
LightModule::~LightModule()
{
}
void LightModule::setBlockingPolygons(std::vector<geo::Polygon>* blockingPolygons)
{
this->blockingPolygons = blockingPolygons;
}
//Test-cast a Ray (will follow mouse in the Test)
void LightModule::updateRays()
{
Ray r(geo::Vertex(geo::Vector(200, 100)), geo::Vector(-100, 0));
rays.push_back(r);
}
void LightModule::updateVisible()
{
}
//Both for Testing will later be part of a seperate class
geo::Vertex LightModule::callCI(Ray r, geo::Polygon *p)
{
return this->getClosestIntersection(r, p);
}
geo::Vertex LightModule::callI(Ray r, geo::Edge* e)
{
return this->getIntersection(r, e);
}
//TEST
geo::Vertex LightModule::getIntersection(Ray r, geo::Edge* e)
{
geo::Vertex v;
v.setIntersectVert(false);
float r_px = r.getOrigin().getPosition().getX();
float r_py = r.getOrigin().getPosition().getY();
float r_dx = r.getDirection().getX();
float r_dy = r.getDirection().getY();
float s_px = e->getOrigin().getPosition().getX();
float s_py = e->getOrigin().getPosition().getY();
float s_dx = e->getDirection().getX();
float s_dy = e->getDirection().getY();
float r_mag = sqrt(r_dx*r_dx + r_dy*r_dy);
float s_mag = sqrt(s_dx*s_dx + s_dy*s_dy);
if (r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag)
{
return v;
}
float T2 = (r_dx*(s_py - r_py) + r_dy*(r_px - s_px)) / (s_dx*r_dy - s_dy*r_dx);
float T1 = (s_px + s_dx*T2 - r_px) / r_dx;
if (T1 < 0 /*|| T1 > 1 For Lines*/)
{
return v;
}
if (T2 < 0 || T2 > 1)
{
return v;
}
v.setIntersectVert(true);
v.setPosition(geo::Vector(r_px + r_dx*T1, r_py + r_dy*T1));
return v;
}
geo::Vertex LightModule::getClosestIntersection(Ray r, geo::Polygon *p)
{
geo::Vertex v;
v.setIntersectVert(false);
geo::Vertex v_nearest(geo::Vector(0, 0));
v_nearest.setIntersectVert(false);
geo::Vector h1;
geo::Vector h2;
for (int i = 0; i < p->getEdges().size(); i++)
{
v = this->getIntersection(r, &p->getEdges().at(i));
h1.setX(v.getPosition().getX() - r.getOrigin().getPosition().getX());
h1.setY(v.getPosition().getY() - r.getOrigin().getPosition().getY());
h2.setX(v_nearest.getPosition().getX() - r.getOrigin().getPosition().getX());
h2.setY(v_nearest.getPosition().getY() - r.getOrigin().getPosition().getY());
if (i < 1)
v_nearest = v;
else if (v.isIntersectVert() == true && h1.getLength() < h2.getLength())
{
v_nearest = v;
}
}
return v_nearest;
}
对于测试,我创建了一个多边形一个LightModule,并调用updateRays,然后调用辅助函数callCI((。我知道当我必须级联我的getter和setter时,我的代码会变得非常混乱,我必须解决这个问题,但对于其他人来说,我希望一切都可以理解,如果不能随意询问的话。刚刚提到的是,我用顶点阵列测试绘制我的对象,但我不需要相交过程的图形输出,我只需要可见的多边形。
再次指出:我需要一种更快的方法来找到射线和多边形之间的交点,因为我不知道我的代码中是否做错了什么,所以我把它都发布在这里,这样有人可能会帮助我提高代码的效率,或者向我展示一种不同的方法来解决我的问题。
祝你今天愉快,谢谢你的回答:(Paul
编辑:首先对多边形进行三角测量,然后进行射线三角相交测试,会有意义地更快吗?
我不能谈论算法(这可能是你所需要的(,但我会立即思考如何加快你的速度。
首先,您可以定义所有您的getter和setterinline
(将它们放在头中的类中,而不是单独的源文件中(,这样编译器就可以优化函数调用。
然后这些变化可能会为你购买一些帧:
// make sure your getters and setters are inline so the compiler
// can optimize them away
geo::Vertex LightModule::getClosestIntersection(Ray r, geo::Polygon* p)
{
geo::Vertex v;
v.setIntersectVert(false);
geo::Vector h1;
geo::Vector h2;
// cache these
Vector ray_position = r.getOrigin().getPosition();
geo::Vertex v_nearest(geo::Vector(0, 0));
v_nearest.setIntersectVert(false);
// cache size (don't dereference each time)
size_t size = p->getEdges().size();
// avoid acces violation
if(!size)
return v_nearest;
// preset item 0
v_nearest = this->getIntersection(r, &p->getEdges()[0]);
// start from 1 not 0
for(int i = 1; i < size; i++)
{
// don't use at() its slower
// v = this->getIntersection(r, &p->getEdges().at(i));
v = this->getIntersection(r, &p->getEdges()[i]);
// used cached ray position rather than call functions
h1.setX(v.getPosition().getX() - ray_position.getX());
h1.setY(v.getPosition().getY() - ray_position.getY());
h2.setX(v_nearest.getPosition().getX() - ray_position.getX());
h2.setY(v_nearest.getPosition().getY() - ray_position.getY());
// this if not needed because presetting item 0
//if(i < 1)
// v_nearest = v;
if(v.isIntersectVert() == true && h1.getLength() < h2.getLength())
{
v_nearest = v;
}
}
return v_nearest;
}
我通过在循环之前计算0项并从1开始循环,删除了其中一个if
语句,其余的只是缓存一个常用的值,并避免at()
,因为它进行绑定检查,所以速度较慢。
- 计算缩放多边形的比例,得到给定的多边形面积
- 将QGraphicsItem的移动区域限制在多边形区域内
- 重新排列单线以形成闭合多边形?
- 提升几何体:C++并集多个多边形
- 在 QT C++中绘制/操作多边形
- Maya API C++:从多边形获取材质
- 添加带有提升的多边形::p奥利贡不编译?
- 使用 C++在 OpenGL 中对 3D 多边形进行纹理处理
- 使用 C++在 OpenGL 中移动自动旋转的 3D 多边形
- 如何使用增强::几何计算多边形的旋转固体体积?
- 从拉伸多边形构建多面体
- 使用提升几何缓冲区缩放多边形时的冗余折点
- cgal多边形网格中的tet网格密度分级
- 如何绘制具有随机顶点数量的多边形并旋转它们
- 多边形裁剪 - 一点点详细说明
- 使用裁剪器库在线和多边形之间相交
- 平移 CGAL 多边形,而无需循环穿过折点
- 无法正确改变窗口中多边形的形状
- 在多边形内查找增强 rtree 元素
- 将当前多边形数据单元与下一个多边形单元格 - VTK 进行比较