Cine y Series Españolas –un desastre muy evitable-

En este post voy a tratar de explicar por qué no me gustan las series Españolas, salvo contadísimas excepciones. Dejando a un margen las comedias facilonas y absurdas (donde no hace falta esmerarse mucho en ningún aspecto, solo hacer reír), y excepciones como “Cuéntame”, que no lo hace tan mal en muchos de los aspectos que comentaremos aquí, las demás son un puñetero desastre. Por muchos motivos.

Empezamos…

1 - Temática

En primer lugar, la originalidad de la temática es, generalmente, nula. Cuando no aprovechan vergonzosamente el tirón de tragedias como la de “Niños Robados”, se limitan a plagiar lo que se hace en USA (tanto en el cine como en la televisión). Este magnífico post deja bien claro de qué hablo. Su autor ha hecho un trabajo genial que me voy a permitir fusilar parcialmente y completar aquí:

Downton Abbey y Gran Hotel

"Downton Abbey" –> "Gran Hotel"

Cheers vs Cheers española

"Cheers" –> "Cheers"

Las chicas de oro originales y las españolas

"Las chicas de oro" –>"Las chicas de oro"

Pirtas

Piratas del Caribe –> "Piratas"… Hasta el cartel y el logo son plagios…

Series policiacas

"CSI", "El mentalista" –> "Génesis: en la mente del asesino" u "Homicidios"

image

"Falcon Crest" –> "Gran reserva"

Los protegidos = Héroes + Los Serrano

"Héroes" –> "Los protegidos"

Ángel o Demonio vs Crepúsculo

"Crepúsculo" –> "Ángel o demonio"

Doctor Mateo vs Doctor en Alaska vs House

"House" + "Doctor en Alaska" = "Doctor Mateo"

"Urgencias" –> "Hospital Central"

image

"Prison Break" –> "La fuga"

image

"Perdidos" + "Waterworld" = "El barco".

Roma vs Hispania

"Roma" –> "Hispania"

image

"Los Borgia" –> “Los Borgia”

image

"Los Tudor" –> "Toledo"

13313_340970587478_5031791_n[1]

Assasin’s Creed –> Águila Roja

image

Mr. Selfridge –> Galerías Velvet

image

Revenge –> Sin identidad

En fin, ¿algo que añadir? Yo me quedo sin palabras al ver esto…

2 – Actores y guionistas

En cuanto a series británicas y americanas, muchas veces las veo en versión original. Pero incluso cuando no es así y a la interpretación del actor le han calzado por encima la voz de otro, incluso en esos casos suelo creerme lo que veo. Por lo general, los actores americanos y británicos se meten muchísimo más en el papel. Para ellos, lo primero es que la interpretación resulte creíble, por encima de su imagen. Estudian el personaje, la forma de hablar de la época, la forma de moverse y expresarse. Se asesoran, y se concentran plenamente en ello. Los actores españoles, salvo excepciones, dejan mucho que desear en todos estos aspectos. Y eso resta realismo.

Si a eso le sumamos que los guiones muchas veces son de risa, pues poco podemos hacer. Cuando veo algún episodio de series como Aguila Roja y compañía, me muero de risa al ver cómo hablan los personajes. Parece que están en el “insti”, colega…

Señores, es muy poco probable que en la antigua Roma, o incluso en el siglo XVII, se hablara así. Y eso resta realismo.

3.- Estética

Yo entiendo que un actor vive de su imagen, y que le joda que le saquen feo. Pero señores, esos peinados seguro que no existían hace 600 años. Esa ropita inmaculada, esas manos de manicura y ese cutis impoluto (con una media barba cuidada para engañar), ese cuero recién salido de la tienda. Esos tejidos modernos que no encajan hace 2000 años. Es que no tienen ni una mancha, oigan… Y eso resta realismo.

Mientras que en EEUU han evolucionado de esto:

Robin-Hood-Errol-Flynn-002

a esto:

En España seguimos igual que estaban ellos hace 50 años. ¿Os fijáis en la imagen de Russel Crowe? Pelo desaliñado, sudado y sangrando, con las manos llenas de mierda y la ropa rota y sucia.

 

