2009-12-30 4 views
2

Я уже давно борется с этим. Я пытаюсь определить координаты экрана вершин в модели на экране моего NDS, используя devKitPro. Похоже, что библиотека реализует некоторые функции OpenGL, но, в частности, отсутствует функция gluProject, которая, как я полагаю, позволяет мне сделать именно это, легко.gluProject на NDS?

Я уже давно пытаюсь вычислить координаты экрана с помощью матриц проекции, которые хранятся в регистрах DS, но мне не повезло даже при попытке построить матрицу проецирования с нуля на основе документации 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-трансформированные координаты вершин модели, а также учитывая, какие матрицы будут применены к нему, чтобы на самом деле придумать координаты экрана, не используя функцию gluProject OpenGL? Можете ли вы увидеть что-то явно очевидное, что мне не хватает в моем коде? (Я уточню, когда это возможно, я знаю, что это грубо, это прототип, над которым я работаю, чистота не является высоким приоритетом)

Спасибо!

PS: Как я понимаю, currentMatrix, что я тяну из регистров ДСА, должны быть давая мне комбинированную проекционную, перевод, и матрицу вращения, так как она должна быть точной матрицей, которая будет использоваться для перевод на собственное оборудование DS, по крайней мере, согласно спецификациям в GBATEK. На практике, похоже, на самом деле нет привязанных к нему проекционных координат, которые, я полагаю, имеют какое-то отношение к моим проблемам. Но я не уверен, так как вычисление самой проекции не приводит к разным результатам.

ответ

5

Это почти правильно.

правильные шаги:

  • Умножение матрицы вида модели с Projection (как вы уже сделали).

  • Расширьте свою трехмерную вершину до однородной координаты, добавив W-компонент со значением 1. Например, ваш (x, y, z) -вектор становится (x, y, z, w) с w = 1.

  • Умножьте этот вектор на матричный продукт. Ваша матрица должна быть 4x4 и ваш вектор размером 4. Результат будет также вектором size4 (не отбрасывайте еще!). Результатом этого умножения является ваш вектор в пространстве клипов. FYI: Вы уже можете сделать пару очень полезных вещей с этим вектором: проверьте, находится ли точка на экране. Шесть условий:

 
    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) 
  • Project ваша точка в 2D пространстве.Для этого разделите х и у на ш:
 
    x' = x/w; 
    y' = y/w; 
  • Если вы заинтересованы в глубине стоимости (например, что будет записано в Zbuffer) вы можете проецировать г, а также:
 
z' = z/w 
  • Обратите внимание, что предыдущий шаг не будет работать, если вес равен нулю. Этот случай случается, если ваша точка равна позиции камеры. Лучшее, что вы могли бы сделать в этом случае, - установить x 'и y' на ноль. (в следующем шаге будет перемещаться точка в центр экрана).

  • Заключительный шаг: Получить координаты окна просмотра OpenGL и применить его:

 
    x_screen = viewport_left + (x' + 1) * viewport_width * 0.5; 
    y_screen = viewport_top + (y' + 1) * viewport_height * 0.5; 
  • Важно: Координата вашего экрана может быть с ног на голову. В отличие от большинства других графических API в OpenGL y = 0 обозначает нижнюю часть экрана.

Это все.

+0

Ничего себе! Я думал, что могу забыть о некоторых шагах. Я, спасибо, проверит это сегодня вечером.^_^ –

+0

+1, хотя математика в видовом экране выглядит неправильно. x 'и y' находятся в диапазоне [-1 1], поэтому их необходимо вернуть до [0-1] до умножения – Bahbar

+0

О, да .. конечно .. Я это изменим! –

1

Я добавлю еще несколько мыслей к подробному ответу Нильса.

  1. не использовать парные. Я не знаком с NDS, но сомневаюсь, что у него есть аппаратное обеспечение для двойной математики.
  2. Я также сомневаюсь, что вид модели и проекция еще не умножены, если вы читаете аппаратные регистры. Я еще не видел аппаратную платформу, которая не использует полный MVP в регистрах напрямую.
  3. Хранилище матрицы в регистры может быть или не быть в том же порядке, что и OpenGL. если они нет, вектор-матрица умножения должен выполняться в другом порядке.
+0

Первый комментарий кажется правдивым, я получал странные результаты при умножении вручную. Действительно, «разделение на w» казалось реальным исправлением, но оно выглядит действительно странно. Вы абсолютно правы, у DS нет аппаратной поддержки математики с плавающей запятой. Внутри он использует математику с фиксированной точкой, поэтому я делаю все смещение и умножение, чтобы вернуть его к двойной точности - это доказательство концептуального проекта, и я полностью планирую использовать математическую библиотеку с фиксированной точкой в ​​финальной версии по соображениям производительности. –