2010-10-28 27 views
10

como se ve en la imagenOpenGL GL_SELECT o detección de colisión manual?

http://oi56.tinypic.com/ifu33k.jpg

que dibujo conjunto de contornos (polígonos) como GL_LINE_STRIP. Ahora quiero seleccionar la curva (polígono) debajo del mouse para eliminar, mover ..etc en 3D.

Me pregunto qué método utilizar:

1.Utilice OpenGL recoger y selección. (glRenderMode (GL_SELECT))

2.utilice la detección de colisión manual, usando un rayo de selección y verifique si el rayo está dentro de cada polígono.

+0

aprecio todas las respuestas, ya que solo puedo dar crédito a la generosidad una vez y seleccionar una respuesta. Escojo la respuesta de Kos como correcta, ya que he implementado y otorgado generosidad a Redrobes, para obtener una buena explicación de la geometría. gracias a todos. –

+0

Mira cómo Irrlicht lo hace, ejemplo './7.collision' en 1.8.1 lo hace. –

+0

El nombre de esta operación es "ray casting": https://unity3d.com/learn/tutorials/modules/beginner/physics/raycasting una física de Bullet también puede hacerlo: http://bulletphysics.org/mediawiki-1.5 .8/index.php/Using_RayTest –

Respuesta

16

Yo fuertemente recomendar contra GL_SELECT. Este método es muy antiguo y está ausente en las nuevas versiones GL, y es probable que tenga problemas con las tarjetas gráficas modernas. No espere que sea compatible con hardware: probablemente encontrará un respaldo de software (controlador) para este modo en muchas GPU, siempre que funcione. Utilice bajo su propio riesgo :)

Déjeme ofrecerle una alternativa.

Para objetos grandes sólidos, hay un viejo, buen enfoque de la selección por:

  • activación y configuración de la prueba de tijera a una ventana de 1x1 en la posición del cursor
  • dibujar la pantalla y no había luz, texturizado y muestreo múltiple, la asignación de un color sólido, único para cada entidad "importante" - este color se convertirá en el ID de objeto para recoger
  • llamando glReadPixels y recuperar el color, que luego servirá para identificar el objeto recogido
  • claro t él amortigua, restableciendo la tijera al tamaño normal y dibujando la escena normalmente.

Esto le da un método de selección "por objeto" muy confiable. Además, dibujar y borrar solo 1 píxel con una operación mínima por píxel no afectará realmente tu rendimiento, a menos que tengas poco poder de procesamiento de vértices (es poco probable, creo) o que tengas muchos objetos en realidad y que Limitado al número de llamadas al sorteo (pero, de nuevo, creo que es posible optimizar esto en una sola llamada al sorteo si puede pasar el color como datos por píxel).

El color en RGB es de 3 bytes sin firmar, pero debería ser posible utilizar adicionalmente el canal alfa del framebuffer para el último byte, por lo que obtendría 4 bytes en total, suficiente para almacenar cualquier puntero de 32 bits al objeto como el color.

Como alternativa, puede crear un objeto framebuffer dedicado con un formato de píxel específico (como GL_R32UI, o incluso GL_RG32UI si necesita 64 bits) para eso.

Lo anterior es una buena y rápida alternativa (tanto en términos de confiabilidad como en tiempo de implementación) para el enfoque geométrico estricto.

+0

gracias por su respuesta. ¿Este método funcionará bien para los contornos (líneas)? ya que no estoy renderizando polígonos sólidos? –

+0

Esto significa que tengo que representar el objeto dos veces? B Primero dibuje para la selección del color, luego lea el valor del píxel. Entonces render de forma normal? –

+1

Sí, eso es correcto. dibujas cada objeto dos veces. Dado que para la fase de selección solo se vuelve a dibujar un solo píxel de la pantalla (debido a glViewport), esto no debería ser un problema de rendimiento. Acerca de trabajar con contornos, básicamente, si dibuja las líneas sin mezclar, etc., debería funcionar perfectamente, el único inconveniente es que el usuario deberá hacer clic precisamente en la línea. Es posible que desee ampliar glLineWidth para la etapa de preparación. ¿Es este el comportamiento que esperas? – Kos

0

La primera es fácil de implementar y se usa ampliamente.

1

En el pasado he usado GL_SELECT para determinar qué objeto (s) contribuyeron con el píxel (s) de interés y luego usé la geometría computacional para obtener una intersección precisa con el (los) objeto (s) si fuera necesario.

1

¿Espera seleccionar haciendo clic en el contorno (en el borde) o en el interior del polígono? Su segundo enfoque parece que quiere hacer clic en el interior para seleccionar el polígono que lo contenga más apretado. No creo que GL_SELECT después de representar GL_LINE_STRIP haga que el interior responda a los clics.

Si se tratara de un trazado de contornos verdadero (de la imagen no creo que sea, los bordes parecen intersecarse), entonces estaría disponible un algoritmo mucho más simple.

5

Encontré que en las nuevas GPU, el modo GL_SELECT es extremadamente lento. Jugué con algunas maneras diferentes de solucionar el problema.

