Вопрос

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

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

Огромное спасибо!

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

Это было полезно?

Решение

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

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

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

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

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

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

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

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

Вот и все.

Другие советы

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

  1. не используйте двойники.Я не знаком с NDS, но сомневаюсь, что у него есть какое-либо оборудование для двойной математики.
  2. Я также сомневаюсь, что представление модели и проекция еще не умножены, если вы читаете аппаратные регистры.Я еще не видел аппаратной платформы, которая не использовала бы полный MVP в регистрах напрямую.
  3. хранение матрицы в регистрах может быть в том же порядке, что и в OpenGL, а может и не быть.если это не так, то умножение матрица-вектор нужно производить в другом порядке.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top