Pergunta

Estou lutando com isso há um bom tempo. Estou tentando determinar as coordenadas da tela dos vértices em um modelo na tela do meu NDS usando o DevKitPro. A biblioteca parece implementar alguma funcionalidade do OpenGL, mas, em particular, a função Gluproject está faltando, o que (presumo) me permitiria fazer exatamente isso, facilmente.

Estou tentando há um bom tempo calcular as coordenadas da tela manualmente usando as matriculidades de projeção que são armazenadas nos registros do DS, mas não tenho muita sorte, mesmo ao tentar construir a matriz de projeção do zero com base em Documentação do OpenGL. Aqui está o código que estou tentando usar:

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);

} 

Existem muitas mudanças envolvidas, o DS trabalha internamente usando a notação de ponto fixo e eu preciso convertê -lo em duplas para trabalhar. O que estou recebendo parece estar um pouco correto- os pixels são traduzidos perfeitamente se eu estiver usando um quadrilátero plano que está voltado para a tela, mas a rotação é instável. Além disso, já que estou seguindo a matriz de projeção (que é responsável pela largura/altura da tela?) Os últimos passos que eu preciso usar não parecem certos. A matriz de projeção não deveria estar realizando a resolução de rastreamento para mim?

Sou bastante novo em tudo isso, tenho uma compreensão justa da matriz Matrix, mas não sou tão habilidoso quanto gostaria de estar nos gráficos 3D. Alguém aqui sabe de uma maneira, dadas as coordenadas 3D, não transformadas dos vértices de um modelo, e também dadas as matriculares que serão aplicadas a ele, para realmente criar as coordenadas da tela, sem usar a função Gluproject do OpenGL? Você pode ver algo flagrantemente óbvio que estou perdendo no meu código? (Vou esclarecer quando possível, sei que é difícil, este é um protótipo em que estou trabalhando, a limpeza não é uma alta prioridade)

Muitíssimo obrigado!

PS: Pelo que entendi, CurrentMatrix, que eu puxo dos registros do DS, deve estar me dando a matriz combinada de projeção, tradução e rotação, pois deve ser a matriz exata que será usada para a tradução pelo próprio hardware do DS, pelo menos de acordo com as especificações do Gbatek. Na prática, parece não ter as coordenadas de projeção aplicadas a ele, o que eu acho que tem algo a ver com meus problemas. Mas não tenho certeza, pois calcular a projeção eu mesmo não gera resultados diferentes.

Foi útil?

Solução

Isso é quase correto.

As etapas corretas são:

  • Multiplique o ModelView com a matriz de projeção (como você já fez).

  • Estenda seu vértice 3D a uma coordenada homogênea, adicionando um componente w com o valor 1. Por exemplo, seu vetor (x, y, z) se torna (x, y, z, w) com w = 1.

  • Multiplique este vetor com o produto Matrix. Sua matriz deve ser 4x4 e seu vetor de tamanho 4. O resultado também será um vetor de tamanho4 (ainda não solte w!). O resultado dessa multiplicação é o seu vetor no espaço do clipe. FYI: Você já pode fazer algumas coisas muito úteis aqui com este vetor: teste se o ponto estiver na tela. As seis condições são:

    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)
  • Projete seu ponto no espaço 2D. Para fazer isso dividir x e y por w:
  x' = x / w;
  y' = y / w;
  • Se você estiver interessado no valor de profundidade (por exemplo, o que é escrito para o ZBuffer), também pode projetar Z:
 z' = z / w
  • Observe que a etapa anterior não funcionará se W for zero. Este caso acontece se o seu ponto for igual à posição da câmera. O melhor que você pode fazer neste caso é definir x 'e y' como zero. (moverá o ponto para o centro da tela na próxima etapa ..).

  • Etapa final: obtenha as coordenadas do OpenGL Viewport e aplique -o:

  x_screen = viewport_left + (x' + 1) * viewport_width  * 0.5;
  y_screen = viewport_top  + (y' + 1) * viewport_height * 0.5;
  • IMPORTANTE: A coordenada Y da sua tela pode estar de cabeça para baixo. Ao contrário da maioria das outras APIs gráficas no OpenGL y = 0 indica a parte inferior da tela.

Isso é tudo.

Outras dicas

Vou adicionar mais alguns pensamentos à resposta completa de Nils.

  1. Não use duplas. Não estou familiarizado com o NDS, mas duvido que tenha hardware para matemática dupla.
  2. Também duvido que a visualização e a projeção do modelo ainda não sejam multiplicadas se você estiver lendo os registros de hardware. Ainda não vi uma plataforma de hardware que não use o MVP completo nos registros diretamente.
  3. O armazenamento da matriz nos registros pode ou não estar na mesma ordem que o OpenGL. Caso contrário, o vetor de matriz de multiplicação precisa ser feito na outra ordem.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top