Casi casi igual que en Águila Roja:

Camisa blanca inmaculada, manicura perfecta (leñe, hasta hoy en día la gente tiene más roña en la uñas), capa de tejido industrial que SEGURO no existía en el XVII… En fin, que parece que va disfrazado de carnavales. Y eso resta realismo.

4 - Luz, color y formato

Todo lo mencionado en el apartado 3 sería disimulable si las productoras españolas eligieran mejor los formatos y se aplicaran un poquito en la etapa de post-producción.

Entiendo que no tenga sentido en “Los Serrano” o en “La que se avecina”, pero si quieres rodar una serie de aspecto cinematográfico como “Hispania” u otras, por el amor de Dios, rueda SIEMPRE en 16:9 o mejor aún, en 21:9.

Y lo que es aún más importante: la luz y el color. Es necesario trabajar muchísimo la iluminación. Y esto es, muchas veces, bastante asequible, de hecho. Solo hay que empeñarse, y tener un mínimo de conocimientos.

Un ejemplo: el siguiente video muestra parte de los decorados de Rivendell, en El Señor de Los Anillos. Como está grabado in-situ, con una cámara normal y sin post-producción, podréis apreciar que, de hecho, son bastante cutres. Se nota a la legua que son de cartón piedra o de papel pintado, muy al estilo de las series españolas. Entonces, qué marca la diferencia?

La luz. El color. La ambientación. Los planos. La post-producción. Como veis, no se trata de construir un castillo o un palacio de verdad, piedra a piedra. Y para muestra, un botón:

5.- Ejemplo

Vamos a coger todos los aspectos mencionados en los anteriores apartados, y vamos a aplicarlos a un fotograma de Águila Roja. En concreto a éste:

Es un plano triste, en el que el muchacho parte cabizbajo con un saco al hombro, con sus pertenencias. El formato es correcto (16:9), pero sin embargo, la ambientación, la luz y el color escogidos para el rodaje denotan todo lo contrario a lo que se pretende: alegría, verano, naturaleza, limpieza, aire fresco.

imageSi os fijáis en alguien que sabe hacer las cosas, como Peter Jackson… ¿En qué planos de El Señor de los Anillos utilizó este tipo de luz? ¿Acaso cuando Frodo partía de casa de Bilbo en medio del drama que se le venía encima? No. La utilizó en los primeros planos, en los que se muestra la comarca como un lugar idílico. Cuando todavía no hay problema alguno, y todo va bien. Con una música jovial y risueña, con todos los personajes pasándolo bien y sonriendo. Ahí sí encaja esa puesta en escena (ver a la derecha). Pero no aquí. Han escogido una configuración que no ayuda absolutamente nada a transmitir el dramatismo del momento. En definitiva, están restando credibilidad. Por muy bien que lo haga el chaval. Por muy bien que actúe. No hay nada que hacer, la escena está perdida solo por no tener cuidado con éstas cosas.

En este caso, lo ideal hubiera sido rodar en un día nublado, o mejor aún, con una lluvia que aumentara el dramatismo. Pero dado que ya no es posible cambiar eso, nos fijaremos en lo demás: queremos transmitir tristeza, frialdad. Por lo que habrá que usar colores mucho más azules y fríos, como éstos:

image

Además, añadiremos algo que debería estar presente en TODOS los planos de un rodaje que pretende aparentar ser del siglo XVII: imperfecciones. Las imperfecciones deben estar por todas partes (peinados, ropa, ambientación), y añadirlas a los fotogramas como un proceso de post-producción también ayuda. Sin estar reñido con rodar en FullHD, o resolución 4K, si la imagen está un poquito sucia, un pelín “vieja”, ayudar a transmitir la sensación adecuada. Por eso, añadiremos un par de filtros para acrecentar este efecto:

image

También vamos a romperle un poco la ropa y ensuciarlo, que todos los días veo niños que salen del colegio más sucios que eso… Si la comparas, verás que esta imagen es muchísimo más triste que la inicial (incluida de nuevo abajo):

image

El original:

6 - Otro ejemplo

