2009-12-30 6 views
2

저는 지금 좋은 일을 위해이 문제에 고심하고 있습니다. devKitPro를 사용하여 내 NDS 화면의 모델에서 꼭지점의 화면 좌표를 결정하려고합니다. 라이브러리는 OpenGL의 일부 기능을 구현하는 것으로 보이지만, 특히 gluProject 기능이 빠져 있습니다. 이는 내가 정확히 그렇게 쉽게 할 수있게 해줄 것입니다.gluProject on NDS?

저는 DS의 레지스터에 저장된 투영 matricies를 사용하여 화면 좌표를 수동으로 계산하는 동안 좋았 습니다만, 투영 행렬을 만들려고 할 때조차도별로 행운이 없었습니다. OpenGL의 문서를 바탕으로 처음부터. 여기 내가 사용하려고 해요 코드는 다음과 같습니다

void get2DPoint(v16 x, v16 y, v16 z, float &result_x, float &result_y) 
{ 
//Wait for the graphics engine to be ready 
/*while (*(int*)(0x04000600) & BIT(27)) 
    continue;*/ 

//Read in the matrix that we're currently transforming with 
double currentMatrix[4][4]; int i; 
for (i = 0; i < 16; i++) 
    currentMatrix[0][i] = 
    (double(((int*)0x04000640)[i]))/(double(1<<12)); 

//Now this hurts-- take that matrix, and multiply it by the projection matrix, so we obtain 
//proper screen coordinates. 
double f = 1.0/tan(70.0/2.0); 
double aspect = 256.0/192.0; 
double zNear = 0.1; 
double zFar = 40.0; 
double projectionMatrix[4][4] = 
{ 
    { (f/aspect), 0.0, 0.0, 0.0 }, 
    { 0.0, f, 0.0, 0.0 }, 
    { 0.0, 0.0, ((zFar + zNear)/(zNear - zFar)), ((2*zFar*zNear)/(zNear - zFar)) }, 
    { 0.0, 0.0, -1.0, 0.0 }, 
}; 

double finalMatrix[4][4]; 
//Ugh... 
int mx = 0; int my = 0; 
for (my = 0; my < 4; my++) 
    for (mx = 0; mx < 4; mx++) 
    finalMatrix[mx][my] = 
    currentMatrix[my][0] * projectionMatrix[0][mx] + 
    currentMatrix[my][1] * projectionMatrix[1][mx] + 
    currentMatrix[my][2] * projectionMatrix[2][mx] + 
    currentMatrix[my][3] * projectionMatrix[3][mx] ; 

double dx = ((double)x)/(double(1<<12)); 
double dy = ((double)y)/(double(1<<12)); 
double dz = ((double)z)/(double(1<<12)); 

result_x = dx*finalMatrix[0][0] + dy*finalMatrix[0][1] + dz*finalMatrix[0][2] + finalMatrix[0][3]; 
result_y = dx*finalMatrix[1][0] + dy*finalMatrix[1][1] + dz*finalMatrix[1][2] + finalMatrix[1][3]; 

result_x = ((result_x*1.0) + 4.0)*32.0; 
result_y = ((result_y*1.0) + 4.0)*32.0; 


printf("Result: %f, %f\n", result_x, result_y); 

} 

그곳에서 DS는 내부적으로 고정 소수점 표기법을 사용하여 작동과 관련된 변화를 많이하고 내가 작업 할 두 배에 해당 변환해야합니다. 내가 얻는 것은 다소 정확할 것 같습니다. 화면을 바라 보는 평면 쿼드를 사용하면 픽셀이 완벽하게 변환되지만, 회전은 어색합니다. 또한, 나는 스크린 너비/높이를 설명하는 투영 행렬로 가고 있기 때문에, 사용하고자하는 마지막 단계는 전혀 옳지 않은 것처럼 보입니다. 프로젝션 매트릭스가 나를 위해 화면 해상도까지 단계를 달성하면 안됩니까?

저는이 모든 것에 익숙하지 않습니다. 매트릭스 수학에 대한 공정한 이해를 가지고 있지만, 3D 그래픽에 들어가기를 원하는만큼 능숙하지는 않습니다. 여기에있는 누군가가 모델의 정점의 3D, 비 변형 좌표를 감안할 때 OpenGL의 gluProject 함수를 사용하지 않고 화면 좌표를 실제로 나타낼 수있는 방법을 알고 있습니까? 제 코드에 빠져있는 것이 뻔뻔스럽게 보이는 것을 볼 수 있습니까? (나는 가능한 한 명확히 할 것이다, 나는 그것이 거칠다는 것을 알고있다, 이것은 내가 연구하고있는 프로토 타입이며, 청결은 최우선 순위는 아니다)

감사합니다.

