Foros - Stratos

Programadores => Programación gráfica => Mensaje iniciado por: marcode en 02 de Julio de 2008, 03:10:08 AM

Título: un picking relativamente sencillo
Publicado por: marcode en 02 de Julio de 2008, 03:10:08 AM
quiero saber en qué lugar de la superficie, se proyecta un supuesto rayo que sale de una posición en 2D (del cursor del ratón).

La idea es hacer una función a la que supongo tendré que pasar la matriz de vista, la de proyección, el viewport y la posición del cursor. Y me devuelva la coordenada 3D donde hace el picking.

Como el lugar de "colisión" del rayo un plano recto en la altura cero, pues basta con que me devuelva la coordenada X/Z de la superficie del suelo sobre la que estoy "pasando" el cursor.

¿alguien sabría la fórmula?, imagino que es el proceso inverso al de pasar la coordenada 3D a 2D en la pantalla, pero ando un poco liado y no quiero perder demasiado tiempo dando palos de ciego, si alguien lo supiera pues estupendo, mientras seguiré indagando.
Título: un picking relativamente sencillo
Publicado por: AK47 en 02 de Julio de 2008, 08:23:19 AM
Busca en google "picking 3d" y cosas así. Por cierto, como fue lo de los impostores?
Título: un picking relativamente sencillo
Publicado por: Buffon en 02 de Julio de 2008, 11:51:16 AM
Si no recuerdo mal esta era la parte de mi código que lo hacía.

if(state == GLUT_DOWN){
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix((GLdouble) x,(GLdouble) (vista[3]-y),.5,.5,vista);
gluPerspective(anglecam,aspect,radi,5*radi);
glMatrixMode(GL_MODELVIEW);

//TORNEM A DIBUIXAR L'ESCENA
redibuixa();
hits=glRenderMode(GL_RENDER);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
mode=!mode;

int ind=0;
int i=3;
int j=4;

while(ind<hits && ind<mida/5){
 
 scene->meshobjlist[*(nom+i)].facelist[*(nom+j)].selected=!scene->meshobjlist[*(nom+i)].facelist[*(nom+j)].selected;
 
 i+=5;
 j+=5;
 ind++;
}

glEnable(GL_CULL_FACE);
glutPostRedisplay();

     }
Título: un picking relativamente sencillo
Publicado por: marcode en 02 de Julio de 2008, 10:06:59 PM
Cita de: AK47Busca en google "picking 3d" y cosas así. Por cierto, como fue lo de los impostores?