Con las caras pasa más de lo mismo. No importa cómo de bueno sea el actor, si la ambientación y el maquillaje no ayudan, no tiene nada que hacer. Lo siento, pero Francis Lorenzo, por muy buen actor que sea, no tiene una cara extremadamente dramática.

El peinado tampoco ayuda. Ni el maquillaje. Ni la ausencia total de manchas e imperfecciones. Nuevamente, ¿qué buscan los productores? ¿Que el señor Lorenzo salga fantástico, o que su serie resulte creíble?

Para saber cómo dotar a una cara de más personalidad, o de más fuerza, solo hay que ver este vídeo:

Conclusión

La HBO y la NBC están demostrando que se puede hacer series realmente alucinantes, con calidad cinematográfica, y que se puede ganar mucho dinero con ello. No hay más que ver Juego de Tronos, Érase una vez, o la inminente Revolution:

No creo que en España no haya actores o guionistas de calidad. Si se empeñan, saben hacerlo. Pero hay que escoger al actor adecuado, escoger un guión adecuado, y olvidarse de salir guapos en la foto. Un guerrero romano era un bárbaro, por definición, y seguro que iba muy sucio. Además, Llongeras todavía no había abierto sucursal en Roma, así que el pelo se lo cortarían a machete… Si cuidamos esas cosas, nos exigimos el máximo, y trabajamos bien la post-producción, sin duda que en España podremos hacer cosas como éstas:

image

O los alucinantes efectos especiales de la segunda temporada:

Creo sinceramente que los productores harían bien en tratar de hacer un único buen proyecto, que les reporte muchos millones, que empeñarse en hacer muchas pequeñas versiones abaratadas, plagiadas y cutres de lo que hacen los demás. Se gastan millonadas para obtener un rédito muy dudoso, haciendo un producto que podría mejorarse notablemente simplemente con poner un poquito de atención.

Una pena…

Properly calculating the diffuse contribution of lights in HLSL Shaders

It’s been many years since Vertex and Pixel Shaders came out, and several years too since the Fixed Pipeline is deprecated, but there are still many questions in the forums out there asking about how to properly calculate the diffuse contribution of Lights. This paper has a great tutorial about the issue, and includes a whole Shader that mimics the Fixed Pipeline behavior. However, we will see here how to perform just the basic calculations, just in case you don’t need to emulate the full pipeline.
First thing is to write some D3D9 code that allows you to switch from the old Fixed Pipeline and your own Shaders, using the same parameters. Doing so, you will easily find any behavior differences in light calculations. You can read more about how D3D9 Fixed Pipeline calculates lighting in this page.
When writing shaders, people tend to calculate the diffuse contribution like:
Out.Color = (materialAmbient * lightAmbient) + (materialDiffuse * lightDiffuse * dot(Normal, L));
Where L is the vector from the vertex position (in world coordinates) to the light.
Apart from not doing any specular or emissive calculations (which could not be necessary in many cases, depending on your scenario), there are several mistakes in that approach:
1.- You don’t want the dot to return negative values, because it will black out colors wrongly. So, you need to clamp it to the 0..1 range, using the saturate operator: saturate(dot(Normal, L))
2.- In order to get the same results as the Fixed Pipeline, you should include Attenuation calculations, because they modify the intensity of light with the distance between the point being lit and the light source. Attenuation (as opposed to what its name suggests), not only attenuates light, but also can increase intensity in some circumstances. (See below how to properly calculate attenuation factors)
3.- Once you are calculating attenuation, you should remove the materialDiffuse factor from the previous equation, as you don’t want it to be attenuated too. You will apply it later, when the entire lighting contribution is properly calculated and attenuated.
Keeping those 3 things in mind, the final calculation in a vertex shader would be:
    float4 LightContrib = (0.f, 0.f, 0.f, 0.f);
    float fAtten = 1.f;

    // 1.- First, we store the total ambient light in the scene (multiplication of material_ambient, light_ambient, and any other global ambient component)
    Out.Color = mMaterialAmbient * mLightAmbient;

    // 2.- Calculate vector from point to Light (both normalized and not-normalized versions, as we might need to calculate its length later)
    float pointToLightDif = mLightPos - P;
    float3 pointToLightNormalized = normalize(pointToLightDif);
    
    // 3.- Calculate dot product between world_normal and pointToLightNormalized
    float NDotL = dot(Nw, pointToLightNormalized);        
    if(NDotL > 0)
    {
        LightContrib = mLightDiffuse * NDotL * mLightDivider;     
            
        float LD = length(pointToLightDif);        
        if(LD > mLightRange)
            fAtten = 0.f;
        else
            fAtten = 1.f/(mLightAtt0 + mLightAtt1*LD + mLightAtt2*LD*LD);
        
        LightContrib *= fAtten;
    }
    Out.Color += LightContrib * mMaterialColor;
    Out.Color = saturate(Out.Color);

 

