假设我画了一个带有点A(0,0,a)B(1,0,b)C(1,1,c)和D(0,1,d)的四边形并且想要找出坐标P(0.6,0.25,p),我该怎么做呢?我希望有更少的处理器重,我错过了,因为到目前为止,我一直在尝试取得Ax和Bx的差异,然后是Cx和Dx,然后找到它们之间的区别,它有点混乱。 / p>
例如,假设我想找到鼠标在此图片中的位置:
是否有一种更容易或更少处理器的重要方法来找到重点? (没有采摘或光线投射,因为鼠标不会在那里,鼠标只是指向我希望它发生的地方,例如)
答案 0 :(得分:0)
仅供参考:使用光线投射应该足以满足您的需求。您需要旋转支点的透视图,以从模型位置的绝对值0和绝对值1进行聚焦。如果您想要另一种快速检查方式,重心坐标也很有用。
使用重心坐标可以确定三角形内的点:
function pointInTriangle(x1, y1, x2, y2, x3, y3, x, y:Number):Boolean
{
var denominator:Number = ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3));
var a:Number = ((y2 - y3)*(x - x3) + (x3 - x2)*(y - y3)) / denominator;
var b:Number = ((y3 - y1)*(x - x3) + (x1 - x3)*(y - y3)) / denominator;
var c:Number = 1 - a - b;
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
}
重心坐标允许将新的p坐标表示为p1,p2,p3的线性组合。更准确地说,它定义了3个标量a,b,c:
x = a * x1 + b * x2 + c * x3 y = a * y1 + b * y2 + c * y3 a + b + c = 1
计算a,b,c的方法如下:
a =((y2 - y3)(x - x3)+(x3 - x2)(y - y3))/((y2 - y3)(x1 - x3) + (x3 - x2)(y1 - y3))b =((y3 - y1)(x - x3)+(x1 - x3)(y - y3))/ ((y2 - y3)(x1 - x3)+(x3 - x2)(y1 - y3))c = 1 - a - b
p在T内,当且仅当0 <= a <= 1且0 <= b <= 1且0 <= c <= 1
参考http://totologic.blogspot.fr/2014/01/accurate-point-in-triangle-test.html
答案 1 :(得分:0)
这不是最漂亮的阅读,但这里有几个你想要做的样本。一个可下载的项目可能对你更有用,但不确定我是否可以在这里发布所有这些。
(这是基本的射线 - 三角交叉点)
应注意使用OpenGL(这是下面的c ++代码) 您希望在OpenGL之外复制的代码的关键部分(如果未使用glaux.lib):
gluUnProject( PosX, PosY, 0, modelview, projection, viewport, &x1, &x2, &x3);
vnear.x = (float)x1; vnear.y = (float)x2; vnear.z = (float)x3;
gluUnProject( PosX, PosY, 1.0, modelview, projection, viewport, &x1, &x2, &x3);
vfar.x = (float)x1; vfar.y = (float)x2; vfar.z = (float)x3;
应该创建一个基本的碰撞类:
class CCollision
{
public:
CVec vnear; // Where is 0 and where is 100% of fulcrum
CVec vfar;
public:
CCollision(void);
~CCollision(void);
public:
bool checkLine (CVec &v1, CVec &v2,CVec &v3, CVec &p );
bool checkLine( float *triangle, CVec &p );
bool checkLine( float* v1, float* v2, float* v3, CVec &p );
void projectRay ( int x, int y );
};
定义如下:
CCollision::CCollision(void){}
CCollision::~CCollision(void){}
bool CCollision::checkLine( float *triangle, CVec &p )
{
CVec p1 = CVec( triangle[0], triangle[1], triangle[2] );
CVec p2 = CVec( triangle[3], triangle[4], triangle[5] );
CVec p3 = CVec( triangle[6], triangle[7], triangle[8] );
return checkLine( p1, p2, p3, p );
}
bool CCollision::checkLine( float *v1, float *v2, float *v3, CVec &p )
{
CVec p1 = CVec( v1[0], v1[1], v1[2] );
CVec p2 = CVec( v2[0], v2[1], v2[2] );
CVec p3 = CVec( v3[0], v3[1], v3[2] );
return checkLine( p1, p2, p3, p );
}
bool CCollision::checkLine( CVec &v1, CVec &v2, CVec &v3, CVec &p )
{
CVec sect;
// Find Triangle Normal, then normalize it (use Magnitude)
CVec Normal;
Normal = ( v2 - v1 )%( v3 - v1 );
Normal.Normalize(); // Normalize
// Find the distance to the plane, based on the Normal.
float distanceNear = (vnear-v1)^Normal;
float distanceFar = (vfar-v1)^Normal;
if (( (distanceNear * distanceFar) >= 0.0f)||( distanceNear == distanceFar))
return false; // Are they equal?
// Find exact intersection point.
sect = vnear + (vfar-vnear) * ( -distanceNear/(distanceFar-distanceNear) );
// Check all points against the Normalized vector.
CVec v;
// Point 1
v = Normal%( v2-v1 );
if ( (v^( sect-v1 )) < 0.0f )
return false;
// Point 2
v = Normal%( v3-v2 );
if ( (v^( sect-v2 )) < 0.0f )
return false;
// Point 3
v = Normal%( v1-v3 );
if ( (v^( sect-v1 )) < 0.0f )
return false;
// Lastly, lets set the intersection point.
p = sect;
return true;
}
void CCollision::projectRay( int x, int y )
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLdouble PosX, PosY, x1, x2, x3;
glGetDoublev(GL_MODELVIEW_MATRIX, modelview );
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
PosX = (float)x;
PosY = (float)viewport[3] - (float)y;
gluUnProject( PosX, PosY, 0, modelview, projection, viewport, &x1, &x2, &x3);
vnear.x = (float)x1; vnear.y = (float)x2; vnear.z = (float)x3;
gluUnProject( PosX, PosY, 1.0, modelview, projection, viewport, &x1, &x2, &x3);
vfar.x = (float)x1; vfar.y = (float)x2; vfar.z = (float)x3;
}
使用上述代码的方法是捕获输入并指定所需的数据:
case WM_LBUTTONDOWN:
project->scene->bCheckForCollision = true;
project->scene->collision.projectRay(
LOWORD(((LPARAM *)m.LParam.ToPointer())),
HIWORD((LPARAM *)m.LParam.ToPointer())
); } 那将是使用鼠标点击作为捕获,尽管我们希望在所有现实中从透视矩阵进行。
上面的代码来自我在2005年写过的工作地形生成器。
或者,另一种方法是运行我先前提供的inTriangle代码,然后检测三角形每一边的斜率。这需要滚动所有点。
更好的方法是创建一个像我们上面描述的那样的透视矩阵。有关您需要做什么的直观示例:
旋转相机直接向下看播放器
(c)中-----&GT;玩家[(地形)
现在,使用我最初发布的相同概念,您可以通过从透视图创建近/远矢量来识别交叉点。这永远不需要绘制,但是你正在将射线投射到确切的位置。