lunes, 19 de enero de 2015

Implementación de la cámara: tercera versión

Decía en el último artículo que ya tengo la cámara funcionando como quiero, y que los problemas de rendimiento no eran culpa del sistema de cámara. En este artículo voy a cubrir cómo funciona la cámara al final y pequeños problemas y sus soluciones.



El sistema básico tiene las ideas que expliqué en el artículo sobre la segunda versión de la cámara. Tener trozos de spline de 5 nodos, con nodos equidistantes, y donde el último tramo de un spline y el primero del siguiente se suponerponen haciendo una transición suave entre un spline y el siguiente en esa parte en común. Lo que al final se queda fuera es la aproximación de la posición del personaje al spline por trozos de spline. Ahora mismo sigo aproximando el spline como una recta para saber a qué altura del spline está el personaje. En mis pruebas no se nota diferencia entre las dos aproximaciones y es más barata.



Uno de los problemas que tenía desde el principio de los tiempos y que pensaba que el usar la transición suave entre 2 splines se iba a arreglar era el de los puntos muertos en los empalmes de splines. Se entiende mucho mejor con una imagen de estas cutres que dibujo tipo paint (pero que uso programas de los buenos para hacerlos, el manco soy yo, no el sw): 

Empalme de splines



Las rectas azules y verdes son la aproximación de 2 splines, los cuadrados de su color es la zona que la aproximación que hago consideraría como dentro de ese spline, entre 0 y 1 en coordenadas del spline. Y la x roja la posición del personaje. Y ahí está el problema está por encima del 1 para el primer spline, así que intentará dibujarlo con el valor del spline 2, y en el siguiente frame vería que el valor del spline 2 es negativo e intentaría dibujarlo con el valor del spline 1. Incluso he tenido implementaciones en que este problema daba un bucle infinito al usar recursividad y me tocaba matar Unity (por cierto, una forma de matar tu juego sin matar el editor estaría muy bien Unity). Si no el problema es que hay un punto en el que estando el personaje quieto, la cámara vibra entre dos tomas, que a lo mejor son muy cercanas, pero la sensación de parpadeo entre las dos es horrorosa, y no solo es si te pilla quieto en ese sitio, al pasar por él, aunque solo vibre una vez, se nota que ha pasado algo raro. El dibujo es una versión muy exagerada, nunca hay tanto hueco entre dos splines, pero siempre hay un pequeño hueco, sobre todo si nos alejamos del spline (a un lado en la cámara del juego), y lo mismo pasas varias veces por allí sin percibir el error, pero en alguna partida se ve, y no mola.



Y hay otra cosa que he pasado por alto en el ejemplo y es que ahora los splines se superponen un poco, es decir el final del spline 1 no es el principio del 2, sino que el [75%-100%] del 1 coincide con el [0%-25%] del 2. Así que no debería tener ese problema ¿o sí?, realmente lo único que he hecho es desplazar los valores donde ocurre, pero sigue ocurriendo. Un ejemplo práctico: posición en el spline 1: 100.01%, hay que dibujarlo en el spline 2, donde tiene la posición 24.95%, en el siguiente frame: 24,5% es menor a 25%, así que debe dibujarse en el spline 1. Y así tenemos un parpadeo constante, si cada frame se coloca la cámara en un sitio un poco distinto. Claro, es que teniendo todo un tramo para hacer los cambios, lo hago en el mismo punto al avanzar y al retroceder, separando los dos puntos clave no tengo ese problema. Así ahora al avanzar se cambia de un spline al siguiente cuando alcanza el 100% (y sigue por el 25% del siguiente), pero al retroceder, se hace cuando bajo del 15% del spline (siguiendo hacia abajo por el 90% del spline anterior). Y así, por mucho error de aproximación en los empalmes que haya, no puede ser de un 10% y no tengo ese fenómeno del parpadeo.



Relacionado con esto está el error de índice fuera de rango que obtenía a veces y que no sabía de donde venía, y el problema es el mismo. Cuando llego al 75% de un spline se toma posición respecto a ese spline y respecto al siguiente y se va interpolando entre las 2. Por ejemplo: 0.8 en un spline en realidad tomo un 80% de la posición del primer spline al 0.8 y un 20% del segundo spline al 0.5. Justo al llegar a 0.75, puede pasar que el segundo spline me de un valor de -0.02, por ejemplo, y ese valor negativo es lo que me hacía saltar por los aires el método para calcular posiciones de spline de iTween. Por encima de 1, el método extrapola valores muy bien, pero por debajo de 0 peta. Sabiendo esto y añadiendo unos clamps por ahí la solución era fácil, lo difícil era darse cuenta del problema, sobre todo porque se daba en ocasiones contadas, no era fácil de reproducir.



Otro problema era la orientación de la cámara. Para no hacerlo caro intenté aprovechar la última posición de la cámara y la actual para ir enfocando hacia la tangente. El primer error saltaba inmediatamente: si el jugador se paraba la posición anterior y la actual son la misma y la cámara se pone a mirar para cuenca. Solución fácil: comprobar la posición, si es la misma y el jugador no se ha movido pues no hacemos caso y seguimos con la anterior posición registrada. Pero volvemos a tener un problema de precisión. ¿Y si el jugador se ha movido muy poco? ¿Y si no se ha movido pero por un problema de precisión Unity cree que si? En estos casos puede que los operadores de comparación fallen al ser dos cifras muy parecidas y haga lo que lo debe, ponerme la cámara mirando al revés. Es un caso raro, pero he conseguido dando vueltas por algún punto conflictivo que la cámara mire justo hacia el sitio contrario de donde debería. ¿Y qué hago? ¿Pongo un umbral de movimiento? Esto podría tener un problema, que alguien se moviese muy muy despacio y la cámara no le siguiera al no detectar el movimiento.



Lo podría hacer acumulado, no tomar una nueva posición para la orientación hasta que no se haya desplazado un mínimo desde la anterior, pero sigo teniendo problemas. A veces da saltos, porque el diferencial usado para separar los puntos no es siempre el mismo y se nota mucho el tirón. Intenté también usar posiciones pasadas cuando sea posible e inventarlas con un desplazamiento sobre el spline cuando no. Aquí el parpadeo era evidente, la diferencia de orientación cuando se usaba uno u otro método era muy evidente. Tras descubrir que los problemas de rendimiento no eran por la cámara pude dejarme de tanta tontería y tomar siempre dos medidas de cámara para poder orientarla. Ahora si la cámara acaba en una posición x (en spline) calculo su posición en coordenadas del mundo y la posición de x+0.1 y pongo la cámara a mirar en la dirección de la tangente generada por estos dos puntos. Así el movimiento de la cámara es bastante suave.



El último problema que tuve fue la orientación inicial de la cámara. El jugador empieza algo por detrás del punto 0 de la cámara, y tanto la posición de la cámara como la auxiliar para orientación quedaban por debajo de 0, siendo clampeadas a 0 y teniendo otra vez la cámara mirando para cuenca. Con un poco de precaución del orden en que hacer la suma de valores extra y los clamps esto también se solucionó.






En el vídeo se puede ver como ahora funciona bien y suave. Hacia el final del desfiladero hace un giro brusco, es por cómo he puesto los splines, sin preocuparme mucho (espero), ya que como va a cambiar la fase, tendré que poner que la cámara vaya por otro sitio y no merece la pena dedicarle mucho tiempo. Otra cosa que se ve en el vídeo es que ahora solo 1 veneno se activa ante el personaje y ataca, ya os contaré el problema, ¡me pongo ahora mismo con ello!

No hay comentarios :

Publicar un comentario