/// <summary> /// Prepara una nueva animacion para ser ejecutada /// </summary> protected void initAnimationSettings(string animationName, bool playLoop, float userFrameRate) { isAnimating = true; currentAnimation = animations[animationName]; this.playLoop = playLoop; currentTime = 0; currentFrame = 0; //Cambiar BoundingBox boundingBox = currentAnimation.BoundingBox; updateBoundingBox(); //Si el usuario no especifico un FrameRate, tomar el default de la animacion if (userFrameRate == -1f) { frameRate = (float)currentAnimation.FrameRate; } else { frameRate = userFrameRate; } //La duracion de la animacion. animationTimeLenght = ((float)currentAnimation.FramesCount - 1) / frameRate; //Configurar postura inicial de los huesos for (int i = 0; i < bones.Length; i++) { TgcSkeletalBone bone = bones[i]; if (!currentAnimation.hasFrames(i)) { throw new Exception("El hueso " + bone.Name + " no posee KeyFrames"); } //Determinar matriz local inicial TgcSkeletalAnimationFrame firstFrame = currentAnimation.BoneFrames[i][0]; bone.MatLocal = Matrix.RotationQuaternion(firstFrame.Rotation) * Matrix.Translation(firstFrame.Position); //Multiplicar por matriz del padre, si tiene if (bone.ParentBone != null) { bone.MatFinal = bone.MatLocal * bone.ParentBone.MatFinal; } else { bone.MatFinal = bone.MatLocal; } } //Ajustar vertices a posicion inicial del esqueleto updateMeshVertices(); }
/// <summary> /// Actualiza la posicion de cada hueso del esqueleto segun sus KeyFrames de la animacion /// </summary> protected void updateSkeleton() { for (int i = 0; i < bones.Length; i++) { TgcSkeletalBone bone = bones[i]; //Tomar el frame actual para este hueso List <TgcSkeletalAnimationFrame> boneFrames = currentAnimation.BoneFrames[i]; //Solo hay un frame, no hacer nada, ya se hizo en el init de la animacion if (boneFrames.Count == 1) { continue; } //Obtener cuadro actual segun el tiempo transcurrido float currentFrameF = currentTime * frameRate; //Ve a que KeyFrame le corresponde int keyFrameIdx = getCurrentFrameBone(boneFrames, currentFrameF); this.currentFrame = keyFrameIdx; //Armar un intervalo entre el proximo KeyFrame y el anterior TgcSkeletalAnimationFrame frame1 = boneFrames[keyFrameIdx - 1]; TgcSkeletalAnimationFrame frame2 = boneFrames[keyFrameIdx]; //Calcular la cantidad que hay interpolar en base al la diferencia entre cuadros float framesDiff = frame2.Frame - frame1.Frame; float interpolationValue = (currentFrameF - frame1.Frame) / framesDiff; //Interpolar traslacion Vector3 frameTranslation = (frame2.Position - frame1.Position) * interpolationValue + frame1.Position; //Interpolar rotacion con SLERP Quaternion quatFrameRotation = Quaternion.Slerp(frame1.Rotation, frame2.Rotation, interpolationValue); //Unir ambas transformaciones de este frame Matrix frameMatrix = Matrix.RotationQuaternion(quatFrameRotation) * Matrix.Translation(frameTranslation); //Multiplicar por la matriz del padre, si tiene if (bone.ParentBone != null) { bone.MatFinal = frameMatrix * bone.ParentBone.MatFinal; } else { bone.MatFinal = frameMatrix; } } }
/// <summary> /// Cargar estructura de animacion /// </summary> private TgcSkeletalAnimation loadAnimation(TgcSkeletalMesh mesh, TgcSkeletalAnimationData animationData) { //Crear array para todos los huesos, tengan o no keyFrames List <TgcSkeletalAnimationFrame>[] boneFrames = new List <TgcSkeletalAnimationFrame> [mesh.Bones.Length]; //Cargar los frames para los huesos que si tienen for (int i = 0; i < animationData.bonesFrames.Length; i++) { TgcSkeletalAnimationBoneData boneData = animationData.bonesFrames[i]; //Crear frames for (int j = 0; j < boneData.keyFrames.Length; j++) { TgcSkeletalAnimationBoneFrameData frameData = boneData.keyFrames[j]; TgcSkeletalAnimationFrame frame = new TgcSkeletalAnimationFrame( frameData.frame, new Vector3(frameData.position[0], frameData.position[1], frameData.position[2]), new Quaternion(frameData.rotation[0], frameData.rotation[1], frameData.rotation[2], frameData.rotation[3]) ); //Agregar a lista de frames del hueso if (boneFrames[boneData.id] == null) { boneFrames[boneData.id] = new List <TgcSkeletalAnimationFrame>(); } boneFrames[boneData.id].Add(frame); } } //BoundingBox de la animación, aprovechar lo que viene en el XML o utilizar el de la malla estática TgcBoundingBox boundingBox = null; if (animationData.pMin != null && animationData.pMax != null) { boundingBox = new TgcBoundingBox( TgcParserUtils.float3ArrayToVector3(animationData.pMin), TgcParserUtils.float3ArrayToVector3(animationData.pMax)); } else { boundingBox = mesh.BoundingBox; } //Crear animacion TgcSkeletalAnimation animation = new TgcSkeletalAnimation(animationData.name, animationData.frameRate, animationData.framesCount, boneFrames, boundingBox); return(animation); }
/// <summary> /// Cargar estructura de animacion /// </summary> private TgcSkeletalAnimation loadAnimation(TgcSkeletalMesh mesh, TgcSkeletalAnimationData animationData) { //Crear array para todos los huesos, tengan o no keyFrames List<TgcSkeletalAnimationFrame>[] boneFrames = new List<TgcSkeletalAnimationFrame>[mesh.Bones.Length]; //Cargar los frames para los huesos que si tienen for (int i = 0; i < animationData.bonesFrames.Length; i++) { TgcSkeletalAnimationBoneData boneData = animationData.bonesFrames[i]; //Crear frames for (int j = 0; j < boneData.keyFrames.Length; j++) { TgcSkeletalAnimationBoneFrameData frameData = boneData.keyFrames[j]; TgcSkeletalAnimationFrame frame = new TgcSkeletalAnimationFrame( frameData.frame, new Vector3(frameData.position[0], frameData.position[1], frameData.position[2]), new Quaternion(frameData.rotation[0], frameData.rotation[1], frameData.rotation[2], frameData.rotation[3]) ); //Agregar a lista de frames del hueso if (boneFrames[boneData.id] == null) { boneFrames[boneData.id] = new List<TgcSkeletalAnimationFrame>(); } boneFrames[boneData.id].Add(frame); } } //BoundingBox de la animación, aprovechar lo que viene en el XML o utilizar el de la malla estática TgcBoundingBox boundingBox = null; if (animationData.pMin != null && animationData.pMax != null) { boundingBox = new TgcBoundingBox( TgcParserUtils.float3ArrayToVector3(animationData.pMin), TgcParserUtils.float3ArrayToVector3(animationData.pMax)); } else { boundingBox = mesh.BoundingBox; } //Crear animacion TgcSkeletalAnimation animation = new TgcSkeletalAnimation(animationData.name, animationData.frameRate, animationData.framesCount, boneFrames, boundingBox); return animation; }