2011-02-14 6 views
6

Estoy escribiendo un Minecraft como el mundo estático de bloques 3d en C++/openGL. Estoy trabajando para mejorar las tasas de fotogramas, y hasta ahora he implementado la eliminación de triturados utilizando un octárbol. Esto ayuda, pero sigo viendo tasas de fotogramas moderadas a malas. El siguiente paso sería sacrificar cubos que están ocultos desde el punto de vista por cubos más cercanos. Sin embargo, no he podido encontrar muchos recursos sobre cómo lograr esto.3D Oclusion Culling

+0

Has leído sobre z-buffers? http://de.wikipedia.org/wiki/Z-Buffer –

+2

@Thomas: puede referirse a http://en.wikipedia.org/wiki/Z-Buffer :) –

+0

He leído brevemente sobre ellos, pero no lo suficiente para saber cómo usarlos Tendré que leer más. –

Respuesta

7

Crea un objetivo de renderizado con un Z-buffer (o "buffer de profundidad") habilitado. Luego, asegúrese de ordenar todos sus objetos opacos para que se representen de adelante hacia atrás, es decir, los más cercanos a la cámara primero. Todo lo que use la mezcla alfa todavía tiene que renderizarse de nuevo al frente, DESPUÉS de que haya renderizado todos sus objetos opacos.

Otra técnica es la eliminación de oclusiones: puede "renderizar en seco" su geometría de forma económica y luego averiguar cuántos píxeles no pasaron la prueba de profundidad. Hay compatibilidad con consultas de oclusión en DirectX y OpenGL, aunque no todas las GPU pueden hacerlo.

El inconveniente es que se necesita un retraso entre la representación y la obtención del resultado; dependiendo de la configuración (como cuando se usa mosaico predicado), puede ser un fotograma completo. Eso significa que debe ser creativo allí, como representar un cuadro delimitador que sea más grande que el objeto en sí, y descartar los resultados después de un corte de la cámara.

Y una cosa más: una solución más tradicional (que puede usarse al mismo tiempo que la oclusión) es un sistema de sala/portal, donde define regiones como "habitaciones", conectadas a través de "portales". Si un portal no es visible desde su habitación actual, no puede ver la sala conectada a él. E incluso lo es, puede hacer clic en su ventana gráfica para ver lo que está visible a través del portal.

+1

Tenga en cuenta que z-buffering es una buena forma de evitar hacer operaciones innecesarias de fragmentos (píxeles) (calcular el color de un fragmento, realizar búsquedas de textura, iluminación, etc.) pero, si es posible, es mejor omitir la geometría que no es visible (y evite hacer transformaciones en vértices que no contribuirán a la imagen final), como lo hace con la vista de eliminación de trituración. –

+0

Para eso, hay eliminación de oclusión. Debería editar mi respuesta para tocar ese tema. – EboMike

3

Si tiene superficies cercanas a la cámara, puede crear un tronco que represente un área que no es visible, y eliminar objetos que estén completamente contenidos en ese tronco. En el siguiente diagrama, C es la cámara, | es una superficie plana cerca de la cámara, y la región en forma de tronco de rosa compuesta de . representa el área ocluida. La superficie se llama antiportal.

 . 
     .. 
     ... 
    .... 
    |.... 
    |.... 
    |.... 
    |.... 
C |.... 
    |.... 
    |.... 
    |.... 
    .... 
     ... 
     .. 
     . 

(Debe, por supuesto, también a su vez en las pruebas de la profundidad y la escritura de profundidad como se menciona en otra respuesta y comentarios - que es muy sencillo de hacer en OpenGL.)

+0

Esta puede ser una gran técnica, pero creo que es importante agregar que solo se debe hacer para oscurecer objetos que sabes con anticipación que pueden oscurecer una gran cantidad del mundo desde el tronco. Ir por la borda en contraportales puede hacer las cosas más lentas. – Alan

4

¿Cuántos bloques estás haciendo y en que hardware? El hardware moderno es muy rápido y es muy difícil abrumarlo con la geometría (a menos que hablemos de una plataforma portátil). En cualquier hardware de escritorio moderadamente reciente, debería poder renderizar cientos de miles de cubos por cuadro a 60 fotogramas por segundo sin ningún tipo de trucos de descarte.