Comparison

First image is the Programmable version. You can slightly tell it by the reflections on the windows.
image
Second image is the Fixed Pipeline version (no real time reflections on windows):
image

Simax Simulator to be used by the DGT as a diagnostic tool for brain damage

The DGT (Dirección General de Tráfico www.dgt.es), the Spanish organization in charge of traffic legislation and the Imserso (www.imserso.es), the Spanish Institute for the third age and social services, are using one of our Simax Simulators to test the ability to drive on people suffering from some kind of brain damage. The simulator allows them to safely drive through a real environment and to interact with other drivers, while the system automatically monitors and evaluates the way they drive, presenting a complete report with possible failures. Then, experts process that information, along with the results of other tests, to determine if the driver should be suggested to continue driving or not.

More info at: www.simaxvirt.com

[Please navigate to minute 36 to access to the info]

 

Simulador Simax como herramienta de diagnóstico para personas con daño cerebral (minuto 36)

La DGT (Dirección General de Tráfico), así como el Imserso (Instituto de Mayores y Servicios Sociales), están utilizando uno de nuestros simuladores Simax para evaluar la habilidad para conducir en personas que han sufrido algún tipo de daño cerebral. El simulador permite a dichas personas conducir de forma totalmente segura por un entorno real, e interactuar con otros conductores, mientras evalúa y monitoriza automáticamente el modo en que conducen, para presentar finalmente un completo informe con los posibles fallos cometidos durante el proceso. Entonces, expertos en la materia analizan dichos resultados, conjuntamente con los de otros tests realizados, para determinar si es aconsejable que esa persona siga conduciendo o no.

Más información en: www.simaxvirt.com

Cómo controlar el orden de propiedades o categorías en un PropertyGrid

El control PropertyGrid es fantástico para crear herramientas de prototipado rápido, donde podamos cambiar propiedades de objetos de forma rápida y visual. Como ya sabrás, el espacio de nombres System.ComponentModel contiene multitud de atributos y herramientas para personalizar el modo en que las propiedades se agrupan y configuran dentro de un PropertyGrid.

De forma automática, las propiedades se ordenan alfabéticamente según su DisplayName, o se agrupan por categorías (y se aplica el mismo criterio alfabético dentro de éstas) si así lo selecciona el usuario. Lamentablemente, no existe una forma sencilla de poder controlar manualmente el orden de las propiedades o de las categorías.

Existen muchas formas distintas de lograrlo, pero casi todas implican escribir código. Un workaround sencillo, efectivo, y que no implica utilizar código adicional es el siguiente:

1.- Dentro del atributo DisplayName de cada propiedad, o dentro del nombre de cada categoría (atributo Category),  añadiremos por delante tantos caracteres especiales de tipo \u200B como posiciones queramos “subir” dicha propiedad o categoría hacia arriba. Dicho carácter identifica un espacio vacío de longitud 0, por lo que en la práctica no modificará el texto que se muestra en la propiedad, pero sí afectará al algoritmo de ordenación.

En el siguiente ejemplo, se muestra un objeto con dos propiedades Width y Height. De forma natural (por orden alfabético), Height aparecería antes que Width. Para modificar ese comportamiento y lograr el orden inverso, mucho más natural, solo tendremos que modificar los atributos como sigue:

        [Category("Layout")]
        [DisplayName("\u200B\u200BWidth")]
        public float Width
        {
            get { return mWidth; }
            set { mWidth = value; }
        }
        [Category("Layout")]
        [DisplayName("\u200BHeight")]
        public float Height
        {
            get { return mHeight; }
            set { mHeight = value; }
        }

