답변:
3D 피킹을 사용하고 싶을 것입니다. 게임에서 사용하는 코드는 다음과 같습니다.
먼저 카메라에서 광선을 비췄습니다. 마우스를 사용하고 있지만 사용자 가보고있는 곳을 사용하는 경우 창의 중앙을 사용할 수 있습니다. 이것은 내 카메라 클래스의 코드입니다.
public Ray GetPickRay() {
int mouseX = Mouse.getX();
int mouseY = WORLD.Byte56Game.getHeight() - Mouse.getY();
float windowWidth = WORLD.Byte56Game.getWidth();
float windowHeight = WORLD.Byte56Game.getHeight();
//get the mouse position in screenSpace coords
double screenSpaceX = ((float) mouseX / (windowWidth / 2) - 1.0f) * aspectRatio;
double screenSpaceY = (1.0f - (float) mouseY / (windowHeight / 2));
double viewRatio = Math.tan(((float) Math.PI / (180.f/ViewAngle) / 2.00f)) * zoomFactor;
screenSpaceX = screenSpaceX * viewRatio;
screenSpaceY = screenSpaceY * viewRatio;
//Find the far and near camera spaces
Vector4f cameraSpaceNear = new Vector4f((float) (screenSpaceX * NearPlane), (float) (screenSpaceY * NearPlane), (float) (-NearPlane), 1);
Vector4f cameraSpaceFar = new Vector4f((float) (screenSpaceX * FarPlane), (float) (screenSpaceY * FarPlane), (float) (-FarPlane), 1);
//Unproject the 2D window into 3D to see where in 3D we're actually clicking
Matrix4f tmpView = Matrix4f(view);
Matrix4f invView = (Matrix4f) tmpView.invert();
Vector4f worldSpaceNear = new Vector4f();
Matrix4f.transform(invView, cameraSpaceNear, worldSpaceNear);
Vector4f worldSpaceFar = new Vector4f();
Matrix4f.transform(invView, cameraSpaceFar, worldSpaceFar);
//calculate the ray position and direction
Vector3f rayPosition = new Vector3f(worldSpaceNear.x, worldSpaceNear.y, worldSpaceNear.z);
Vector3f rayDirection = new Vector3f(worldSpaceFar.x - worldSpaceNear.x, worldSpaceFar.y - worldSpaceNear.y, worldSpaceFar.z - worldSpaceNear.z);
rayDirection.normalise();
return new Ray(rayPosition, rayDirection);
}
그런 다음 광선이 물체와 교차 할 때까지 광선을 따라갑니다. 경계 상자 또는 이와 비슷한 것으로 게임에 적용 할 수 있습니다. 일반적으로 이것은 광선을 따라갑니다 (선의 방향을 시작점에 계속해서 추가하고 '무언가에 부딪 칠 때까지').
다음으로 어떤면이 선택되고 있는지 확인하려면 큐브의 삼각형을 반복하여 광선이 교차하는지 확인하면됩니다. 다음 함수는 그렇게하고 선택한면까지의 거리를 반환 한 다음 카메라에 가장 가까운 교차면을 사용합니다 (따라서 뒷면을 선택하지 않습니다).
public static float RayIntersectsTriangle(Ray R, Vector3f vertex1, Vector3f vertex2, Vector3f vertex3) {
// Compute vectors along two edges of the triangle.
Vector3f edge1 = null, edge2 = null;
edge1 = Vector3f.sub(vertex2, vertex1, edge1);
edge2 = Vector3f.sub(vertex3, vertex1, edge2);
// Compute the determinant.
Vector3f directionCrossEdge2 = null;
directionCrossEdge2 = Vector3f.cross(R.Direction, edge2, directionCrossEdge2);
float determinant = Vector3f.dot(directionCrossEdge2, edge1);
// If the ray and triangle are parallel, there is no collision.
if (determinant > -.0000001f && determinant < .0000001f) {
return Float.MAX_VALUE;
}
float inverseDeterminant = 1.0f / determinant;
// Calculate the U parameter of the intersection point.
Vector3f distanceVector = null;
distanceVector = Vector3f.sub(R.Position, vertex1, distanceVector);
float triangleU = Vector3f.dot(directionCrossEdge2, distanceVector);
triangleU *= inverseDeterminant;
// Make sure the U is inside the triangle.
if (triangleU < 0 || triangleU > 1) {
return Float.MAX_VALUE;
}
// Calculate the V parameter of the intersection point.
Vector3f distanceCrossEdge1 = null;
distanceCrossEdge1 = Vector3f.cross(distanceVector, edge1, distanceCrossEdge1);
float triangleV = Vector3f.dot(R.Direction, distanceCrossEdge1);
triangleV *= inverseDeterminant;
// Make sure the V is inside the triangle.
if (triangleV < 0 || triangleU + triangleV > 1) {
return Float.MAX_VALUE;
}
// Get the distance to the face from our ray origin
float rayDistance = Vector3f.dot(distanceCrossEdge1, edge2);
rayDistance *= inverseDeterminant;
// Is the triangle behind us?
if (rayDistance < 0) {
rayDistance *= -1;
return Float.MAX_VALUE;
}
return rayDistance;
}
가장 짧은 거리의 삼각형이 선택된 삼각형입니다. 또한, 내 게임에 대한 뻔뻔한 플러그, 당신은 그것을 확인하고 따라와 가끔 나가는 여론 조사에 투표해야합니다. 감사! http://byte56.com
찾고있는 기술을 "피킹"또는 "3D 피킹"이라고합니다. 여러 가지 방법이 있습니다. 가장 일반적인 것 중 하나는 투영 변환의 역수를 사용하여 화면의 2D 점을 눈 공간으로 변환하는 것입니다. 이를 통해 뷰 공간에 광선을 생성 할 수 있으며,이를 통해 다양한 장면 형상 비트의 물리적 표현과의 충돌을 테스트하여 사용자가 '적중 한'오브젝트를 결정할 수 있습니다.
GL이 지원하는 "피킹 버퍼"(또는 "선택 버퍼")를 사용할 수도 있습니다. 여기에는 기본적으로 모든 픽셀의 고유 객체 식별자를 버퍼에 쓴 다음 해당 버퍼를 테스트하는 것이 포함됩니다.
OpenGL FAQ는 둘 다에 대한 간단한 토론을 가지고 있습니다. (선택 버퍼는 전체 GL 기능이므로 선택 버퍼에 더 중점을 둡니다. 레이 피킹은 파이프 라인에서 활성 매트릭스를 추출하는 경우를 제외하고 API와 무관합니다). 다음은 광선 따기 기법의보다 구체적인 예입니다 (iOS의 경우, 쉽게 번역해야 함). 이 사이트 에는 LWJGL로 포팅 된 일부 OpenGL Red Book 예제에 대한 소스 코드가 있으며 여기에는 픽킹 데모가 포함됩니다.
SO에 대한이 질문 도 참조하십시오 .