这不会是最漂亮的读物,但这里有几个您想要做的示例。一个可下载的项目可能对你更有用,但我不确定我是否可以在这里发布所有这些内容。
(这是基本的射线-三角形相交)
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)-----> 玩家[(地形)
现在,使用我最初发布的相同概念,您可以通过从视角创建近/远矢量来识别相交点。这永远不需要绘制,但您正在将光线投射到确切的点。