java - descargar - buen efecto de explosión y partículas en 3D con OpenGL(JOGL)
java jogl (1)
OK, entonces veamos cómo abordamos por primera vez la implementación de las partículas: teníamos una clase abstracta Sprite
que representaba una sola partícula:
protected void draw(GLAutoDrawable gLDrawable) {
// each sprite has a different blending function.
changeBlendingFunc(gLDrawable);
// getting the quad as an array of length 4, containing vectors
Vector[] bb = getQuadBillboard();
GL gl = gLDrawable.getGL();
// getting the texture
getTexture().bind();
// getting the colors
float[] rgba = getRGBA();
gl.glColor4f(rgba[0],rgba[1],rgba[2],rgba[3]);
//draw the sprite on the computed quad
gl.glBegin(GL.GL_QUADS);
gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3d(bb[0].x, bb[0].y, bb[0].z);
gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3d(bb[1].x, bb[1].y, bb[1].z);
gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3d(bb[2].x, bb[2].y, bb[2].z);
gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3d(bb[3].x, bb[3].y, bb[3].z);
gl.glEnd();
}
La mayoría de las llamadas a métodos son bastante comprensibles aquí, sin sorpresas. la representación es bastante simple. en el método de display
, primero dibujamos todos los objetos opacos, luego, tomamos todos los Sprite
sy los Sprite
( distancia cuadrada de la cámara ), luego dibujamos las partículas, de modo que más lejos de la cámara se dibuje primero. pero lo real que tenemos que profundizar aquí es el método getQuadBillboard
. podemos entender que cada partícula tiene que "sentarse" en un plano que es perpendicular a la posición de la cámara, como aquí: la forma de calcular un plano perpendicular como ese no es difícil:
Substituya la posición de la partícula desde la posición de la cámara para obtener un vector que sea perpendicular al plano, y normalícelo, de modo que pueda usarse como una normal para el avión. ahora un plano se define estrechamente por una posición normal, que ahora tenemos (la posición de la partícula es un punto por el que pasa el avión)
calcule la "altura" del quad, normalizando la proyección del vector
Y
de la cámara en el plano. puedes obtener el vector proyectado calculando:H = cam.Y - normal * (cam.Y dot normal)
crea el "ancho" del quad, calculando
W = H cross normal
devuelve los 4 puntos / vectores:
{position+H+W,position+HW,position-HW,position-H+W}
pero no todos los sprites actúan así, algunos no son perpendiculares. por ejemplo, el sprite del anillo de ondas de choque o los rastros de chispas / humo voladores: por lo que cada sprite tuvo que dar su propia "valla publicitaria" .BTW, el cálculo de los rastros de humo y las chispas de los sprites fue también un desafío. creamos otra clase abstracta, la llamamos LineSprite
. Voy a omitir las explicaciones aquí, puedes ver el código aquí: LineSprite
.
Bueno, este primer intento fue bueno, pero hubo un problema inesperado. aquí hay una captura de pantalla que ilustra el problema: como puedes ver, los sprites se cruzan entre sí, así que si miramos 2 sprites que se cruzan, parte del primer sprite está detrás del segundo sprite, y otra parte del mismo, está enfrente del 2nd sprite, lo que resultó en algo extraño Renderizado, donde las líneas de la intersección son visibles. tenga en cuenta que, incluso si deshabilitamos glDepthMask
, al representar las partículas, el resultado todavía tendría las líneas de intersección visibles, debido a las diferentes mezclas que tienen lugar en cada elemento. así que de alguna manera teníamos que hacer que los sprites no se cruzaran. la idea que tuvimos fue realmente genial.
¿sabes todo esto realmente genial arte callejero en 3D ? aquí hay una imagen que enfatiza la idea:
pensamos que la idea podría implementarse en nuestro juego, para que los sprites no se crucen entre sí. aquí hay una imagen para ilustrar la idea:
Básicamente, hicimos que todos los sprites estuvieran en planos paralelos, por lo que no podría tener lugar ninguna intersección. y no efectuó los datos visibles, ya que permaneció igual. desde cualquier otro ángulo, se vería estirado, pero desde el punto de vista de la cámara, todavía se veía genial. entonces para la implementación:
cuando obtenga 4 vectores que representen una valla publicitaria cuádruple y la posición de la partícula, tendremos que generar un nuevo conjunto de 4 vectores que represente la valla publicitaria cuádruple original. la idea de cómo hacer esto se explica muy bien aquí: Intersección de un avión y una línea . tenemos la "línea" que se define por la posición de la cámara y cada uno de los 4 vectores. tenemos el avión, ya que podríamos usar nuestro vector de cámara Z
como la normal y la posición de la partícula. también, un pequeño cambio estaría en la función de comparación para clasificar los sprites. ahora debería usar la matriz homogénea, que está definida por nuestra base ortonormal de cámara, y en realidad, el cálculo es tan fácil como calcular: cam.getZ_Vector().getX()*pos.getX() + cam.getZ_Vector().getY()*pos.getY() + cam.getZ_Vector().getZ()*pos.getZ();
. Una cosa más que deberíamos notar es que si una partícula está fuera del ángulo de visión de la cámara, es decir, detrás de la cámara, no queremos verla, y especialmente, no queremos calcular su proyección (podría resulta en algunos efectos muy extraños y psicodélicos ...). y todo lo que queda es mostrar la clase final de Sprite
el resultado es bastante agradable:
Espero que ayude, me encantaría recibir sus comentarios sobre este "artículo" (o sobre el juego:}, que puede explorar, usar y usar como quiera ...)
Hace tiempo que quería escribirlo ... Como proyecto para la universidad, escribí (con un amigo) un juego que necesitaba buenas explosiones y efectos de partículas. hemos encontrado algunos problemas, que hemos resuelto con bastante elegancia (creo), y me gustaría compartir el conocimiento.
OK, entonces, encontramos este tutorial: crear un efecto de explosión de partículas que parecía bastante fácil de implementar usando Java con JOGL. antes de responder cómo exactamente hemos implementado este tutorial, explicaré cómo se realiza la representación:
Cámara : es solo una base ortonormal que básicamente significa que contiene 3 vectores ortogonales normalizados y un 4to vector que representa la posición de la cámara. el renderizado se hace usando gluLookAt
:
glu.gluLookAt(cam.getPosition().getX(), cam.getPosition().getY(), cam.getPosition().getZ(),
cam.getZ_Vector().getX(), cam.getZ_Vector().getY(), cam.getZ_Vector().getZ(),
cam.getY_Vector().getX(), cam.getY_Vector().getY(), cam.getY_Vector().getZ());
de modo que el vector z
la cámara es realmente el objetivo, el vector y
es el vector "ascendente", y la posición es, bueno ... la posición.
entonces (si lo ponemos en un estilo de pregunta), ¿cómo implementar un buen efecto de partículas?
PD: todos los ejemplos de código y las capturas de pantalla del juego (tanto en respuesta como en pregunta) provienen del juego, que está alojado aquí: Astroid Shooter