這是非常類似的東西等軸接口,用於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