Así, logramos un PropertyGrid correctamente ordenado, como el de la siguiente ilustración:

image

2.- Debemos asegurarnos de que el PropertyGrid utiliza una fuente que soporte dicho carácter, ya que no todas lo hacen. Por ejemplo, la fuente por defecto Microsoft Sans Serif 8.25 lo soporta perfectamente. No obstante, si queréis aseguraros de forma programática de que la fuente es correcta, podéis utilizar este código:

        public UIEditor()
        {
            InitializeComponent();

            this.propertyGrid1.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Regular);
        }

La importancia de la codificación binaria de Shaders en DirectX o Silverlight

Si alguna vez te has topado con un Vertex o Pixel Shader que al menos en apariencia es correcto, pero que sin embargo produce errores al compilar, ten en cuenta que la codificación utilizada para salvar el texto afecta.

Como ya sabrás, por mucho que un archivo contenga texto, en el disco duro de tu ordenador se almacena como datos binarios. Y para ello, es necesario escoger uno de los muchos métodos existentes para transformar el texto a binario, y vice-versa.

Si abrimos un archivo de texto con una herramienta de análisis Hexadecimal, como HxD, podremos observar que los primeros bytes del mismo determinan su codificación. Por ejemplo, la siguiente ilustración muestra un fichero con la cabecera EF BB BF, que determina que el fichero utiliza codificación UTF-8 (la codificación por defecto en Visual Studio).

image

Podéis encontrar más información sobre cabeceras de archivos de texto aqui.

Lamentablemente, el compilador de Shaders de DirectX solo admite determinados tipos de codificación, y UTF-8 no está entre ellos. Por eso, por mucho que el código de ese shader sea correcto, si tratamos de compilarlo recibiremos el siguiente error (u otros, dependiendo del entorno en el que nos encontremos):

“X3000: Illegal character in shader file“

Si esto sucede, solo tenemos que cambiar la codificación con la que se salva el archivo a disco, utilizando una sencilla opción de Visual Studio (Archivo->Opciones avanzadas de Salvado):

image

Aqui, podremos escoger qué codificación utilizar para guardar el archivo. Por ejemplo, podemos escoger “Western European (Windows) – Codepage 1252”, que es una codificación ASCII simple, para que el compilador de shaders funcione correctamente:

image

Mas info:

http://blog.pixelingene.com/2008/07/file-encodings-matter-when-writing-pixel-shaders/

http://www.cplotts.com/2008/08/22/encodings-matter-with-fx-files/

Conduce un simulador Simax Bentley Continental GT V8

Como parte de la promoción del Campeonato del Mundo FIA GT1 que tendrá lugar la semana que viene en el Circuito de Navarra, estos días tenéis la oportunidad de rodar virtualmente con un Bentley Continental GT V8 a los mandos de un simulador Simax. En el Parque Comercial Galaria (c.c. La Morea) - Pamplona -

WP_000252

Bentley Continental GT V8 Simulator, by Simax

Ayer lanzamos un video sobre el último producto Simax: el simulador del nuevo Bentley Continental GT V8, utilizado por la marca en la premiere mundial para prensa especializada este año. Tuvo gran aceptación entre gente como Tiff Needell (Fifth Gear), Frank Marcus (MotorTrend USA) o Guy Smith (ganador de LeMans 2003). Este último estuvo casi 2 horas conduciendo en el simulador, bajando tiempos vuelta tras vuelta. Más info en: www.simaxvirt.com

--

Yesterdary, we released a video about the latest Simax product: the Bentley Continental GT V8 simulator, which was used by the brand in the world press premiere last February. People like Tiff Needell (Fifth Gear), Frank Marcus (MotorTrend USA) or Guy Smith (2003 LeMans winner) had the chance to try it. Mr. Smith was driving for almost 2 hours in the sim, getting better and better times each lap. More info at: www.simaxvirt.com

