Animationen funktionieren nur synchron

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Marcel78
Beiträge: 3
Registriert: 12.07.2009, 18:11
Wohnort: Wilhelmshaven
Kontaktdaten:

Animationen funktionieren nur synchron

Beitrag von Marcel78 »

Hallo,

bin mit C++ und DirectX 9 dabei animierte X-Files in mein Spiel zu bringen. Soweit hat es geklappt, leider bewegen sich alle Modelle synchron.
Hab das nach dem SkinnedMesh Sample programmiert, durch das MultiAnimation Sample steig ich nicht durch.
Mesh wird so geladen:

Code: Alles auswählen

CAllocateHierarchy Alloc;
D3DXLoadMeshHierarchyFromX( mod[0].dateiname, D3DXMESH_MANAGED, g_pd3dDevice, &Alloc, NULL, &g_pFrameRoot, &g_pAnimControl );
SetupBoneMatrixPointers( g_pFrameRoot );
Alle Meshes teilen sich g_pFrameRoot. Für's Zeichnen nehm ichfolgenden Code, wobei AnimController der jeweilige geklonte Controller für das entsprechende Mesh ist.

Code: Alles auswählen

AnimController->AdvanceTime( TimeDelta, NULL );
UpdateFrameMatrices( g_pFrameRoot, &matWorld );
DrawFrame( g_pd3dDevice, g_pFrameRoot );
Die Controller lassen sich auch einzeln ansprechen, jeder einzelne funktioniert aber immer für alle Meshes gleichzeitig. Die Sample-Beschreibung sagt mir auch nur, dass es mit getrennten Controllern unabhängig funktionieren soll.
Jemand eine Idee was ich falsch machen könnte? Vielleicht hab ich das Prinzip ja nicht richtig verstanden...

Gruß, Marcel
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4260
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Animationen funktionieren nur synchron

Beitrag von Chromanoid »

EDIT: Nach nochmal in Ruhe durchlesen deines threads, scheint es mir, dass du genau das machst was ich beschrieben habe... Vielleicht funktioniert das Clone nicht, weil an den richtigen Stellen keine deepcopy gemacht wird... Schau einfach mal rein und lass dich nicht irritieren, wenn das ganze so schon von dir gemacht wird... :)
Wie erzeugst du denn deine Modell-Referenzen? Also bei dem SkinnedMesh Beispiel braucht glaube ich jede "Modell-Instanz" einen eigenen AnimationPlayer. Den musst du einfach mit
animationPlayer=new AnimationPlayer(skinningData);
initialisieren...
animationClips = skinningData.AnimationClips;
und dann
animationPlayer.StartClip(animationClips["idle"])


Ich hab damals mal ne ziemlich hässliche Wrapperklasse für Modelle geschrieben, die sicherlich verbesserungswürdig ist. Kann gut sein, dass die im Grunde zusammmengeklaut ist. Die Notation der Variablen ist grässlich :) finde ich heute jeden falls so ^^. Naja:

Code: Alles auswählen

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using SkinnedModel;

namespace Kloakenmonsterkillerspiel
{
    class SimpleModel
    {
        private Matrix m_xDefaultTransformation=Matrix.Identity;
        public Matrix DefaultTransformation
        {
            get { return m_xDefaultTransformation; }
            set { m_xDefaultTransformation = value; }
        }
        private Effect m_xRenderEffect=null;
        public Effect RenderEffect
        {
            get { return m_xRenderEffect; }
            set { m_xRenderEffect = value; }
        }
        private Model m_xRenderModel=null;
        public Model RenderModel
        {
            get { return m_xRenderModel; }
            set { m_xRenderModel = value; }
        }
        private Vector3 m_xPosition = new Vector3(0.0f, 0.0f, 0.0f);
        public Vector3 Position
        {
            get { return m_xPosition; }
            set { m_xPosition = value; }
        }
        private Vector3 m_xScale= new Vector3(1.0f, 1.0f, 1.0f);
        public Vector3 Scale
        {
            get { return m_xScale; }
            set { m_xScale = value; }
        }
        private Vector3 m_xRotation= new Vector3(0.0f, 0.0f, 0.0f); 
        public Vector3 Rotation
        {
            get { return m_xRotation; }
            set { m_xRotation = value; }
        }
        public Matrix WorldMatrix
        {
            get { return DefaultTransformation * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position) * Matrix.CreateScale(Scale); }
        }
        private AnimationPlayer m_xAnimationPlayer;
        public AnimationPlayer animationPlayer
        {
            get { return m_xAnimationPlayer; }
        }

