您需要有 opengl 投影和模型视图矩阵。将它们相乘以获得模型视图投影矩阵。反转此矩阵以获得将剪辑空间坐标转换为世界坐标的矩阵。变换您的触摸点,使其与剪辑坐标相对应:屏幕的中心应为零,而 X 和 Y 的边缘应分别为 +1/-1。
构造两个点,一个在 (0,0,0) 和一个在 (touch_x,touch_y,-1) 并通过逆模型视图投影矩阵变换两者。
做透视除法的倒数。
您应该得到两个点来描述从相机中心到“远距离”(远平面)的线。
根据模型的简化边界框进行挑选。您应该能够在网上找到大量的光线/框相交算法。
另一种解决方案是将每个模型以稍微不同的颜色绘制到屏幕外缓冲区中,并从那里读取触摸点的颜色,告诉你哪个 brich 被触摸了。
这是我为一个使用子弹物理的小项目编写的光标的来源:
float x=((float)mpos.x/screensize.x)*2.0f -1.0f;
float y=((float)mpos.y/screensize.y)*-2.0f +1.0f;
p2=renderer->camera.unProject(vec4(x,y,1.0f,1));
p2/=p2.w;
vec4 pos=activecam.GetView().col_t;
p1=pos+(((vec3)p2 - (vec3)pos) / 2048.0f * 0.1f);
p1.w=1.0f;
btCollisionWorld::ClosestRayResultCallback rayCallback(btVector3(p1.x,p1.y,p1.z),btVector3(p2.x,p2.y,p2.z));
game.dynamicsWorld->rayTest(btVector3(p1.x,p1.y,p1.z),btVector3(p2.x,p2.y,p2.z), rayCallback);
if (rayCallback.hasHit())
{
btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject);
if(body==game.worldBody)
{
renderer->setHighlight(0);
}
else if (body)
{
Entity* ent=(Entity*)body->getUserPointer();
if(ent)
{
renderer->setHighlight(dynamic_cast<ModelEntity*>(ent));
//cerr<<"hit ";
//cerr<<ent->getName()<<endl;
}
}
}