Developing a MatrixStack in pure managed C# code (ready for XNA)

Some time ago, we already talked about the possibility of creating your own Math library directly in C#, with no native code. If you take enough care, it can be as fast as performing interop with a native one.
Today, we are showing an additional example on this matter, and we are going to develop our own fast MatrixStack class, all in safe C# code, with no COM interop.

Why?

I never understood well why the MatrixStack class remains to be an iDisposable COM object. Don´t know what kind of optimizations it has internally that justify having disposable resources, but it’s annoying to have the iDisposable overhead with no need for it.
Besides that, MatrixStacks are used in most cases as simple matrix helpers, to traverse object hierarchies. So, replacing the API MatrixStack with your own one should be a piece of cake, and will definitely help you if trying to port your code to some other platform.
Last, but not least, XNA does not have a MatrixStack class. So this C# implementation fits perfectly on it for all that want to use it.
I this example, I will be comparing my own class with the SlimDX MatrixStack, which is nothing more than a wrapper over the D3DX Matrix Stack.

The interface

In order to make the SlimDX stack replacement painless, I will keep the exact same interface in my class (except the COM-related stuff, which is no longer necessary). So, it will have to be something like this:
image

How it works

A MatrixStack, basically supplies a mechanism to enable matrices to be pushed onto and popped off of a matrix stack. Implementing a matrix stack is an efficient way to track matrices while traversing a transform hierarchy.
So, we can clear the stack to the Identity or to any other matrix, we can operate with the top of the stack, and we can add (push) or remove (pop) nodes (or levels, if you want) to the stack.
Example: for a robot arm hierarchy, we would go like this:

1.- Initialize the stack, and load the matrix of the first node in the hierarchy (the upper arm, for example). Now you can use the Top matrix to draw the upper arm.
2.- Create another level on the stack (Push) for the lower arm, and multiply the lower arm matrix. Use the Top matrix to draw the lower arm.
3.- Create another level on the stack (Push) for the hand, and multiply the hand matrix. Use the Top matrix to draw the hand.
The stack itself does nothing you cannot do with regular Matrix multiplications, except that it keeps track of the previous levels you have been creating. So you can go back to the upper node whenever you want. After the previous operations, for instance, if we perform a Pop, we would remove the top node of the stack, and go back to the previous. This way, the new Top node would represent the lower arm matrix, instead of the hand matrix.

The code

