Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Problema con transformaciones

Iniciado por blau, 14 de Agosto de 2010, 01:15:14 PM

« anterior - próximo »

blau

Buenas, estoy implementando haciendo un editor para un juego de plataformas 2D, y me ha surgido un problema con los gizmos.

He implementado un sistema basado en entidades/componentes, ahora mismo hay hechos dos tipos de componentes,
el sprite para ser dibujado, y la transformacion del sprite.  Las transformaciones pueden ser jerarquizadas en un estructura de arbol.
Todo esto funciona bien, los sprites se dibujan correctamente conforme voy actualizando las transformaciones de las que dependen.

Donde tengo el problema,el problema esta en que el gizmo que uso para rotar,escalar y trasladar con el raton, no entiendo por que motivo no lo hace correctamente.

La unica diferencia esta en que el sprite lo dibujo con el spritebatch, y la ultima transformacion la aplica el spritebatch, y en el gizmo me voy  directamente a la transformacion absoluta para generar los ejes y pintarlo a pelo con un drawuserprimitives para las lineas y con un spritebatch sin aplicarle matriz de transformacion para los cuadraditos de seleccion.


Bueno, pongo codigo, este es mi manager de transformaciones, tengo varios tipos de transformaciones, porque las he clasificado, en tres segun pueden tener padre y si van a necesitar calcular sus matrices o no, pero la que nos atañe es esta:

Código (csharp) [Seleccionar]

public class Bone2DManager : Transform2DManager
   {
       public static readonly Bone2DManager DefaultManager = new Bone2DManager();

       List<int>[] Children;

       Set<int> DirtyDataLocal = new Set<int>();
       Set<int> DirtyDataAbsolute = new Set<int>();

       int BuildCount = 0;

       Bone2DManager()            
       {
           Children = new List<int>[Transforms.Length];
           for (int i = 0; i < Transforms.Length; i++)
           {
               Children[i] = new List<int>(1);
           }
       }      

       public override void Draw(GameTime gametime) { }

       public override void Update(GameTime gametime)
       {
           BuildCount++;
           // Local transform
           foreach (int index in DirtyDataLocal)
           {
               if ( Transforms[index].BuildMode == BuildModes.Translation)
               {
                   Transforms[index].Local.M41 = Transforms[index].Position.X;
                   Transforms[index].Local.M42 = Transforms[index].Position.Y;
               }
               else
               {
                   Transforms[index].Local =
                       Matrix.CreateScale(Transforms[index].Scale, Transforms[index].Scale, 1)
                       * Matrix.CreateRotationZ(Transforms[index].Rotation)
                       * Matrix.CreateTranslation(Transforms[index].Position.X, Transforms[index].Position.Y, 0);
               }
           }

           DirtyDataLocal.Clear();

           // Absolute transform
           foreach(int index in DirtyDataAbsolute)
           {                
               RecursiveBuildAbsoluteMatrix(index);
           }

           DirtyDataAbsolute.Clear();
       }

     
       /// <summary>
       /// Hace una busqueda en profundidad hasta encontrar a su padre, y a la vuelta va actualizando las matrices absolutas
       /// y marcando las que ya estan actualizadas
       /// </summary>
       /// <param name="index"></param>
       /// <param name="Absolute"></param>
       void RecursiveBuildAbsoluteMatrix(int index)
       {

           if (Transforms[index].BuildId == BuildCount) return;   // Si este nodo ya esta calculado nos salimos
           
           int Padre = Transforms[index].ParentId;     // Obtenemos el identificador del padre
   
           if (Padre == Global.InvalidMatrixIdTransform2D)              // Si no hay padre la matriz absoluta es la local
           {
               Transforms[index].Absolute = Transforms[index].Local;
               Transforms[index].BuildId = BuildCount; // Marcamos el nodo como construido
               return;
           }

           // Si el padre esta sucio
           if (DirtyDataAbsolute.Contains(Padre))
           {
               RecursiveBuildAbsoluteMatrix(Padre);  // Probamos a construir la matriz del padre
           }

           // Construimos la matriz absoluta
                       
          Matrix.Multiply(ref Transforms[index].Local, ref Transforms[Padre].Absolute, out Transforms[index].Absolute);

           Transforms[index].BuildId = BuildCount;     // Marcamos la matriz absoluta como construida
       }


Esto pertenece al Sprite2DManager, y es la funcion que se encarga de pintar sprites,
basicamente se ordena todo por layer, por bone de trasnformacion para agrupar las llamadas al spritebatch, y luego se pintan los sprites agrupados por textura.

Código (csharp) [Seleccionar]

public void Draw(GameTime gameTime)
       {
           for (int LayerId = 0; LayerId < (int)RenderLayer.Count; LayerId++)
           {
               foreach (int BoneId in LayersToBoneIds[LayerId])
               {
                   Matrix World = Transforms.Transform2DManager.Transforms[BoneId].Absolute;
                   //!!!-----¡¡¡¡
                   // Habria que establecer los parametros de renderstate segun la capa
                   //!!!-----¡¡¡¡
                   Batch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, World);
                   
                   int BoneLayerId = BoneId | (LayerId << 16);                 // Esto permite que un bone pueda contener sprites de distintas layers
                   int IndexGroup = BoneIdToGroupList[BoneLayerId];            // Obtenemos la lista de sprites agrupada por textura
                   List<Sprite2D> group = GroupList[IndexGroup];               // Obtenemos la lista de sprites agrupada por textura
                   
                   foreach (Sprite2D sprite in group)
                   {
                       Batch.Draw(sprite.Texture, sprite.Transform.Position, null, Color.White, sprite.Transform.Rotation, sprite.Origin, sprite.Transform.Scale, SpriteEffects.None, 1);
                   }

                   Batch.End();
               }
           }
       }