sigue pendiente  :(


lo otro a ser posible no querría usar el gluPickMatrix
Título: un picking relativamente sencillo
Publicado por: Prompt en 03 de Julio de 2008, 10:42:11 AM
joder... "scene->meshobjlist[*(nom+i)].facelist[*(nom+j)].selected=!scene->meshobjlist[*(nom+i)].facelist[*(nom+j)].selected;"
Título: un picking relativamente sencillo
Publicado por: AK47 en 03 de Julio de 2008, 01:00:35 PM
Que código más feo, Prompt :P
Título: un picking relativamente sencillo
Publicado por: Buffon en 03 de Julio de 2008, 01:27:16 PM
Cita de: marcode
Cita de: AK47Busca en google "picking 3d" y cosas así. Por cierto, como fue lo de los impostores?

sigue pendiente  :(


lo otro a ser posible no querría usar el gluPickMatrix

tu no tas leído mi respuesta xDDDDD

(ese código tiene 5 años por lo menos y es una práctica de tercero de carrera <.<)

me edito:

tu querías el orden de multiplicación de las matrices no el código concreto que lo hiciera ^^ :P
Título: un picking relativamente sencillo
Publicado por: Buffon en 03 de Julio de 2008, 01:39:37 PM
Cita de: Promptjoder... "scene->meshobjlist[*(nom+i)].facelist[*(nom+j)].selected=!scene->meshobjlist[*(nom+i)].facelist[*(nom+j)].selected;"

cada mesh le metimo un booleano que decía si estaba seleccionado o no y en el rendering lo pintabamos de otro color si así era.

Aún así no es forma de programar, lo se xDDDDD
Título: un picking relativamente sencillo
Publicado por: marcode en 03 de Julio de 2008, 02:10:18 PM
es que no quiero usar el modo de render de selección de opengl, porque es que no lo necesito, y además no sería lo más eficaz.

Quiero poder seleccionar la celda correspondiente en la típica matriz de celdas iguales. Que en 2D sería muy fácil, pero en 3D se complica un poco porque depende de la posición y la orientación de la cámara, de la proyección y el viewport.

Todavía no lo he intentado hacer, pero es que como no lo tengo nada claro quería saber si alguien que esté puesto en el tema tenía alguna idea.
Título: un picking relativamente sencillo
Publicado por: Prompt en 04 de Julio de 2008, 09:54:03 AM
Es que para 3D está pensado GL_SELECT :) como método más optimo, si vas a hacer calculos más complejos y volver a hacer el rayo a mano, quizás sea más optimo no usarlo e implementarte el tuyo.

Yo particularmente lo que haría es pintar en GL_SELECT obtener a que objeto le he dado y comprobar si mi rayo da en ese objeto y donde.
Título: un picking relativamente sencillo
Publicado por: Buffon en 04 de Julio de 2008, 10:58:12 AM
Cita de: marcodees que no quiero usar el modo de render de selección de opengl, porque es que no lo necesito, y además no sería lo más eficaz.

Quiero poder seleccionar la celda correspondiente en la típica matriz de celdas iguales. Que en 2D sería muy fácil, pero en 3D se complica un poco porque depende de la posición y la orientación de la cámara, de la proyección y el viewport.

Todavía no lo he intentado hacer, pero es que como no lo tengo nada claro quería saber si alguien que esté puesto en el tema tenía alguna idea.

piensa que te he pasado un código de hace 5 años jaja.

a ver si encuentro uno que tengo más actual que usa GL_SELECT como dice prompt.

pero repito, tu pedías el orden de multiplicación de las matrices y te he puesto algo que utilizar como esquema, no creí que quisieras el código completo :P
Título: un picking relativamente sencillo
Publicado por: Prompt en 04 de Julio de 2008, 11:13:08 AM
Cita de: Buffon
pero repito, tu pedías el orden de multiplicación de las matrices y te he puesto algo que utilizar como esquema, no creí que quisieras el código completo :P

Es que la gente es mu floja... muy muy floja :P no pide links ni algo para estudiar no... piden ya el código para copiar, pegar y adaptar. :evil:
Título: un picking relativamente sencillo
Publicado por: marcode en 04 de Julio de 2008, 12:32:34 PM
CitarEs que la gente es mu floja... muy muy floja Razz no pide links ni algo para estudiar no... piden ya el código para copiar, pegar y adaptar.

?
Título: un picking relativamente sencillo
Publicado por: Warchief en 04 de Julio de 2008, 12:39:51 PM
Puedes mirar en motores de código abierto. Por ejemplo en Irrlicht (version 3demon):

getScreenCoordinatesFrom3DPosition( const core::vector3df& pos3d, ICameraSceneNode* camera )
{
core::vector2di pos2d(-1000,-1000);

 // ...

core::vector2di dim = Driver->getScreenSize();
dim.X /= 2;
dim.Y /= 2;

f32 transformedPos[4];

core::matrix4 trans = camera->getProjectionMatrix();
trans *= camera->getViewMatrix();

transformedPos[0] = pos3d.X;
transformedPos[1] = pos3d.Y;
transformedPos[2] = pos3d.Z;
transformedPos[3] = 1.0f;

trans.multiplyWith1x4Matrix(transformedPos);

if(transformedPos[3] < 0)
return core::vector2di(-10000,-10000);

f32 zDiv = transformedPos[3] == 0.0f ? 1.0f :
(1.0f / transformedPos[3]);

pos2d.X = (s32)(dim.X * transformedPos[0] * zDiv) + dim.X;
pos2d.Y = ((s32)(dim.Y - (dim.Y * (transformedPos[1] * zDiv))));

return pos2d;
}


Será cuestión de adaptarlo a las funciones que tengas en tu motor o API.
Título: un picking relativamente sencillo
Publicado por: marcode en 04 de Julio de 2008, 01:56:08 PM
Cita de: WarchiefPuedes mirar en motores de código abierto. Por ejemplo en Irrlicht (version 3demon):

getScreenCoordinatesFrom3DPosition( const core::vector3df& pos3d, ICameraSceneNode* camera )
{
core::vector2di pos2d(-1000,-1000);

 // ...

core::vector2di dim = Driver->getScreenSize();
dim.X /= 2;
dim.Y /= 2;

f32 transformedPos[4];

core::matrix4 trans = camera->getProjectionMatrix();
trans *= camera->getViewMatrix();

transformedPos[0] = pos3d.X;
transformedPos[1] = pos3d.Y;
transformedPos[2] = pos3d.Z;
transformedPos[3] = 1.0f;

trans.multiplyWith1x4Matrix(transformedPos);

if(transformedPos[3] < 0)
return core::vector2di(-10000,-10000);

f32 zDiv = transformedPos[3] == 0.0f ? 1.0f :
(1.0f / transformedPos[3]);

pos2d.X = (s32)(dim.X * transformedPos[0] * zDiv) + dim.X;
pos2d.Y = ((s32)(dim.Y - (dim.Y * (transformedPos[1] * zDiv))));

return pos2d;
}


Será cuestión de adaptarlo a las funciones que tengas en tu motor o API.

Quiero hacer eso pero al revés. Creo que se aproxima más a lo que haría un trazador de rayos, es decir, que conozco la posición 2D, la proyección y vista de la cámara, y quiero saber a qué posición 3D corresponde. Con la ventaja de que el lugar de colisión no es un objeto, sino una superficie plana y recta con respecto al origen de coordenadas e infinita.

Pensaba que iba a ser más sencillo y que lo sabría alguien, una simple fórmula.
Título: un picking relativamente sencillo
Publicado por: Warchief en 04 de Julio de 2008, 03:15:13 PM
Despiste, 2d -> 3d es.


//! Returns a 3d ray which would go through the 2d screen coodinates.
core::line3d<f32> CSceneCollisionManager::getRayFromScreenCoordinates( const core::vector2di& pos, ICameraSceneNode* camera )
{
core::line3d<f32> ln;
// ...
const scene::SViewFrustrum* f = camera->getViewFrustrum();

core::vector3df farLeftUp = f->getFarLeftUp();
core::vector3df lefttoright = f->getFarRightUp() - farLeftUp;
core::vector3df uptodown = f->getFarLeftDown() - farLeftUp;

core::vector2di screenSize = Driver->getScreenSize();

f32 dx = pos.X / (f32)screenSize.X;
f32 dy = pos.Y / (f32)screenSize.Y;

if(camera->isOrthogonal())
ln.start = f->cameraPosition + (lefttoright * (dx-0.5f)) + (uptodown * (dy-0.5f));
else
ln.start = f->cameraPosition;

ln.start = f->cameraPosition;
ln.end = farLeftUp + (lefttoright * dx) + (uptodown * dy);

return ln;
}


Con la línea trazas la colisión. En tu caso, colisión de recta con plano.

Puedes mirar el código del motor [ http://irrlicht.sourceforge.net/ ]
Título: un picking relativamente sencillo
Publicado por: Warchief en 04 de Julio de 2008, 03:21:09 PM
En internet también hay cosas:
http://www.3dkingdoms.com/selection.html
Título: un picking relativamente sencillo
Publicado por: marcode en 05 de Julio de 2008, 12:50:24 AM
Gracias, encontré la solución en la página que pusiste, Warchief. La función que necesitaba es exactamente gluUnProject, que desconocía.

A esta función se le pasa la posición del cursor y la distancia z que buscamos, el viewport y las matrices de transformación, y te devuelve las coordenadas en 3D. De manera que con 2 llamadas con diferentes distancias obtenemos un rayo que "sale" del cursor a la escena, y con él se puede determinar su intersección con cualquier plano y por tanto el punto exacto de colisión que buscaba.

ahora lo que he intentado hacer es mi propia función gluUnproject conociendo la fórmula.

CitarTo compute the coordinates (objX, objY, and objZ),
     gluUnProject multiplies the normalized device   coordinates by
     the inverse of model*proj as follows:

http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/unproject.html

multiplico la matriz modelview por la de projection, la matriz resultante la invierto. y multiplico el punto 2D de la ventana normalizado por esa matriz.

Es así ¿no?
Pues no funciona :roll:

Bueno, da igual, ya lo resolveré, lo que quería ya lo he encontrado.