        private Matrix[] m_xTransforms;
        private EffectParameter m_xWorldMatrixHelper;
        private EffectParameter m_xProjMatrixHelper;
        private EffectParameter m_xViewMatrixHelper;
        private EffectParameter m_xBonesHelper;

        private bool m_bAnimated = false;
        private IDictionary<string,AnimationClip> m_xAnimationClips;
        
        public SimpleModel(Model in_RenderModel, Effect in_RenderEffect, Matrix in_xDefaultTransformation, bool in_bAnimated)
        {
            m_bAnimated = in_bAnimated;
            RenderModel = in_RenderModel;
            RenderEffect = in_RenderEffect;
            if (!(RenderEffect is BasicEffect))            
            {
                m_xWorldMatrixHelper = RenderEffect.Parameters["WorldMatrix"];
                m_xProjMatrixHelper = RenderEffect.Parameters["ProjMatrix"];
                m_xViewMatrixHelper = RenderEffect.Parameters["ViewMatrix"];
            }
            DefaultTransformation = in_xDefaultTransformation;
            m_xTransforms = new Matrix[RenderModel.Bones.Count];
            RenderModel.CopyAbsoluteBoneTransformsTo(m_xTransforms);
            foreach (ModelMesh mesh in RenderModel.Meshes)
            {                
                foreach (ModelMeshPart part in mesh.MeshParts)
                {                    
                    part.Effect = RenderEffect;
                }
            }
            if (m_bAnimated)
            {
                m_xBonesHelper = RenderEffect.Parameters["Bones"];
                SkinningData skinningData = RenderModel.Tag as SkinningData;
                if (skinningData == null)
                    throw new InvalidOperationException
                        ("This model does not contain a SkinningData tag.");
                m_xAnimationPlayer = new AnimationPlayer(skinningData);
                                
                m_xAnimationClips = skinningData.AnimationClips;
                m_xAnimationPlayer.StartClip(m_xAnimationClips["idle"]);                            
            }
        }
        public bool DrawModel(Matrix in_xProjMatrix,Matrix in_xViewMatrix)
        {                       
            Matrix World=WorldMatrix;
            
            foreach (ModelMesh mesh in RenderModel.Meshes)
            {
               
                if (RenderEffect is BasicEffect)
                {
                    ((BasicEffect)RenderEffect).Projection = in_xProjMatrix;
                    ((BasicEffect)RenderEffect).View = in_xViewMatrix;
                    ((BasicEffect)RenderEffect).World = WorldMatrix * m_xTransforms[mesh.ParentBone.Index];
                }
                else
                {
                    m_xProjMatrixHelper.SetValue( in_xProjMatrix);
                    m_xViewMatrixHelper.SetValue(in_xViewMatrix );
                    m_xWorldMatrixHelper.SetValue(WorldMatrix * m_xTransforms[mesh.ParentBone.Index]);
                }
                if (m_bAnimated)
                {
                    m_xBonesHelper.SetValue(animationPlayer.GetSkinTransforms());
                }
                mesh.Draw();
            }
            return true;
        }
        public bool DrawModel(Matrix in_xWorldMatrix,Matrix in_xProjMatrix, Matrix in_xViewMatrix)
        {
            Matrix World = WorldMatrix;

            foreach (ModelMesh mesh in RenderModel.Meshes)
            {

                if (RenderEffect is BasicEffect)
                {
                    ((BasicEffect)RenderEffect).Projection = in_xProjMatrix;
                    ((BasicEffect)RenderEffect).View = in_xViewMatrix;
                    ((BasicEffect)RenderEffect).World = m_xTransforms[mesh.ParentBone.Index]*in_xWorldMatrix;
                }
                else
                {
                    m_xProjMatrixHelper.SetValue(in_xProjMatrix);
                    m_xViewMatrixHelper.SetValue(in_xViewMatrix);
                    m_xWorldMatrixHelper.SetValue(m_xTransforms[mesh.ParentBone.Index]*in_xWorldMatrix);
                }
                if (m_bAnimated)
                {
                    m_xBonesHelper.SetValue(animationPlayer.GetSkinTransforms());
                }
                mesh.Draw();
            }
            return true;
        }
    }
}
Marcel78
Beiträge: 3
Registriert: 12.07.2009, 18:11
Wohnort: Wilhelmshaven
Kontaktdaten:

