No hay forma de que la GPU cree todo (excepto el uso de Geometry Shaders que requiere SM4.0).
Si estuviera creando un sistema de partículas para obtener la máxima eficiencia de la CPU, me pre-crear (sólo para recoger un número en aras de ejemplo) 100 partículas en una memoria tampón de vértice y el índice de esta manera:
- Crear un búfer de vértices que contenga cuádruples (cuatro vértices por partícula, no seis como tiene)
- Utilice un formato de vértice personalizado que puede almacenar un valor de "compensación de tiempo", así como un valor de "velocidad inicial" (similar al XNA Particle 3D Sample)
- Establezca el valor de tiempo de modo que cada parte icle tiene un desplazamiento de tiempo de 1/100th menos que el último (por lo tanto, el rango de desplazamiento de 1.0 a 0.01 a través del buffer).
- Establezca la velocidad inicial de forma aleatoria.
- Usa un buffer de índice que te da los dos triángulos que necesitas usando los cuatro vértices para cada partícula.
Y lo bueno es que sólo tiene que hacer esto una vez - se puede volver a utilizar el mismo tampón búfer de vértices y el índice para todos los sistemas de partículas (siempre que sean lo suficientemente grandes para su sistema de partículas más grande).
entonces habría un vertex shader que tomaría la siguiente entrada:
- por vértice:
- tiempo compensado
- La velocidad inicial
- Shader Parámetros:
- Hora
- vida útil de partículas (que también es el tiempo de partícula wrap-around valor, y la fracción de partículas en el tampón que se utiliza)
- posición Sistema de partículas/rotación/escala (la matriz mundo)
- Cualesquiera otras entradas interesantes que le gustan, tales como: tamaño de partícula, la gravedad, el viento, etc.
- una escala de tiempo (para obtener un tiempo real, por lo que la velocidad y otros cálculos de la física tienen sentido)
Ese sombreado de vértice (una vez más como XNA Particle 3D Sample) podría determinar la posición del vértice de una partícula en función de su velocidad inicial y el tiempo que esa partícula había estado en la simulación.
El tiempo para cada partícula sería (pseudo código):
time = (currentTime + timeOffset) % particleLifetime;
En otras palabras, a medida que avanza el tiempo, las partículas serán liberados a una velocidad constante (debido al desplazamiento). Y cada vez que una partícula muere en time = particleLifetime
(¿o está en 1.0? El módulo de coma flotante es confuso), el tiempo vuelve a time = 0.0
para que la partícula entre de nuevo en la animación.
Luego, cuando llegó el momento de dibujar mis partículas, tenía configurados mis parámetros de búfers, sombreadores y sombreadores, y llamé al DrawIndexedPrimitives
. Ahora, aquí está el bit inteligente: establecería startIndex
y primitiveCount
para que ninguna partícula comience a mediados de la animación. Cuando el sistema de partículas empiece por primera vez dibujaría 1 partícula (2 primitivos), y para cuando esa partícula esté a punto de morir, dibujaría las 100 partículas, la 100ª de las cuales estaría comenzando.
Luego, un momento después, el temporizador de la 1ra partícula giraría alrededor y la convertiría en la partícula 101.
(Si sólo quería 50 partículas en mi sistema, me acaba de establecer mi vida partículas de 0,5 y sólo alguna vez dibujar el primer 50 de las 100 partículas en el búfer de vértices/index.)
Y cuando llegó el momento de apagar el sistema de partículas; simplemente haga lo mismo a la inversa; establezca startIndex
y primitiveCount
de modo que las partículas dejen de ser arrastradas después de que mueran.
Ahora debo admitir que he pasado por alto las matemáticas involucradas y algunos detalles sobre el uso de quads para partículas, pero no debería ser demasiado difícil de entender. El principio básico para entender es que está tratando su búfer de vértices/índices como un búfer circular de partículas.
Una desventaja de un buffer circular es que, cuando deja de emitir partículas, a menos que se detenga cuando el tiempo actual es un múltiplo de la vida útil de la partícula, terminará con el conjunto activo de partículas sobre los extremos del búfer con un espacio en el medio, lo que requiere dos llamadas de extracción (un poco más lento). Para evitar esto, podría esperar hasta el momento adecuado antes de detenerse: para la mayoría de los sistemas, esto debería estar bien, pero podría parecer extraño para algunos (por ejemplo, un sistema de partículas "lento" que debe detenerse instantáneamente).
Otro inconveniente de este método es que las partículas deben liberarse a una velocidad constante, aunque esto suele ser bastante típico para los sistemas de partículas (obviamente esto es por sistema y la velocidad es ajustable). Con un pequeño ajuste, un efecto de explosión (todas las partículas liberadas a la vez) debería ser posible.
Dicho todo esto: Si es posible, puede valer la pena utilizar una biblioteca de partículas existente.