Here is my implementation of the MatrixStack. Please keep in mind that it has not been intensively tested, and might contain errors. Use it at your own risk:
    public class MatrixStack
    {
        /// <summary>
        /// Retrieves the Top node matrix of the stack
        /// </summary>
        public Matrix Top = Matrix.Identity;        
        public object Tag = null;
        private List<Matrix> mStack = new List<Matrix>();
        
        /// <summary>
        ///
        /// </summary>
        public MatrixStack()
        {
            LoadIdentity();
        }
        /// <summary>
        /// Clears the stack and loads the Identity Matrix in the top of the stack
        /// </summary>
        public void LoadIdentity()
        {
            mStack.Clear();
            Top = Matrix.Identity;
        }
        /// <summary>
        /// Clears the Stack, and loads the matrix in the top of the stack
        /// </summary>
        /// <param name="pMat"></param>
        public void LoadMatrix(Matrix pMat)
        {
            mStack.Clear();
            Top = pMat;
        }
        /// <summary>
        /// Adds a new level to the stack, cloning the current TOP matrix of the stack
        /// </summary>
        public void Push()
        {
            mStack.Add(Top);
        }
        /// <summary>
        /// Removes the current TOP matrix of the stacks, returning back to the previous one
        /// </summary>
        public void Pop()
        {
            if (mStack.Count > 0)
            {
                Top = mStack[mStack.Count - 1];
                mStack.RemoveAt(mStack.Count - 1);                
            }
        }
        /// <summary>
        /// This method right-multiplies the given matrix to the current matrix (transformation is about the current world origin).
        /// This method does not add an item to the stack, it replaces the current matrix with the product of the current matrix and the given matrix.
        /// </summary>
        /// <param name="pMat"></param>
        public void MultiplyMatrix(Matrix pMat)
        {
            Matrix.Multiply(ref Top, ref pMat, out Top);
        }
        /// <summary>
        /// This method left-multiplies the given matrix to the current matrix (transformation is about the local origin of the object).
        /// This method does not add an item to the stack, it replaces the current matrix with the product of the given matrix and the current matrix.
        /// </summary>
        /// <param name="pMat"></param>
        public void MultiplyMatrixLocal(Matrix pMat)
        {
            Matrix.Multiply(ref pMat, ref Top, out Top);            
        }      
        /// <summary>
        /// Rotates (relative to world coordinate space) around an arbitrary axis.
        /// </summary>
        public void RotateAxis(Vector3 pAxis, float pAngle)
        {
            Matrix tmp;
            Matrix.RotationAxisAngle(ref pAxis, pAngle, out tmp);
            Matrix.Multiply(ref Top, ref tmp, out Top);           
        }
        /// <summary>
        /// Rotates (relative to world coordinate space) around an arbitrary axis.
        /// </summary>
        public void RotateAxisLocal(Vector3 pAxis, float pAngle)
        {
            Matrix tmp;
            Matrix.RotationAxisAngle(ref pAxis, pAngle, out tmp);
            Matrix.Multiply(ref tmp, ref Top, out Top);           
        }
        /// <summary>
        /// Rotates (relative to world coordinate space) the specified Euler Angles
        /// </summary>
        public void RotateYawPitchRoll(float pYaw, float pPitch, float pRoll)
        {
            Matrix tmp;
            Matrix.CreateFromYawPitchRoll(pYaw, pPitch, pRoll, out tmp);
            Matrix.Multiply(ref Top, ref tmp, out Top);            
        }
        /// <summary>
        /// Rotates (relative to world coordinate space) the specified Euler Angles
        /// </summary>
        public void RotateYawPitchRollLocal(float pYaw, float pPitch, float pRoll)
        {
            Matrix tmp;
            Matrix.CreateFromYawPitchRoll(pYaw, pPitch, pRoll, out tmp);
            Matrix.Multiply(ref tmp, ref Top, out Top);           
        }
        /// <summary>
        /// Scale the current matrix about the world coordinate origin
        /// </summary>
        public void Scale(float pX, float pY, float pZ)
        {
            Matrix tmp;
            Matrix.CreateScale(pX, pY, pZ, out tmp);
            Matrix.Multiply(ref Top, ref tmp, out Top);
        }
        /// <summary>
        /// Scale the current matrix about the world coordinate origin
        /// </summary>
        public void ScaleLocal(float pX, float pY, float pZ)
        {
            Matrix tmp;
            Matrix.CreateScale(pX, pY, pZ, out tmp);
            Matrix.Multiply(ref tmp, ref Top, out Top);           
        }
        /// <summary>
        /// Determines the product of the current matrix and the computed translation matrix determined by the given factors (x, y, and z).
        /// </summary>
        public void Translate(float pX, float pY, float pZ)
        {
            Matrix tmp;
            Matrix.CreateTranslation(pX, pY, pZ, out tmp);
            Matrix.Multiply(ref Top, ref tmp, out Top);           
        }
        /// <summary>
        /// Determines the product of the current matrix and the computed translation matrix determined by the given factors (x, y, and z).
        /// </summary>
        public void TranslateLocal(float pX, float pY, float pZ)
        {
            Matrix tmp;
            Matrix.CreateTranslation(pX, pY, pZ, out tmp);
            Matrix.Multiply(ref tmp, ref Top, out Top);
        }
    }

It has to be fast

When you start coding your own MatrixStack, you will soon realize that .Net includes a Generic Collection called Stack. You can use it, although I didn’t. Why?
Because I have separated the management of the Top Matrix of the stack to a member variable, and for the rest I just preferred to use a simple list to keep track of the previous nodes.
The Top Matrix is stored as a member variable to be able to pass it By Reference to the Matrix Multiplication methods. The speed increase avoiding to pass a whole matrix by value is significant. In the example below, it was around a 40% faster.

