有人可以链接一篇好的文章/教程/任何内容,或者甚至可以解释如何正确从鼠标坐标投射光线以选择3D中的对象?
我已经有Ray和交叉点工作,现在我只需要通过鼠标点击创建光线。
我只想拥有一些我知道其实应该工作的东西,这就是为什么我在这里问专业人士,而不是我不确定它是否在一开始就是正确的。
我有一个光线类,如果我将原点和方向设置为与相机相同,它实际上可以工作并检测交叉点,所以当我移动相机时它实际上选择了正确的东西。
现在我想用鼠标实际进行3D拾取,而不是相机移动
我已经阅读了很多关于这个,2个教程的问题,特别是那些不同的数学内容,因为我真的不擅长它。
但这对我没什么帮助,因为那里的人经常使用一些" unproject"功能,似乎实际上已被弃用,我不知道如何使用,也无法访问。
现在我将光线原点设置到相机位置,然后尝试从this tutorial中的计算中获取光线的方向。
它有效有点,这意味着当相机指向物体并且沿着整个y轴有时时选择有效,我不知道发生了什么
如果有人想立即查看我的代码:
public Ray2(Camera cam, float mouseX, float mouseY) {
origin = cam.getEye();
float height = 600;
float width = 600;
float aspect = (float) width / (float) height;
float x = (2.0f * mouseX) / width - 1.0f;
float y = 1.0f - (2.0f * mouseX) / height;
float z = 1.0f;
Vector ray_nds = vecmath.vector(x, y, z);
Vector4f clip = new Vector4f(ray_nds.x(), ray_nds.y(), -1.0f, 1.0f);
Matrix proj = vecmath.perspectiveMatrix(60f, aspect, 0.1f, 100f);
proj = proj.invertRigid();
float tempX = proj.get(0, 0) * clip.x + proj.get(1, 0) * clip.y
+ proj.get(2, 0) * clip.z + proj.get(3, 0) * clip.w;
float tempY = proj.get(0, 1) * clip.x + proj.get(1, 1) * clip.y
+ proj.get(2, 1) * clip.z + proj.get(3, 1) * clip.w;
float tempZ = proj.get(0, 2) * clip.x + proj.get(1, 2) * clip.y
+ proj.get(2, 2) * clip.z + proj.get(3, 2) * clip.w;
float tempW = proj.get(0, 3) * clip.x + proj.get(1, 3) * clip.y
+ proj.get(2, 3) * clip.z + proj.get(3, 3) * clip.w;
Vector4f ray_eye = new Vector4f(tempX, tempY, tempZ, tempW);
ray_eye = new Vector4f(ray_eye.x, ray_eye.y, -1.0f, 0.0f);
Matrix view = cam.getTransformation();
view = view.invertRigid();
tempX = view.get(0, 0) * ray_eye.x + view.get(1, 0) * ray_eye.y
+ view.get(2, 0) * ray_eye.z + view.get(3, 0) * ray_eye.w;
tempY = view.get(0, 1) * ray_eye.x + view.get(1, 1) * ray_eye.y
+ view.get(2, 1) * ray_eye.z + view.get(3, 1) * ray_eye.w;
tempZ = view.get(0, 2) * ray_eye.x + view.get(1, 2) * ray_eye.y
+ view.get(2, 2) * ray_eye.z + view.get(3, 2) * ray_eye.w;
tempW = view.get(0, 3) * ray_eye.x + view.get(1, 3) * ray_eye.y
+ view.get(2, 3) * ray_eye.z + view.get(3, 3) * ray_eye.w;
Vector ray_wor = vecmath.vector(tempX, tempY, tempZ);
// don't forget to normalise the vector at some point
ray_wor = ray_wor.normalize();
direction = ray_wor;
}
答案 0 :(得分:1)
首先,unproject()方法是可行的方法。它根本没有被弃用。例如,你可以在GLM math library中找到它。这是我基于Ray的3D拾取的实现:
// let's check if this renderable's AABB is clicked:
const glm::ivec2& mCoords = _inputManager->GetMouseCoords();
int mouseY = _viewportHeight - mCoords.y;
//unproject twice to build a ray from near to far plane"
glm::vec3 v0 = glm::unProject(glm::vec3(float(mCoords.x), float(mouseY), 0.0f),_camera->Transform().GetView(),_camera->Transform().GetProjection(), _viewport);
glm::vec3 v1 = glm::unProject(glm::vec3(float(mCoords.x), float(mouseY), 1.0f),_camera->Transform().GetView(),_camera->Transform().GetProjection(), _viewport);
glm::vec3 dir = (v1 - v0);
Ray r(_camera->Transform().GetPosition(),dir);
float ishit ;
//construct AABB:
glm::mat4 aabbMatr = glm::translate(glm::mat4(1.0),renderable->Transform().GetPosition());
aabbMatr = glm::scale(aabbMatr,renderable->Transform().GetScale());
//transforms AABB vertices(need it if the origianl bbox is not axis aligned as in this case)
renderable->GetBoundBox()->RecalcVertices(aabbMatr);
//this method makes typical Ray-AABB intersection test:
if(r.CheckIntersectAABB(*renderable->GetBoundBox().get(),&ishit)){
printf("HIT!\n");
}
但是我建议你也看看color based 3d picking像素完美,更容易实现。