Sunday, July 26, 2009

Nueva 4k

Pues eso, hemos terminado una nueva 4k. Las criticas no han sido buenas, y quedamos segundos. Ademas, para añadirle insulto, es la 4k a la que posiblemente he dedicado mas tiempo. Vaya, un fiasco, no? No creáis. Voy a contar porqué.

Hace 2 años exactos, decidí dejar de producir. Acababa de volver de la Euskal, habíamos ganado la competición de 4k, y yo solo podía sentir frustración por la producción con la que habíamos ganado: mucho material reutilizado y hecha con desgana. El hecho que ganara solo añadió insulto al asunto. Ya entonces consideraba seriamente que no producía al nivel que podía hacerlo, al menos en lo que respecta a técnica. Hacer cosas abstractas esta bien una temporada, pero después de unos años...

Decidí dejar de producir hasta que no pusiera todo mi empeño en una producción. Hace algo menos de un año empecé con la versión final de la Let yourself go, ya que creía que merecía un poco de amor antes de olvidarla para siempre. La idea era pillar carrerilla en algo orientado a la demoscene, y luego empezar algo nuevo. Siempre con la idea de volver a producir con ganas, y dar lo que pudiera, al menos a nivel técnico.

Y aunque el resultado de la otopoto no sea el que tenía en la cabeza, y siendo consciente que había muchísimas cosas por pulir, puedo levantar la cabeza alto y sentirme orgulloso de haber trabajado en ella a consciencia. Obviamente, el resultado artístico deja que desear, pero técnicamente tiene detalles interesantes. En la próxima tengo que recordar centrarme mas en la parte artística, como hacía con las producciones mas abstractas.

Solo para notar como las prisas finales hicieron recortar en calidad, comparad los 2 shots siguientes. El primero es el de la prod a una semana de la party, el segundo de la versión presentada en la party:


No mucho mas que comentar al respecto, si alguien quiere mas detalles, que comente y le responderé lo mejor que sepa.

A parte, en esta euskal también di una charla sobre 4k. Hubo cosas que funcionaron muy bien y otras que no. A parte, estaba algo nervioso, pues la sala estaba MUY llena (50-70 personas) y no había ensayado la charla tan a fondo como hubiera querido. Tenéis, de momento, el audio y las diapositivas usadas aquí. A final de verano saldrá el vídeo de la charla, cuando esté disponible ya lo comentaré por aquí.

Friday, July 03, 2009

Hoy, snippets cortos de código

Viendo como OpenGL va a deprecar parte del API (cosa que me parece bien, a ver si conseguimos mejores drivers!), y la costumbre de programar cosas de mas que tenemos algunos, he creído que alguien le seria útil. Funcionan 100% igual que las funciones de la API (misma matriz, etc). Empezaré por el mas trivial (la implementación es directa respecto a la documentación), crear una matriz de proyección ortográfica, con los mismos parámetros que gluOrtho:

   1:  CMatrix4x4 CreateOrtographicProj (float left,   float right, 
   2:                                    float bottom, float top, 
   3:                                    float Near,   float zFar)
   4:  {
   5:   CMatrix4x4 result;
   6:
   7:   float  tx = -(right+left)/(right-left),
   8:          ty = -(top+bottom)/(top-bottom),
   9:          tz = -(zFar+zNear)/(zFar-zNear);
  10:
  11:   result.Set (2.f/(right-left), 0.f,              0.f,               tx,
  12:               0.f,              2.f/(top-bottom), 0.f,               ty,
  13:               0.f,              0.f,             -2.f/(zFar-zNear),  tz,
  14:               0.f,              0.f,              0.f,               1.f);
  15:
  16:   return result;
  17:  }

Como apunte, en todos los snippets de codigo usan ciertas clases matemáticas sencillas que uso, en esta la clase matriz cuadrada de 4 elementos. Si hay alguna duda sobre esto, comentadlo y expando los detalles sobre ellas. A efectos prácticos, podéis suponer que CMatrix4x4::Set (...) es equivalente a ir asignando a un array de floats de 16 elementos: el primer parámetro seria el primer elemento del array, el segundo parámetro el segundo elemento, etc.

En segundo lugar, proyección en perspectiva, equivalente a gluPerspective:

   1:  CMatrix4x4 CreatePerspectiveProj (float fovy,  float aspect, 
   2:                                    float zNear, float zFar)
   3:  {
   4:   float f    = tanf (((fovy/180.f)*(float)M_PI) / 2.0f);
   5:   float div  = (zNear-zFar);
   6:
   7:   f   = IsFloatEqual(f, 0.f) ? FLT_MAX : 1.f / f;
   8:   div = IsFloatEqual(div, 0.f) ? FLT_MAX : 1.f / div;
9:
  10:   CMatrix4x4 result;
  11:
  12:   result.Set (f / aspect, 0.f,   0.f,              0.f,
  13:               0.f,          f,   0.f,              0.f,
  14:               0.f,        0.f,   (zFar+zNear)*div, (2.f*zFar*zNear)*div,
  15:               0.f,        0.f,  -1.f,              0.f);
  16:
  17:   return result;
  18:  }

A comentar, la macro IsFloatEqual solo compara dos números en coma flotante: el método normalmente mas recomendado (pero menos rápido, obviamente), es restarlos, coger el valor absoluto, y comparar si es menor que cierto epsilon. Esto se hace así debido a que por precisión de los numeros en coma flotante, comparar con numeros exactos (por ejemplo, haciendo float == 0.0) es desaconsejable.

Finalmente, el que tiene mas curro, el gluLookAt (sobretodo, porque la documentación obvia ciertos detalles):

   1:  CMatrix4x4 CreateLookAt (const CVector3 &eye,
   2:                           const CVector3 &center, 
   3:                           const CVector3 &up)
   4:  {
   5:   CVector3 f      (center-eye);
   6:   CVector3 upLocal(up);
   7:
   8:   f.Normalize();
   9:   upLocal.Normalize();
  10:
  11:   CVector3 s = f ^ upLocal;
  12:   CVector3 u = s ^ f;
  13:
  14:   s.Normalize();
  15:   u.Normalize();
  16:
  17:   CMatrix4x4 result, translate;
  18:
  19:   result.Set ( s.x,  s.y,  s.z, 0.f,
  20:                u.x,  u.y,  u.z, 0.f,
  21:               -f.x, -f.y, -f.z, 0.f,
  22:                0.f,  0.f,  0.f, 1.f);
  23:
  24:   translate.SetTranslation (eye*-1.f);
  25:
  26:   return result*translate;
  27:  }

A ver, destacar de este snippet, que el operador^ de la clase CVector3 equivale a hacer un producto vectorial (cross product), que el método Normalize hace lo inferible del nombre (es decir, normaliza el vector usando su modulo), y que el método SetTranslation de la clase CMatrix4x4, simplemente asigna a una traslación a la matriz (en este caso, al ser una matriz identidad, simplemente creamos una matriz de traslación).

No he explicado a fondo que hace cada parte, para eso tenéis los links a la documentación de OpenGL, y si hay mas preguntas mejor dejad comentarios.

La licencia de este código es la obvia y clásica haced lo que os dé la gana con él. Si encontrais algun bug, comentarlo y aprendemos todos de ello :)