Y este codigo es el que pinta el gizmo:
Código (csharp) [Seleccionar]

      const float Distance = 25;

       Vector2 ObjectAxisX = Vector2.UnitX * Distance;
       Vector2 ObjectAxisY = Vector2.UnitY * Distance;

public override void Draw(GameTime gameTime)
       {
           Transform2D Transform = EditorComponent.Instancia.Selected as Transform2D;

           if (Transform == null) return;

           // Lineas
           Lineas.Instancia.AddLine3D(Transform.AbsoluteMatrix, new Vector3(ObjectAxisX.X, ObjectAxisX.Y, 0), Vector3.Zero, Color.Red);
           Lineas.Instancia.AddLine3D(Transform.AbsoluteMatrix, new Vector3(ObjectAxisY.X, ObjectAxisY.Y, 0), Vector3.Zero, Color.Green);
           
           Vector2 PosX, PosY, PosXY;

           PosX = Vector2.Transform(ObjectAxisX, Transform.AbsoluteMatrix);
           PosY = Vector2.Transform(ObjectAxisY, Transform.AbsoluteMatrix);
           PosXY = Vector2.Transform(Vector2.Zero, Transform.AbsoluteMatrix);

           float scale = 2 * (Radio * 2) / (OperationModeTextures[(int)OperationMode].Width);
           
           Vector2 origin;
           origin.X = OperationModeTextures[(int)OperationMode].Width;
           origin.Y = OperationModeTextures[(int)OperationMode].Height;

           Batch.Begin();
           // Cuadraditos para seleccionar con el raton
           Batch.Draw(Texture, PosX, null, XX.Color, 0, Vector2.One * 0.5f, Radio * 2, SpriteEffects.None, 1);
           Batch.Draw(Texture, PosY, null, YY.Color, 0, Vector2.One * 0.5f, Radio * 2, SpriteEffects.None, 1);
           
           // Muestra de la operacion de transformacion seleccionada en el origen del gizmo
           Batch.Draw(OperationModeTextures[(int) OperationMode], PosXY, null, XY.Color, 0, origin * 0.5f, scale, SpriteEffects.None, 1);
           Batch.End();
       }



Y esta es la configuracion inicial de la escena:
Código (csharp) [Seleccionar]

 prueba4.Components.First<Bone2D>().IdParent = 3;
 prueba4.Components.First<Bone2D>().Position = new Vector2(100, 100);
 prueba3.Components.First<Bone2D>().IdParent = 2;
 prueba3.Components.First<Bone2D>().Position = new Vector2(100, 100);
 prueba3.Components.First<Bone2D>().RotationDegrees = 45;
 prueba2.Components.First<Bone2D>().RotationDegrees = 45;
 prueba2.Components.First<Bone2D>().Position = new Vector2(100, 100);



blau

#1
Vale, no hacedme caso, algunos de los problemas que tenia ya están solucionados.

No multiplicaba en el orden correcto las matrices al calcular las absolutas.

Y el otro problema que tenia era un paso por valor que estaba mal calculado, y accediendo directamente por indexación a la tabla de matrices lo he resuelto.

Ahora ya solo me queda que hacer el movimiento del gizmo con el ratón correctamente.

Cuando lo haga subiré lo que llevo hecho por si alguien quiere hacer critica "constructiva". ;)

Edit:

   Aqui el enlace para la descarga http://astro.estanuestraweb.com/deploy/publish.rar
 
   Para editar una transformacion seleccionarla en el panel de la izquierda y aparecera el gizmo y el de los ancestros.
    Si haces click en el origen del gizmo cambias la transformacion entre escala, traslacion y rotacion.
    Arrastrando los cuadraditos de los ejes ejecutas la operacion.
    Tambien puedes arrastrar el origen.







Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.