Test 1 – Reliability

I just made several random operations with the matrix stack, trying to test some of its features by comparing the end Top Matrix, both with a SlimDX MatrixStack and my own. The test operations are:
matrixStack.LoadIdentity();
matrixStack.MultiplyMatrix(Matrix.PerspectiveFovLH(0.8f, 1.6f, 0.1f, 999f));
matrixStack.Translate(10, 10, 10);
matrixStack.Scale(2, 2, 2);
matrixStack.RotateYawPitchRoll(1f, 0f, 0f);
matrixStack.RotateAxis(Vector3.UnitY, 0.75f);
matrixStack.Push();
matrixStack.TranslateLocal(-5, -5, -5);
matrixStack.ScaleLocal(0.1f, 0.1f, 0.1f);
matrixStack.Pop();
matrixStack.MultiplyMatrixLocal(Matrix.RotationZ(1.45f));
The resulting top matrix is:
SlimDX MatrixStack:
  1. [M11:-0.06350367 M12:4.695973 M13:-0.3505643 M14:0]
  2. [M21:0.5231493 M22:0.5700315 M23:2.887983 M24:0]
  3. [M31:18.08297 M32:20 M33:-23.60117 M34:1]
  4. [M41:-0.1968169 M42:0 M43:0.03565279 M44:0]
MyMatrixStack:
  1. {M11:-0.06350368 M12:4.695973 M13:-0.3505643 M14:0}
  2. {M21:0.5231493 M22:0.5700315 M23:2.887982 M24:0}
  3. {M31:18.08297 M32:20 M33:-23.60117 M34:1}
  4. {M41:-0.1968169 M42:0 M43:0.0356528 M44:0}
As you can see, the result is exactly the same.

Test 2 - Speed

Speed is important, so I decided to run the above mentioned operation 10 million times, to se how long it takes to complete both using SlimDX and my own code.
Obviously, if we run in Debug mode (disabling optimizations), there will be a huge performance difference, as the SlimDX dll is already compiled with optimizations. But what happens if we turn all optimizations on when compiling our code?
Here is the result of a small test application:
image
As you can see, the .Net Framework alone is faster than SlimDX, thanks to its optimizations and to the absence of the interop layer.
What happens if we increase the number of iterations to 60 million? The difference is obviously bigger (1.36 seconds faster):
image
Note: This test has been done on an intel i7 CPU at 3.8 Ghz, running on Windows 7 x64 with .Net Framework 4.0.
Note2: SlimDX MatrixStack uses its own Matrix class and operations. My implementation uses my own Matrix implementation, also written in pure C# code.
Conclusion: .Net Rocks. A purely native C++ code would be even faster of course, but if you put in the equation the huge amount of benefits .Net will give you, I really think it’s worth it. Don’t you think?
Cheers !

New XNA 4.0 book by Packt Publishing

Packt has released a new book on XNA 4.0 development: XNA 4.0 Game Development by Example: Beginner's Guide – Visual Basic Edition.

2403EXP_XNA%204_0%20Game%20Developement%20by%20Example

I think I will have the chance to review the book, so I’ll tell you more when I’ve read it, but it looks promising. Seems to be a must for anyone that is facing XNA 4.0 development in Visual Basic.

Cheers !

Simax to develop the Bentley Continental GT V8 Simulator

During the last month, Bentley has been presenting the new Continental GT V8 at the Circuit of Navarra.

SimaxBentley_DiarioDeNavarra_Low

Simax was there, testing the car and working in the development of an accurate simulation, to be introduced in the Simax driving simulators permanently installed at the circuit, so journalists could test the car both virtually and in the real track.

After several days working with Bentley experts to tune up the simulated car, the result has been pretty impressive. Now, journalists from all around the globe, like Tiff Needell, from Fifth Gear (in the picture, driving one of our simulators) are coming to the event.

P1010404_Low

There were also some professional drivers there, like the LeMans 2003 Winner Guy Smith, who was driving in our simulator for almost one hour and a half. It was a pleasure to hear his impressions, and I must say, he really liked the sim.

P1010372_Low