这是非常类似的东西等轴接口,用于iPad的项目我的工作。这与您的项目具有相同的屏幕分辨率。当我第一次看到你的问题时,我几天前正在构建其他项目代码。但是需要构建拾取对象的接口代码。所以尝试开发代码是有意义的。我使用空白彩色棋盘安装了一个测试来适应你的问题。
这是一个快速的视频演示。请原谅它的丑陋外观。另请注意关于视频,游标后面的值是整数,但代码产生浮点值。还有另一个功能是我为了自己的使用而做的额外工作。如果这是你想要的东西,我会把它包含在我的答案中。
http://youtu.be/JyddfSf57ic
此代码是故意冗长,因为我在数学生锈。所以我花了很多时间在最近几天重新学习点和跨产品,也读重心代码,但决定反对它。
代码之前的最后一件事:问题中的投影矩阵存在问题。您在投影矩阵中包含相机变换。从技术上讲,这是允许的,但网上有很多资源表明这是不好的做法。
希望这会有所帮助!
void calculateTouchPointOnGrid(CGPoint screenTouch) {
float backingWidth = 1024;
float backingHeight = 768;
float aspect = backingWidth/backingHeight;
float zNear = 0;
float zFar = 20;
glm::detail::tvec3<float> unprojectedNearZ;
glm::detail::tvec3<float> unprojectedFarZ;
/*
Window coordinates, including zNear
This code uses zNear and zFar as two arbitrary values of
magnitude along the direction (vector) of the camera's
view (affected by projection and model-view matrices) that enable
determining the line/ray, originating from screenTouch (or
mouse click, etc) that later intersects the plane.
*/
glm::vec3 win = glm::vec3(screenTouch.x, backingHeight - screenTouch.y, zNear);
// Model & View matrix
glm::detail::tmat4x4<float> modelTransformMatrix = glm::detail::tmat4x4<float>(1);
modelTransformMatrix = glm::translate(modelTransformMatrix, glm::detail::tvec3<float>(0,0,-1));
modelTransformMatrix = glm::rotate(modelTransformMatrix, 0.f, glm::detail::tvec3<float>(0,1,0));
modelTransformMatrix = glm::scale(modelTransformMatrix, glm::detail::tvec3<float>(1,1,1));
glm::detail::tmat4x4<float> modelViewMatrix = lookAtMat * modelTransformMatrix;
/*
Projection
*/
const glm::detail::tmat4x4<float> projectionMatrix =
glm::ortho<float>(-aspect*5, aspect*5, -5, 5, 0, 20);
/*
Viewport
*/
const glm::vec4 viewport = glm::vec4(0, 0, backingWidth, backingHeight);
/*
Calculate two points on a line/ray based on the window coordinate (including arbitrary Z value), plus modelViewMatrix, projection matrix and viewport
*/
unprojectedNearZ = glm::unProject(win,
modelViewMatrix,
projectionMatrix,
viewport);
win[2] = zFar;
unprojectedFarZ = glm::unProject(win,
modelViewMatrix,
projectionMatrix,
viewport);
/*
Define the start of the ray
*/
glm::vec3 rayStart(unprojectedNearZ[0], unprojectedNearZ[1], unprojectedNearZ[2]);
/*
Determine the vector traveling parallel to the camera from the two
unprojected points
*/
float lookatVectX = unprojectedFarZ[0] - unprojectedNearZ[0];
float lookatVectY = unprojectedFarZ[1] - unprojectedNearZ[1];
float lookatVectZ = unprojectedFarZ[2] - unprojectedNearZ[2];
glm::vec3 dir(lookatVectX, lookatVectY, lookatVectZ);
/*
Define three points on the plane that will define a triangle.
Winding order does not matter.
*/
glm::vec3 p0(0,0,0);
glm::vec3 p1(1,0,0);
glm::vec3 p2(0,0,1);
/*
And finally the destination of the calculations
*/
glm::vec3 linePlaneIntersect;
if (cartesianLineIntersectPlane(rayStart, dir, p0, p1, p2, linePlaneIntersect)) {
// do work here using the linePlaneIntersect values
}
}
bool cartesianLineIntersectPlane(glm::vec3 rayStart, glm::vec3 dir,
glm::vec3 p0, glm::vec3 p1, glm::vec3 p2, glm::vec3 &linePlaneIntersect) {
/*
Create edge vectors to form the plane normal
*/
glm::vec3 edge1 = p1 - p0;
glm::vec3 edge2 = p2 - p0;
/*
Check if the ray direction is parallel to plane, before continuing
*/
glm::vec3 perpendicularvector = glm::cross(dir, edge2);
/*
dot product of edge1 on perpendicular vector
if orthogonal (approximately 0) then ray is parallel to plane, has 0 or infinite contact points
*/
float det = glm::dot(edge1, perpendicularvector);
float Epsilon = std::numeric_limits<float>::epsilon();
if (det > -Epsilon && det < Epsilon)
// Parallel, return false
return false;
/*
Calculate the normalized/unit normal vector
*/
glm::vec3 planeNormal = glm::normalize(glm::cross(edge1, edge2));
/*
Calculate d, the dot product of the normal and any point on the plane.
D is the magnitude of the plane's normal, to the origin.
*/
float d = planeNormal[0] * p0[0] + planeNormal[1] * p0[1] + planeNormal[2] * p0[2];
/*
Take the x,y,z equations, ie:
finalP.xyz = raystart.xyz + dir.xyz * t
substitute them into the scalar equation for plane, ie:
ax + by + cz = d
and solve for t. (This gets a bit wordy) t is the
multiplier on the direction vector, originating at raystart,
where it intersects the plane.
eg:
ax + by + cz = d
a(raystart.x + dir.x * t) + b(raystart.y + dir.y * t) + c(raystart.z + dir.z * t) = d
a(raystart.x) + a(dir.x*t) + b(raystart.y) + b(dir.y*t) + c(raystart.z) + c(dir.z*t) = d
a(raystart.x) + a(dir.x*t) + b(raystart.y) + b(dir.y*t) + c(raystart.z) + c(dir.z*t) - d = 0
a(raystart.x) + b(raystart.y) + c(raystart.z) - d = - a(dir.x*t) - b(dir.y*t) - c(dir.z*t)
(a(raystart.x) + b(raystart.y) + c(raystart.z) - d)/(a(-dir.x) + b(-dir.y) + c(-dir.z) = t
*/
float leftsideScalars = (planeNormal[0] * rayStart[0] +
planeNormal[1] * rayStart[1] +
planeNormal[2] * rayStart[2] - d);
float directionDotProduct = (planeNormal[0] * (-dir[0]) +
planeNormal[1] * (-dir[1]) +
planeNormal[2] * (-dir[2]));
/*
Final calculation of t, hurrah!
*/
float t = leftsideScalars/directionDotProduct;
/*
This is the particular value of t for that line that lies
in the plane. Then you can solve for x, y, and z by going
back up to the line equations and substituting t back in.
*/
linePlaneIntersect = glm::vec3(rayStart[0] + dir[0] * t,
rayStart[1] + dir[1] * t,
rayStart[2] + dir[2] * t
);
return true;
}
这个问题的答案可以帮助你 http://stackoverflow.com/questions/18244678/3d-ray-picking-use-mouse-coordinates-when-mouse-isnt-locked –
我试图按照什么(glm :: vec3 pos = glm :: unProject(glm :: vec3(x,y,0)),view,ortho,glm :: vec4(0,0,1024, 768));'但是这并没有产生我需要的结果。如果我删除了视图部分并只使用了一个单位矩阵,我得到了和前面一样将x和y转换为纵横比的结果。 – user975989