La primera fue hacer una prueba de colisión de la CPU, que funcionó, pero no fue tan rápido como me hubiera gustado. Definitivamente se ralentiza cuando estás lanzando rayos en la pantalla (usando gluUnproject) y luego tratando de encontrar con qué objeto está colisionando el mouse. La única forma de obtener velocidades satisfactorias fue usar un octárbol para reducir el número de pruebas de colisión y luego hacer una prueba de colisión de cuadro delimitador; sin embargo, esto dio como resultado un método que no era perfecto para píxeles.

El método que establecí fue encontrar primero todos los objetos debajo del mouse (usando gluUnproject y pruebas de colisión de cuadro delimitador) que generalmente es muy rápido. Luego hice que cada uno de los objetos que potencialmente colisionaron con el mouse en el backbuffer sea de un color diferente. Luego utilicé glReadPixel para obtener el color debajo del mouse y mapeo de nuevo al objeto. glReadPixel es una llamada lenta, ya que tiene que leer desde el búfer de cuadros. Sin embargo, se realiza una vez por cuadro, lo que termina tomando una cantidad insignificante de tiempo. Puedes acelerarlo renderizando a un PBO si lo deseas.

Giawa

1

usted utiliza no puede seleccionar si se queda con las líneas, ya que tendría que hacer clic en los píxeles de línea prestados no el espacio dentro de las líneas que delimitan los que he leído como lo que desea hacer.

Puede usar la respuesta de Kos pero para representar el espacio que necesita para llenarlo de forma sólida, lo que implicaría convertir todos sus contornos en tipos convexos, lo cual es doloroso. Entonces creo que eso funcionaría a veces y daría la respuesta incorrecta en algunos casos a menos que lo hicieras.

Lo que necesita hacer es usar la CPU. Usted tiene extensiones de vista desde la ventana gráfica y la matriz de perspectiva. Con las coordenadas del mouse, genere la vista del vector del puntero del mouse. También tienes todas las coordenadas de los contornos.

Tome la primera coord del primer contorno y cree un vector para la segunda coord. Haz un vector de ellos. Tome la tercera coordenada y haga un vector de 2 a 3 y repita todo el contorno del contorno y finalmente haga que el último de la coord n ​​vuelva a ser 0. Para cada par en secuencia, encuentre el producto cruzado y resuma todos los resultados. Cuando tenga ese vector de suma final, consérvelo y haga un producto de puntos con el vector de dirección del puntero del mouse. Si es + ve entonces el mouse está dentro del contorno, si es -ve entonces no es y si es 0 entonces supongo que el plano del contorno y la dirección del mouse son paralelos.

Haga eso para cada contorno y luego sabrá cuáles de ellos se activan con el mouse. Depende de usted cuál elegir de ese conjunto. El más alto Z?

Parece un montón de trabajo, pero no está tan mal y dará la respuesta correcta.También le gustaría mantener cuadros delimitadores de todos sus contornos, luego puede sacar los primeros del vector del mouse haciendo los mismos cálculos que para el vector completo pero solo en los 4 lados y si no está dentro, entonces el contorno no puede ser ya sea.

+0

gracias por la respuesta. Mis contornos no tienen una dirección uniforme. Algunos contornos son en sentido horario, mientras que otros son en sentido antihorario. ¿Debo cambiar la operación entre productos dependiendo de la dirección? –

3

Umanga, canto considera cómo responder en línea ... tal vez debería inscribirse :)

En primer lugar debo disculparme por algo que le da la equivocada - que hice la cara posterior sacrificio de uno. Pero el que necesitas es muy similar y es por eso que me confundí ... d'oh.

Obtenga la posición de la cámara como vector del mouse como se dijo anteriormente.

Para cada contorno, recorra todos los cordones de dos en dos (0-1, 1-2, 2-3, ... n-0) y haga un vec de ellos como antes. Es decir. caminar por el contorno.

Ahora haga la cruceta de esos dos (borde de contorno a vec de ratón) en lugar de entre pares como dije antes, haga eso para todos los pares y agregue todos los vectores.

Al final encuentra la magnitud del vector resultante. Si el resultado es cero (teniendo en cuenta los errores de redondeo), entonces está fuera de la forma, independientemente de la orientación. Si estás interesado en enfrentarlo, en lugar de la mag puedes hacer ese dot prod con el vector del mouse para encontrar el enfrentamiento y probar el signo +/-.

Funciona porque el algoritmo encuentra la distancia entre la línea del vector y cada punto. Cuando los resumes y estás afuera, todos cancelan porque el contorno está cerrado. Si estás dentro, entonces todos se resumen. Es en realidad la Ley de campos electromagnéticos de Gauss en física ...

Consulte: http: //en.wikipedia.org/wiki/Gauss%27s_law y tenga en cuenta que "el lado derecho de la ecuación es la carga total encerrada por S dividido por la constante eléctrica "notando la palabra" encerrado "- es decir, cero significa que no está encerrado.

Todavía puede hacer esa optimización con los cuadros delimitadores para la velocidad.

Cuestiones relacionadas