추신 : 내가 이해하는 바로는, DS의 레지스터에서 가져온 currentMatrix는 이어야합니다.은 정확한 투영, 변환 및 회전 행렬을 제공해야합니다. 정확하게 사용될 행렬이어야합니다. 적어도 GBATEK의 사양에 따라 DS의 자체 하드웨어로 변환합니다. 실제로는 투영 좌표가 실제로 적용된 것 같지 않습니다. 내 문제와 관련이 있다고 생각합니다. 그러나 투영 계산 자체가 다른 결과를 생성하지 않으므로 확실하지 않습니다.

답변

5

거의 정확합니다.

올바른 단계는 다음과 같습니다 프로젝션 매트릭스

  • 곱하기 모델 뷰 (이미 한 것 같은).

  • 값이 1 인 W 구성 요소를 추가하여 3D 정점을 균일 좌표로 확장합니다. 예 : (x, y, z) - 벡터가 w = 1 일 때 (x, y, z, w)가됩니다.

  • 이 벡터에 행렬 곱을 곱하십시오. 행렬은 4x4 크기 벡터와 4 크기 벡터 여야합니다. 결과는 크기 4의 벡터가됩니다 (아직 떨어지지 마십시오!). 이 곱셈의 결과는 클립 공간에서의 벡터입니다. 참고 :이 벡터를 사용하면 이미 여기에 유용한 두 가지 작업을 수행 할 수 있습니다. 포인트가 화면에 있는지 테스트하십시오. 여섯 조건은 다음과 같습니다 2D 공간에

 
    x < -w : Point is outside the screen (left of the viewport) 
    x > W : Point is outside the screen (right of the viewport) 
    y < -w : Point is outside the screen (above the viewport) 
    y > w : Point is outside the screen (below the viewport) 
    z < -w : Point is outside the screen (beyond znear) 
    z > w : Point is outside the screen (beyond zfar) 
  • 프로젝트 요점.w하여 분할 x와 y를 수행합니다
 
    x' = x/w; 
    y' = y/w; 
  • 당신이 깊이 값에 관심이 있다면 (예를 들어 어떤 z 버퍼에 기록됩니다) 당신은뿐만 아니라 z를 투사 할 수 있습니다 :
을 W는 0 인 경우 이전 단계가 작동하지 않습니다
 
z' = z/w 
  • 참고. 포인트가 카메라 위치와 같으면이 경우가 발생합니다. 이 경우에 할 수있는 최선의 방법은 x '와 y'를 0으로 설정하는 것입니다. (다음 단계에서 포인트를 화면 중앙으로 이동합니다 ..).

  • 최종 단계 :는 OpenGL 뷰포트 좌표를 확인하고 적용 :

 
    x_screen = viewport_left + (x' + 1) * viewport_width * 0.5; 
    y_screen = viewport_top + (y' + 1) * viewport_height * 0.5; 
  • 중요 : y는 거꾸로 될 수 화면의 좌표입니다. OpenGL에서 대부분의 다른 그래픽 API와 달리 y = 0은 화면 하단을 나타냅니다.

그게 전부입니다.

+0

와우! 나는 내가 몇 걸음을 잊어 버릴지도 모른다고 생각했다. 네, 고마워요, 오늘 밤 이걸 시험 할게요.^_^ –

+0

+1, 뷰포트 수학이 나에게 틀린 것처럼 보일지라도. x '와 y'는 [-1 1] 범위에 있으므로 곱하기 전에 [0-1]로 되돌려 놓아야합니다. – Bahbar

+0

아, 물론 .. .. 나는 그것을 바꿀 것입니다! –

1

나는 Nils의 철저한 대답에 대해 좀 더 생각해 보겠다.

  1. 두 배를 사용하지 마십시오. 나는 NDS에 익숙하지 않지만 이중 수학을위한 하드웨어는 없다고 생각합니다.
  2. 하드웨어 레지스터를 읽는 중 모델 뷰와 프로젝션이 이미 곱셈되지 않았는지 의심 스럽습니다. 필자는 레지스터에서 전체 MVP를 직접 사용하지 않는 하드웨어 플랫폼을 아직 보지 못했습니다.
  3. 레지스터로의 행렬 저장은 OpenGL과 동일한 순서 일 수도 있고 같지 않을 수도 있습니다. 그렇지 않은 경우 곱셈 행렬 벡터를 다른 순서로 수행해야합니다.
+0

첫 번째 댓글은 진품으로 보입니다. 수동으로 곱셈을 할 때 나는 이상한 결과를 얻고있었습니다. 실제로, "w로 나누기"는 진짜 수정 인 것처럼 보였습니다. 그러나 그것은 정말로 이상하게 보입니다. DS가 부동 소수점 연산에 대한 하드웨어 지원을 가지고 있지 않다는 것은 틀림 없습니다. 내부적으로, 고정 소수점 수학을 사용합니다. 그래서 모든 이동 및 곱셈을 수행하여 배 정밀도로 되돌릴 수 있습니다. 이것은 개념 프로젝트의 증거이며, 최종 점에서 고정 소수점 수학 라이브러리를 사용할 계획입니다. 버전으로 업그레이드해야합니다. –