Si está dibujando cada bloque con una llamada de sorteo por separado (glDrawElements/Arrays, glBegin/glEnd, etc.) (puntos de bonificación: no use glBegin/glEnd), ese será su cuello de botella. Este es un escollo común para principiantes. Si está haciendo esto, entonces necesita agrupar todos los triángulos que comparten los parámetros de textura y sombreado en una sola llamada para cada configuración. Si la geometría es estática y no cambia de cuadro a cuadro, desea utilizar un Vertex Buffer Object para cada lote de triángulos.

Esto todavía se puede combinar con la eliminación de troncos con un octree si, por lo general, solo tienes una pequeña porción de tu mundo de juego total en la vista triturada a la vez. Los búferes de vértices todavía se cargan estáticamente y no se cambian. Frustum elimina el octárbol para generar solo los búferes de índice para los triángulos en el tronco y subirlos dinámicamente a cada cuadro.

+0

Estoy dibujando ~ 250,000 cubos de 1x1x1 antes del sacrificio de frustum, en un sistema moderno (Gefore 8800 GT, doble núcleo, 2 GB de ram). Con la eliminación de triturado de troncos, obtengo una velocidad de fotogramas de 17.83 fps, frente a ~ 2 fps sin eliminación de triturado. El dibujo real de cubos se realiza a través de una interfaz provista, pero por lo que puedo ver, se dibujan usando glPush/PopMatrix y glutSolidCube. –

+0

glutSolidCube es su problema. Estás limitado por todos los cambios de estado para dibujar 250,000 cubos, uno a la vez. Menos de 1000 objetos serían un límite típico para correr a una velocidad razonable. – Alan

5

El enfoque que tomé en this minecraft level renderer es esencialmente un relleno de inundación limitado por troncos.Los trozos de 16x16x128 se dividen en trozos de 16x16x16, cada uno con una VBO con la geometría correspondiente. Empiezo un relleno en la cuadrícula de bloque en la ubicación del jugador para encontrar los bloqueos para renderizar. El relleno está limitada por:

  1. la vista de tronco
  2. chunklets maciza - si todo el lateral de un chunklet es bloques opacos, entonces el FloodFill serán no entran en la chunklet en esa dirección
  3. Dirección - la inundación no invertirá la dirección, por ejemplo: si el bloque actual está al norte del segmento inicial, no inunde en el segmento al sur

Parece que funciona bien. Estoy en Android, así que mientras que un análisis más complejo (antiportales según lo observado por Mike Daniels) eliminaría más geometría, ya tengo una CPU limitada, así que no tiene mucho sentido.

Acabo de ver su respuesta a Alan: el sacrificio no es su problema, es lo que hace y cómo lo está enviando a OpenGL que es lento.

Qué dibujar: no renderizar un cubo para cada bloque, renderizar las caras de bloques transparentes que bordean un bloque opaco. Considere un cubo 3x3x3 de, por ejemplo, bloques de piedra: no tiene sentido dibujar el bloque central porque no hay forma de que el jugador lo pueda ver. Del mismo modo, el jugador nunca verá las caras entre dos bloques de piedra adyacentes, así que no los dibujes.

Cómo dibujar: Como señaló Alan, use VBO para la geometría del lote. No creerás cuánto más rápido hacen las cosas.

Un enfoque más fácil, con cambios mínimos en su código actual, sería usar display lists. Esto es lo que usa Minecraft.

-2

El uso de un Z-Buffer asegura que los polígonos se superpongan correctamente.

Habilitar la prueba de profundidad hace que cada operación de dibujo compruebe el Z-buffer antes de colocar píxeles en la pantalla.

Si tiene objetos convexos, debe (para el rendimiento) habilitar el sacrificio de la cara posterior.

código Ejemplo:

glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE);

Puede cambiar el comportamiento de glCullFace() pasando GL_FRONT o GL_BACK ...

glCullFace(...);

// Dibujar el "mundo del juego". ..