Re: Animationen funktionieren nur synchron

Beitrag von Marcel78 »

Hallo Chromanoid,

danke für Deine Antwort. Mit XNA kenn ich mich zwar nicht aus, aber vom Prinzip mach ich das wohl so wie Du.

Ich hab mir eine Klasse für die Modellinstanzen erstellt, in der alle möglichen Variablen initialisiert werden. Auch der AnimationController, den klon ich mit "CloneAnimationController". Soll dann immer eine deepcopy sein, so wie ich's gelesen hab. Die lassen sich auch wunderbar ansprechen, kontrollieren dann halt nur alle Instanzen.
Ansonsten kopier ich nichts. Die FrameRoot-Struktur soll laut Microsoft ja von allen Instanzen gemeinsam genutzt werden. Möglicherweise hab ich da was falsch verstanden?

Da gibt's übrigens Bilder vom deformierten Ei in seiner natürlichen Umgebung :P : http://www.marcelmintken.de (unter Programmierung)

Gruß, Marcel
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4260
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Animationen funktionieren nur synchron

Beitrag von Chromanoid »

Hi :)
Lol hab irgendwie übersehen, dass du ja gar nicht mit XNA arbeitest... Mal wieder Tunnelblick meinerseits sorry ^^

XNA kann ich übrigens nur empfehlen ^^...

Ich könnte mir vorstellen, dass der AnimationController bei dir dieselben Matrizen updatet (also der Pointer auf die Matrizen bei allen AnimationController gleich ist). Wenn du erst "alle" Matrizen der AnimationController aktualisierst und dann renderst würde bei gleichem Pointer auf die Matrizen immer nur das letzte Objekt die Animation für alle vorgeben...

Bei einem Klon der AnimationController scheinen die Matrizen nicht mit geklont zu werden. Das sagt (glaube ich) folgender Abschnitt aus dem Sample:
Because all instances of Tiny share the same frame hierarchy matrices, the sample must advance time on a specific instance and render it before moving on to another instance. Generally, this does not present a problem. However, if an application wishes to update the matrices for all of the instances first then render them, it can make new animation controllers point to a different set of matrices when cloning. This way, each animation controller has its own set of matrices to work with, and overwriting will not occur, at the expense of more memory usage.
Du könntest zum einen einfach immer erst direkt vorm Rendern einer Figur die Matrizen aktualisieren (und nicht erst alle Matrizen aktualisieren und dann alle Figuren rendern) oder einfach noch mal pro AnimationController eine deepcopy der Matrizen machen....
Marcel78
Beiträge: 3
Registriert: 12.07.2009, 18:11
Wohnort: Wilhelmshaven
Kontaktdaten:

Re: Animationen funktionieren nur synchron

Beitrag von Marcel78 »

Hallo Christian,

vielen vielen Dank für Deine Hilfe, läuft jetzt einwandfrei! :-)
Ich war mir einfach nicht sicher, wo ich ansetzen musste.
Chromanoid hat geschrieben:oder einfach noch mal pro AnimationController eine deepcopy der Matrizen machen....
Das war der richtige Ansatz, nur den AnimationController zu klonen reichte nicht, egal welche Reihenfolge ich benutzt hab. Hatte zum Testen dann einfach das selbe Mesh nochmal geladen, mit anderer Variable für die Frame-Hierarchie, das ging.
Mittlerweile hab ich mir das MultiAnimation-Sample noch mal intensiv angeschaut und die Klassen für's Laden, die Instanzen und die Charaktere selbst implementiert. War ein hartes Stück Arbeit, aber jetzt klappt wie gesagt alles wunderbar. :-) Die Meshes lad ich damit jetzt natürlich nur noch einmal.

Gruß, Marcel
Antworten