Example #1
1
	public static AnimationCurve CreateCurve( float[] values, float[] times, bool smooth = true)
	{
		D.Assert( values != null && times != null, "Param == null" );
		D.Assert( values.Length == times.Length, "Size not same" );
		if ( values.Length != times.Length ){
			D.Log("values.Length: {0}   times.Length: {1}", values.Length, times.Length);
		}
		
		AnimationCurve result;
		Keyframe[] ks = new Keyframe[values.Length];
		for( int i = 0; i < values.Length; i ++ ) {
			ks[ i ] = new Keyframe( times[ i ], values[ i ] );
		}
		result = new AnimationCurve( ks );
		if ( smooth){
			for( int i = 0; i < result.length; i++ ) {
				result.SmoothTangents( i, 0 );
			}
		}
		return result;
	}
Example #2
0
    /// <summary>
    /// Create drift orbit
    /// </summary>
    public void Drift(Vector3 origin, float speed, out AnimationCurve[] ac)
    {
        Keyframe[][] kf = new Keyframe[2][];
        kf[X] = new Keyframe[driftPoints + 2];
        kf[Y] = new Keyframe[driftPoints + 2];

        kf[X][0] = new Keyframe(0, origin.x, inTangent, outTangent);
        kf[Y][0] = new Keyframe(0, origin.y, inTangent, outTangent);

        for (int i = 1; i <= driftPoints; i++)
        {
            kf[X][i] = new Keyframe(i / speed, origin.x + (driftX * Random.value), inTangent, outTangent);
            kf[Y][i] = new Keyframe(i / speed, origin.y + (driftY * Random.value), inTangent, outTangent);
        }

        kf[X][driftPoints + 1] = new Keyframe((driftPoints + 1) / speed, origin.x, inTangent, outTangent);
        kf[Y][driftPoints + 1] = new Keyframe((driftPoints + 1) / speed, origin.y, inTangent, outTangent);

        // Curves
        ac = new AnimationCurve[2];
        ac[X] = new AnimationCurve(kf[X]);
        ac[Y] = new AnimationCurve(kf[Y]);

        // Smooth curves
        for (int i = 0; i < ac[X].keys.Length; ++i)
        {
            ac[X].SmoothTangents(i, 0);
            ac[Y].SmoothTangents(i, 0);
        }
    }
    void Start()
    {
        GameObject.Find("GUI Text").guiText.text = "AnimationClip sample";

        AnimationClip clipA = new AnimationClip();
        AnimationCurve curveA = AnimationCurve.Linear(0f, 3f, 3f, 3f);
        Keyframe keyA = new Keyframe(1.5f, 10f);
        curveA.AddKey(keyA);
        clipA.SetCurve("", typeof(Transform), "localPosition.z", curveA);
        clipA.wrapMode = WrapMode.Loop;
        animation.AddClip(clipA, "anim1");

        AnimationClip clipB = new AnimationClip();
        AnimationCurve curveB = AnimationCurve.Linear(0f, 3f, 3f, 3f);
        Keyframe key1 = new Keyframe(0.75f, 7f);
        curveB.AddKey(key1);
        Keyframe key2 = new Keyframe(1.5f, 3f);
        curveB.AddKey(key2);
        Keyframe key3 = new Keyframe(2.25f,7f);
        curveB.AddKey (key3);
        clipB.SetCurve("", typeof(Transform), "localPosition.z", curveB);
        clipB.wrapMode = WrapMode.Loop;
        animation.AddClip(clipB, "anim2");

        animation.Play ("anim1");
    }
    // Use this for initialization
    void Start()
    {
        GameObject[] ob_cubes;

        ob_cubes = GameObject.FindGameObjectsWithTag("ob_cube");

        foreach (GameObject obj in ob_cubes)
        {
            Vector3 move = obj.transform.position;
            AnimationClip clip = new AnimationClip();
            clip.legacy = true;
            Keyframe[] keysX = new Keyframe[2];
            keysX[0] = new Keyframe(0f, move.x - 5);
            keysX[1] = new Keyframe(1f, move.x + 3);
            AnimationCurve curveX = new AnimationCurve(keysX);
            clip.SetCurve("", typeof(Transform), "localPosition.x", curveX);
            clip.wrapMode = WrapMode.PingPong;
            Keyframe[] keysY = new Keyframe[2];
            keysY[0] = new Keyframe(0f, move.y);
            keysY[1] = new Keyframe(1f, move.y);
            AnimationCurve curveY = new AnimationCurve(keysY);
            clip.SetCurve("", typeof(Transform), "localPosition.y", curveY);
            Keyframe[] keysZ = new Keyframe[2];
            keysZ[0] = new Keyframe(0f, move.z);
            keysZ[1] = new Keyframe(1f, move.z);
            AnimationCurve curveZ = new AnimationCurve(keysZ);
            clip.SetCurve("", typeof(Transform), "localPosition.z", curveZ);
            Animation animation = obj.GetComponent<Animation>();
            animation.AddClip(clip, "clip1");
            animation.Play("clip1");
        }
    }
Example #5
0
        public void Test_New2()
        {
            var frame = new Keyframe (1, new Vector3(1,2,3));

            Assert.AreEqual (1, frame.Time);
            Assert.AreEqual (new Vector3(1,2,3), frame.Value);
        }
Example #6
0
    void SetLoupiotteAproach()
    {
        AnimationClip clip = new AnimationClip();
        Keyframe[] xValues = new Keyframe[5];
        Keyframe[] yValues = new Keyframe[5];
        Keyframe[] zValues = new Keyframe[5];
        Keyframe[] stateValues = new Keyframe[5];
        for (int i = 0; i<5; i++)
        {
            xValues[i] = new Keyframe(i * 3.0f, i < 4 ? Random.Range(-20.0f / (2 * i + 1), 20.0f / (2 * i + 1)) : xReference);
            zValues[i] = new Keyframe(i * 3.0f, i < 4 ? Random.Range(-20.0f / (2 * i + 1), 20.0f / (2 * i + 1)) : zReference);
            stateValues[i] = new Keyframe(i * 3.0f, i < 4 ? 0.0f : 1.0f);
        }

        yValues[0] = new Keyframe(0.0f, 50.0f);
        yValues[1] = new Keyframe(3.0f, 35.0f);
        yValues[2] = new Keyframe(6.0f, 25.0f);
        yValues[3] = new Keyframe(9.0f, 15.0f);
        yValues[4] = new Keyframe(12.0f, yReference);

        AnimationCurve xCurve = new AnimationCurve(xValues);
        AnimationCurve yCurve = new AnimationCurve(yValues);
        AnimationCurve zCurve = new AnimationCurve(zValues);
        AnimationCurve stateCurve = new AnimationCurve(stateValues);
        clip.legacy = true;
        clip.SetCurve("", typeof(Loupiotte), "positionToPlayer.x", xCurve);
        clip.SetCurve("", typeof(Loupiotte), "positionToPlayer.y", yCurve);
        clip.SetCurve("", typeof(Loupiotte), "positionToPlayer.z", zCurve);
        clip.SetCurve("", typeof(Loupiotte), "state", stateCurve);

        anim.AddClip(clip, "Approche");
    }
Example #7
0
	public static AnimationCurve CreateLineraCurve( float[] values, float[] times )
	{
		D.Assert( values != null && times != null, "Param == null" );
		D.Assert( values.Length == times.Length, "Size not same" );
		
		AnimationCurve result;
		Keyframe[] ks = new Keyframe[values.Length];
		for( int i = 0; i < values.Length; i ++ ) {
			float inTgt;
			float outTgt;
			if ( i == 0){
				inTgt = 0;
			}else{
				inTgt = (values[ i ] - values[i-1])/(times[i] - times[i-1]);
			}
			if ( i == values.Length -1){
				outTgt = 0;
			}else{
				outTgt = (values[ i+1 ] - values[i])/(times[i+1] - times[i]);
			}
			
			ks[ i ] = new Keyframe( times[ i ], values[ i ], inTgt, outTgt );
		}
		result = new AnimationCurve( ks );
		return result;
	}
    void CreateAnimationClip()
    {
        CameraShakeTool tool = target as CameraShakeTool;

        List<Keyframe> keyframeList = new List<Keyframe>();

        foreach (Vector2 v in tool.value)
        {
            Keyframe k = new Keyframe(v.x, v.y);
            keyframeList.Add(k);
        }

        AnimationClip clip = new AnimationClip();
        #if UNITY_5
        clip.legacy = true;
        #endif
        clip.wrapMode = WrapMode.Once;

        clip.SetCurve("", typeof(Transform), "localPosition.x", new AnimationCurve(keyframeList.ToArray()));

        string activePath = AssetDatabase.GetAssetPath(Selection.activeObject);
        string directory = Path.GetDirectoryName(activePath);
        string filename = Path.GetFileNameWithoutExtension(activePath);
        string path = directory + "/" + filename + ".anim";
        string clipPath = AssetDatabase.GenerateUniqueAssetPath(path);

        AssetDatabase.CreateAsset(clip, clipPath);
    }
Example #9
0
			public static float CalculateCurvesPoint(Keyframe[] aCurve, long nFrame)
			{
				if (null == aCurve || 1> aCurve.Length)
					throw new Exception("curve is empty");
				Keyframe[] aInterval=FindInterval(aCurve, nFrame);
				if (1 == aInterval.Length)
				{
					if (aCurve[0] == aInterval[0])
						; // в идеале расчитать экстрапол¤цию за границы диапазона (касательна¤ в ту же сторону)
					if (aCurve[aCurve.Length - 1] == aInterval[0])
						; // в идеале расчитать экстрапол¤цию за границы диапазона (касательна¤ в ту же сторону)
					return aInterval[0].nPosition; // но пока просто остаЄмс¤ на этой точке
				}

				float nRetVal = 0;
				switch (aInterval[0].eType)
				{
					case Keyframe.Type.hold:
						// формула y=A при M<=x<N  
						nRetVal = aInterval[0].nPosition;
						break;
					case Keyframe.Type.linear:
						// формула y=kx+h, где y-пиксели, x-фреймы. M, N - точки на х; A, B - точки на y, то люба¤ точка (PX, FR) <=  PX=((B-A)/(N-M))*(FR-M)+A
						nRetVal = ((aInterval[1].nPosition - aInterval[0].nPosition) / (aInterval[1].nFrame - aInterval[0].nFrame)) * (nFrame - aInterval[0].nFrame) + aInterval[0].nPosition;
						break;
					case Keyframe.Type.besier:
						break;
					default:
						break;
				}
				return nRetVal;
			}
Example #10
0
    void Start()
    {
        moves[0] = new Vector3( 0f, 1f,  0f);
        moves[1] = new Vector3(-3f, 1f,  5f);
        moves[2] = new Vector3( 3f, 1f,  5f);
        moves[3] = new Vector3(-3f, 1f, -3f);
        moves[4] = new Vector3( 3f, 1f, -3f);
        for(int i=0;i<5;i++){
            cubes[i] = GameObject.Find ("BoardCube"+i);
            Vector3 move = cubes[i].transform.position;
            AnimationClip clip = new AnimationClip();
            Keyframe[] keysX = new Keyframe[2];
            keysX[0] = new Keyframe(  0f, move.x-3);
            keysX[1] = new Keyframe(i+1f, move.x+3);
            AnimationCurve curveX = new AnimationCurve(keysX);
            clip.SetCurve("", typeof(Transform), "localPosition.x", curveX);
            clip.wrapMode = WrapMode.PingPong;

            Keyframe[] keysY = new Keyframe[2];
            keysY[0] = new Keyframe(  0f, move.y);
            keysY[1] = new Keyframe(i+1f, move.y);
            AnimationCurve curveY = new AnimationCurve(keysY);
            clip.SetCurve("", typeof(Transform), "localPosition.y", curveY);

            Keyframe[] keysZ = new Keyframe[2];
            keysZ[0] = new Keyframe(  0f, move.z);
            keysZ[1] = new Keyframe(i+1f, move.z);
            AnimationCurve curveZ = new AnimationCurve(keysZ);
            clip.SetCurve("", typeof(Transform), "localPosition.z", curveZ);

            cubes[i].animation.AddClip(clip, "clip1");
            cubes[i].animation.Play("clip1");
        }
    }
Example #11
0
			public static bool CurveIsWrong(Keyframe[] aCurve)
			{
				if (null == aCurve || 1 > aCurve.Length)
					return true;
				else
					return false;
			}
Example #12
0
        public void Test_New1()
        {
            var frame = new Keyframe (1, 2);

            Assert.AreEqual (1, frame.Time);
            Assert.AreEqual (2, frame.Value);
        }
Example #13
0
 public void ApplyPose(Keyframe pose)
 {
     currentPose = pose;
     SetLocalTranslation(pose.GetTranslation());
     poseRot = pose.GetRotation();
     UpdateTransform();
 }
 //  
 public AnimationInstance(Animation anim)
 {
   animation_ = anim;
   frameRate_ = anim.FrameRate;
   //  The time of the last frame is less than the duration of the animation,
   //  as the last frame has some duration itself.
   lastFrameTime_ = (anim.NumFrames - 1) / frameRate_;
   invFrameRate_ = 1.0f / frameRate_;
   duration_ = anim.NumFrames * invFrameRate_;
   int max = 0;
   //  calculate max bone index
   //  todo: do in content pipeline
   foreach (KeyValuePair<int, AnimationTrack> kvp in anim.Tracks)
   {
     if (kvp.Key >= max)
       max = kvp.Key + 1;
   }
   //  Allocate animation keyframes (for lerping between times).
   keyframes_ = new Keyframe[max];
   //  Load all the tracks (one track per bone).
   tracks_ = new AnimationTrack[max];
   foreach (int i in anim.Tracks.Keys)
   {
     keyframes_[i] = new Keyframe();
     tracks_[i] = anim.Tracks[i];
   }
 }
Example #15
0
	public static AnimationCurve CreateCurve( Keyframe[] keyFrames){
		AnimationCurve result;
		result = new AnimationCurve( keyFrames );
		for( int i = 0; i < result.length; i++ ) {
			result.SmoothTangents( i, 0 );
		}
		return result;
	}
 // UnityEditor.CurveUtility.cs (c) Unity Technologies
 public static TangentMode GetKeyTangentMode(Keyframe keyframe, int leftRight)
 {
     Type t = typeof(UnityEngine.Keyframe);
     FieldInfo field = t.GetField("m_TangentMode", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
     int tangentMode = (int)field.GetValue(keyframe);
     if(leftRight == 0)
         return (TangentMode)((tangentMode & 6) >> 1);
     else
         return (TangentMode)((tangentMode & 24) >> 3);
 }
        public override void Init()
        {
            SceneManager.RC = RC;
            var stativ = new SceneEntity("stativ", new ActionCode());
            var dir = new DirectionalLight(new float3(0, 10, -1), new float4(1, 1, 1, 1), new float4(1, 1, 1, 1),
                new float4(1, 1, 1, 1), new float3(0, 0, 0), 0);
            stativ.AddComponent(dir);
            _camera = new Camera(stativ);
            stativ.transform.GlobalPosition = new float3(0, 0, 100);
            SceneManager.Manager.AddSceneEntity(stativ);
            _camera.Resize(Width, Height);
            Geometry wuerfelGeo = MeshReader.ReadWavefrontObj(new StreamReader(@"Assets/Sphere.obj.model"));
            _wuerfel = new SceneEntity("wuerfel", new Material(MoreShaders.GetSpecularShader(RC)),
                new Renderer(wuerfelGeo));
            SceneManager.Manager.AddSceneEntity(_wuerfel);

            _channel2 = new Channel<float3>(Lerp.Float3Lerp);
            _channel1 = new Channel<float4>(Lerp.Float4Lerp, new float4(0.5f, 0.5f, 0.5f, 0.5f));

            var key0 = new Keyframe<float4>(0, new float4(1, 0, 1, 1));
            var key1 = new Keyframe<float4>(2, new float4(0.125f, 1, 0.125f, 1));
            var key2 = new Keyframe<float4>(4, new float4(0.250f, 0.75f, 0.250f, 1));
            var key3 = new Keyframe<float4>(6, new float4(0.5f, 0.5f, 0.5f, 1));
            var key4 = new Keyframe<float4>(8, new float4(0.75f, 0.25f, 0.75f, 1));
            var key5 = new Keyframe<float4>(10, new float4(1, 25, 0.125f, 1));
            var key6 = new Keyframe<float4>(0, new float4(0, 1, 0, 1));

            _channel1.AddKeyframe(key0);
            _channel1.AddKeyframe(key1);
            _channel1.AddKeyframe(key2);
            _channel1.AddKeyframe(key3);
            _channel1.AddKeyframe(key4);
            _channel1.AddKeyframe(key5);
            _channel1.AddKeyframe(key6);

            var key40 = new Keyframe<float3>(8, new float3(8, 0, 80));
            var key00 = new Keyframe<float3>(0, new float3(0, 0, 0));
            var key10 = new Keyframe<float3>(2, new float3(1, 2, 20));
            var key20 = new Keyframe<float3>(4, new float3(2, 4, 40));
            var key30 = new Keyframe<float3>(6, new float3(4, 4, 60));
            var key50 = new Keyframe<float3>(12, new float3(0, 4, 60));
            var key60 = new Keyframe<float3>(0, new float3(8, 8, 8));

            _channel2.AddKeyframe(key00);
            _channel2.AddKeyframe(key10);
            _channel2.AddKeyframe(key20);
            _channel2.AddKeyframe(key30);
            _channel2.AddKeyframe(key40);
            _channel2.AddKeyframe(key50);
            _channel2.AddKeyframe(key60);

            _myAnim.AddAnimation(_channel1, RC, "ClearColor");
            _myAnim.AddAnimation(_channel2, _wuerfel, "transform.GlobalPosition");
        }
Example #18
0
 void Start()
 {
     GameObject.Find ("GUI Text").guiText.text = "AnimationClip sample";
     AnimationClip clip = new AnimationClip ();
     AnimationCurve curve = AnimationCurve.Linear (0f, 3f, 3f, 3f);
     Keyframe key = new Keyframe (1.5f, 7f);
     curve.AddKey (key);
     clip.SetCurve ("", typeof(Transform), "localPosition.z", curve);
     clip.wrapMode = WrapMode.Loop;
     animation.AddClip (clip, "clip1");
     animation.Play ("clip1");
 }
Example #19
0
    public void SetStartPosition()
    {
        if (XPositionCurve.keys.Length < 2)
            XPositionCurve = AnimationCurve.Linear(0,0,1,0);
        if (YPositionCurve.keys.Length < 2)
            YPositionCurve = AnimationCurve.Linear(0,0,1,0);

        StartPostion = transform.position;
        Keyframe keyx = new Keyframe(0, StartPostion.x);
        XPositionCurve.MoveKey(0, keyx);
        Keyframe keyy = new Keyframe(0, StartPostion.y);
        YPositionCurve.MoveKey(0, keyy);
    }
Example #20
0
    public void TestTimelineData()
    {
        Keyframe<KeyframeParams>[] keyframes = new Keyframe<KeyframeParams>[] {
            new Keyframe<KeyframeParams>() { time=0, value=new KeyframeParams() { a=0,b=10 } },
            new Keyframe<KeyframeParams>() { time=0.5f, value=new KeyframeParams() { a=1,b=5 } },
            new Keyframe<KeyframeParams>() { time=0.1f, value=new KeyframeParams() { a=3,b=1 } }
        };

        KeyframeObject keyframeObject = new KeyframeObject();

        Func<int,float,string> formatMsg = (a,b)=>string.Format( "{0}-{1}", a, b );

        Timeline<KeyframeParams,KeyframeObject> timeline = new Timeline<KeyframeParams, KeyframeObject>() {
            timelineEntity=keyframeObject,
            keyframes=keyframes,
            tweenFunction=(p1,p2,t)=>{
                return new KeyframeParams() {
                    a=(int)Lerp(p1.a,p2.a,t),
                    b=Lerp(p1.b,p2.b,t)
                };
            },
            applyKeyframeParameters=(kfo,p)=>kfo.msg = formatMsg(p.a,p.b)
        };

        Assert.AreEqual( -1, timeline.CurrentKeyframeIndex );

        timeline.Update(0);
        Assert.AreEqual( 0, timeline.CurrentKeyframeIndex );
        Assert.AreEqual( formatMsg(0,10), keyframeObject.msg );

        timeline.Update(0.1f);
        Assert.AreEqual( 0, timeline.CurrentKeyframeIndex );
        Assert.AreEqual( formatMsg(0,9f), keyframeObject.msg );

        timeline.Update(0.4f);
        Assert.AreEqual( 0, timeline.CurrentKeyframeIndex );
        Assert.AreEqual( formatMsg(1,5f), keyframeObject.msg );

        timeline.Update(0.1f);
        Assert.AreEqual( 1, timeline.CurrentKeyframeIndex );
        Assert.AreEqual( formatMsg(3,0.999999f), keyframeObject.msg );

        timeline.Update(0.1f);
        Assert.AreEqual( 2, timeline.CurrentKeyframeIndex );
        Assert.AreEqual( formatMsg(0,10f), keyframeObject.msg ); // this frame has no length

        timeline.Update(0.1f);
        Assert.AreEqual( 0, timeline.CurrentKeyframeIndex ); // loop around
        Assert.AreEqual( formatMsg(0,8f), keyframeObject.msg );
    }
Example #21
0
			public static Keyframe[] FindInterval(Keyframe[] aCurve, long nFrame)
			{
				if (aCurve[0].nFrame >= nFrame)
					return new Keyframe[1] { aCurve[0]};
				if (aCurve[aCurve.Length - 1].nFrame <= nFrame)
					return new Keyframe[1] { aCurve[aCurve.Length - 1] };
				for (int ni = 0; ni < aCurve.Length - 1; ni++)
				{
					if (aCurve[ni].nFrame == nFrame)
						return new Keyframe[1] { aCurve[ni] };
					if (aCurve[ni].nFrame > nFrame || aCurve[ni].nFrame < nFrame && aCurve[ni + 1].nFrame > nFrame)
						return new Keyframe[2] { aCurve[ni], aCurve[ni + 1] };
				}
				throw new Exception("impossible to find interval");
			}
Example #22
0
        private static void WriteKeyframe(BinaryWriter writer, Keyframe keyframe)
        {
            writer.Write(keyframe.Time);

            writer.Write(keyframe.ModelPartAnimStates.Count);
            foreach (var modelPartAnimState in keyframe.ModelPartAnimStates)
            {
                WriteModelPartAnimState(writer, modelPartAnimState);
            }

            writer.Write(keyframe.AnchorAnimStates.Count);
            foreach (var anchorAnimState in keyframe.AnchorAnimStates)
            {
                WriteAnchorAnimState(writer, anchorAnimState);
            }
        }
    public static Keyframe GetNewKey(float time, float value, TangentMode left, TangentMode right)
    {
        object boxed = new Keyframe(time, value); // cant use struct in reflection

        SetKeyBroken(boxed, true);
        SetKeyTangentMode(boxed, 0, left);
        SetKeyTangentMode(boxed, 1, right);

        Keyframe keyframe = (Keyframe)boxed;
        if(left == TangentMode.Stepped)
            keyframe.inTangent = float.PositiveInfinity;
        if(right == TangentMode.Stepped)
            keyframe.outTangent = float.PositiveInfinity;

        return keyframe;
    }
Example #24
0
    void Start()
    {
        //カーブを設定
        if(Application.platform == RuntimePlatform.WindowsEditor && generateCurveOnStartEditor)
        {
            Keyframe[] keys = new Keyframe[envelopeKeys.Length];
            for(int i = 0; i < envelopeKeys.Length; i++)
            {
                EnvelopeKey envKey = envelopeKeys[i];
                keys[i] = AnimationCurveUtil.GetNewKey(envKey.time, envKey.value, envKey.leftTangent, envKey.rightTangent);
            }

            envelopeCurve = new AnimationCurve(keys);
            envelopeCurve.preWrapMode = preWrapMode;
            envelopeCurve.postWrapMode = postWrapMode;
            AnimationCurveUtil.UpdateAllLinearTangents(envelopeCurve);
        }
    }
    public void ResampleKeys()
    {
        keysCount = Mathf.Max (keysCount, 2);

        Keyframe[] keys = new Keyframe[keysCount];
        float inv = 1f / (keysCount - 1);
        for (int i = 0; i < keysCount; i++)
        {
            keys[i] = new Keyframe(i * inv, Random.Range(randMin, randMax));
        }

        float firstVal = keys [0].value;
        float lastVal = keys [keys.Length - 1].value;
        float middle = (firstVal + lastVal) * .5f;
        keys [0].value = middle;
        keys [keys.Length - 1].value = middle;

        curve = new AnimationCurve (keys);
    }
 public static AnimationCurve FromXMLtoAnimationCurve(XmlNode node)
 {
     AnimationCurve output = new AnimationCurve();
     if(node == null || !node.HasChildNodes)
     {
         output.AddKey(0, 1);
         output.AddKey(1, 1);
         return output;
     }
     foreach(XmlNode keyframeNode in node.SelectNodes("keyframe"))
     {
         Keyframe keyFrame = new Keyframe();
         keyFrame.inTangent = float.Parse(keyframeNode["inTangent"].FirstChild.Value);
         keyFrame.outTangent = float.Parse(keyframeNode["outTangent"].FirstChild.Value);
         keyFrame.time = float.Parse(keyframeNode["time"].FirstChild.Value);
         keyFrame.value = float.Parse(keyframeNode["value"].FirstChild.Value);
         output.AddKey(keyFrame);
     }
     return output;
 }
Example #27
0
    // Can be called from outside if you want a different seed
    public void ResampleKeys()
    {
        // Make sure there is at least 2 keys
        keysCount = Mathf.Max( keysCount, 2 );

        // Generate the keys randomly
        Keyframe[] keys = new Keyframe[keysCount];
        float inv = 1f / (keysCount-1);
        for( int i = 0; i < keysCount; i++ )
            keys[i] = new Keyframe( i * inv, Random.Range(randMin, randMax) );

        // Make sure the first and last value matches to have a proper loop
        float firstVal = keys[0].value;
        float lastVal = keys[ keys.Length-1 ].value;
        float middle = (firstVal + lastVal) * .5f;
        keys[0].value = middle;
        keys[ keys.Length-1 ].value = middle;

        // Commit
        curve = new AnimationCurve( keys );
    }
Example #28
0
        private Explosion(Texture2D tex, Rectangle position, Rectangle cut)
        {
            if (tex == null)
            {
                Position = position;
                return;
            }
            Sheet = new AnimatedSpriteSheet(tex)
            {
                Rectangle = new Rectangle(0, 0, 32, 32),
                AutoUpdate = true
            };
            Position = position;

            for (var i = 0; i < 12; i++)
            {
                cut.X = 134 * i;
                var kf = new Keyframe(cut, 60f);
                Sheet.Add(kf);
            }
        }
Example #29
0
        private void DoOnTimer(double tickDuration)
        {
            if (m_skipLoops > 0)
            {
                m_skipLoops--;
                return;
            }

            if (m_group == null)
            {
                return;
            }

            bool update = false;

            if (m_selected)
            {
                if (m_group.RootPart.Velocity != Vector3.Zero)
                {
                    m_group.RootPart.Velocity = Vector3.Zero;
                    m_skippedUpdates          = 1000;
//                    m_group.SendGroupRootTerseUpdate();
                    m_group.RootPart.ScheduleTerseUpdate();
                }
                return;
            }

            if (m_isCrossing)
            {
                // if crossing and timer running then cross failed
                // wait some time then
                // retry to set the position that evtually caused the outbound
                // if still outside region this will call startCrossing below
                m_isCrossing             = false;
                m_skippedUpdates         = 1000;
                m_group.AbsolutePosition = m_nextPosition;

                if (!m_isCrossing)
                {
                    StopTimer();
                    StartTimer();
                }
                return;
            }

            double nowMS = Util.GetTimeStampMS();

            if (m_frames.Count == 0)
            {
                lock (m_frames)
                {
                    GetNextList();

                    if (m_frames.Count == 0)
                    {
                        Done();
                        m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId);
                        return;
                    }

                    m_currentFrame = m_frames[0];
                }
                m_nextPosition = m_group.AbsolutePosition;
                m_currentVel   = (Vector3)m_currentFrame.Position - m_nextPosition;
                m_currentVel  /= (m_currentFrame.TimeMS * 0.001f);

                m_currentFrame.TimeMS += (int)tickDuration;
                m_lasttickMS           = nowMS - 50f;
                update = true;
            }

            int elapsed = (int)(nowMS - m_lasttickMS);

            if (elapsed > 3 * tickDuration)
            {
                elapsed = (int)tickDuration;
            }

            m_currentFrame.TimeMS -= elapsed;
            m_lasttickMS           = nowMS;

            // Do the frame processing
            double remainingSteps = (double)m_currentFrame.TimeMS / tickDuration;

            if (remainingSteps <= 1.0)
            {
                m_group.RootPart.Velocity        = Vector3.Zero;
                m_group.RootPart.AngularVelocity = Vector3.Zero;

                m_nextPosition           = (Vector3)m_currentFrame.Position;
                m_group.AbsolutePosition = m_nextPosition;

                m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation;

                lock (m_frames)
                {
                    m_frames.RemoveAt(0);
                    if (m_frames.Count > 0)
                    {
                        m_currentFrame            = m_frames[0];
                        m_currentVel              = (Vector3)m_currentFrame.Position - m_nextPosition;
                        m_currentVel             /= (m_currentFrame.TimeMS * 0.001f);
                        m_group.RootPart.Velocity = m_currentVel;
                        m_currentFrame.TimeMS    += (int)tickDuration;
                    }
                    else
                    {
                        m_group.RootPart.Velocity = Vector3.Zero;
                    }
                }
                update = true;
            }
            else
            {
//                bool lastSteps = remainingSteps < 4;

                Vector3 currentPosition = m_group.AbsolutePosition;
                Vector3 motionThisFrame = (Vector3)m_currentFrame.Position - currentPosition;
                motionThisFrame /= (float)remainingSteps;

                m_nextPosition = currentPosition + motionThisFrame;

                Quaternion currentRotation = m_group.GroupRotation;
                if ((Quaternion)m_currentFrame.Rotation != currentRotation)
                {
                    float      completed = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
                    Quaternion step      = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, completed);
                    step.Normalize();
                    m_group.RootPart.RotationOffset = step;

/*
 *                  if (Math.Abs(step.X - m_lastRotationUpdate.X) > 0.001f
 || Math.Abs(step.Y - m_lastRotationUpdate.Y) > 0.001f
 || Math.Abs(step.Z - m_lastRotationUpdate.Z) > 0.001f)
 ||                     update = true;
 */
                }

                m_group.AbsolutePosition = m_nextPosition;
//                if(lastSteps)
//                    m_group.RootPart.Velocity = Vector3.Zero;
//                else
                m_group.RootPart.Velocity = m_currentVel;

/*
 *              if(!update && (
 * //                    lastSteps ||
 *                  m_skippedUpdates * tickDuration > 0.5 ||
 *                  Math.Abs(m_nextPosition.X - currentPosition.X) > 5f ||
 *                  Math.Abs(m_nextPosition.Y - currentPosition.Y) > 5f ||
 *                  Math.Abs(m_nextPosition.Z - currentPosition.Z) > 5f
 *                  ))
 *              {
 *                  update = true;
 *              }
 *              else
 *                  m_skippedUpdates++;
 */
            }
//            if(update)
//            {
//                m_lastPosUpdate = m_nextPosition;
//                m_lastRotationUpdate = m_group.GroupRotation;
//                m_skippedUpdates = 0;
//                m_group.SendGroupRootTerseUpdate();
            m_group.RootPart.ScheduleTerseUpdate();
//            }
        }
Example #30
0
    void Start()
    {
        int j = 0;

        while (queryBlock(j, 0))
        {
            List <UnityAudioBlock> blocks = new List <UnityAudioBlock>();
            int        k = 0;
            GameObject audioObjectInstance = Instantiate(objectInstance) as GameObject;
            audioObjects.Add(audioObjectInstance);

            while (queryBlock(j, k))
            {
                UnityAudioBlock nextBlock = getBlock(j, k);
                blocks.Add(nextBlock);
                GameObject objectPosition = Instantiate(objectPositionInstance) as GameObject;

                objectPosition.transform.position = new Vector3(nextBlock.x, nextBlock.y, nextBlock.z);
                k++;
            }

            channelFormats.Add(blocks);
            j++;
        }



        for (int y = 0; y < channelFormats.Count; y++)
        {
            GameObject audioObject = audioObjects[y];
            audioObject.AddComponent <Animation>();

            Animation     objectAnimation = audioObject.GetComponent <Animation>();
            AnimationClip clip            = new AnimationClip();
            clip.name   = Encoding.ASCII.GetString(channelFormats[y][0].name);
            clip.legacy = true;

            Keyframe[] xKeys = new Keyframe[channelFormats[y].Count];
            Keyframe[] yKeys = new Keyframe[channelFormats[y].Count];
            Keyframe[] zKeys = new Keyframe[channelFormats[y].Count];

            for (int i = 0; i < channelFormats[y].Count; i++)
            {
                xKeys[i] = new Keyframe(channelFormats[y][i].rTime, channelFormats[y][i].x);
                yKeys[i] = new Keyframe(channelFormats[y][i].rTime, channelFormats[y][i].y);
                zKeys[i] = new Keyframe(channelFormats[y][i].rTime, channelFormats[y][i].z);
            }

            AnimationCurve xCurve = new AnimationCurve(xKeys);
            clip.SetCurve("", typeof(Transform), "localPosition.x", xCurve);

            AnimationCurve yCurve = new AnimationCurve(yKeys);
            clip.SetCurve("", typeof(Transform), "localPosition.y", yCurve);

            AnimationCurve zCurve = new AnimationCurve(zKeys);
            clip.SetCurve("", typeof(Transform), "localPosition.z", zCurve);

            objectAnimation.AddClip(clip, clip.name);
            objectAnimation.Play(clip.name, PlayMode.StopSameLayer);

            xCurve.AddKey(new Keyframe(21.0f, 0.0f));
            yCurve.AddKey(new Keyframe(21.0f, 10.0f));
            zCurve.AddKey(new Keyframe(21.0f, 10.0f));

            clip.SetCurve("", typeof(Transform), "localPosition.x", xCurve);
            clip.SetCurve("", typeof(Transform), "localPosition.y", yCurve);
            clip.SetCurve("", typeof(Transform), "localPosition.z", zCurve);

            objectAnimation.PlayQueued(clip.name, QueueMode.PlayNow, PlayMode.StopAll);

            xCurve.AddKey(new Keyframe(22.0f, 0.0f));
            yCurve.AddKey(new Keyframe(22.0f, 0.0f));
            zCurve.AddKey(new Keyframe(22.0f, 0.0f));

            clip.SetCurve("", typeof(Transform), "localPosition.x", xCurve);
            clip.SetCurve("", typeof(Transform), "localPosition.y", yCurve);
            clip.SetCurve("", typeof(Transform), "localPosition.z", zCurve);

            objectAnimation.PlayQueued(clip.name, QueueMode.PlayNow, PlayMode.StopAll);
        }
    }
        public void LoadLogToExportAnim()
        {
            if (DisplayName == "")
            {
                Debug.LogWarning("DisplayName is null");
                return;
            }
            if (animator == null)
            {
                animator = GetComponent <Animator>();
            }
            string humrPath = @"Assets/HUMR";

            CreateDirectoryIfNotExist(humrPath);

            ControllerSetUp(humrPath);

            string[] files = Directory.GetFiles(OutputLogPath, "*.txt");

            string[]   strOutputLogLines = File.ReadAllLines(files[index]);
            int        nTargetCounter    = 0;
            List <int> newTargetLines    = new List <int>();//ファイルの中での新しく始まった対象の行を格納する

            newTargetLines.Add(0);
            List <int> newLogLines = new List <int>();//抽出したログの中で新しく始まった行を格納する

            newLogLines.Add(0);
            float beforetime = 0;

            for (int j = 0; j < strOutputLogLines.Length; j++)
            {
                //対象のログの行を抽出
                if (strOutputLogLines[j].Contains(strKeyWord + DisplayName))
                {
                    if (strOutputLogLines[j].Length > nHeaderStrNum + (strKeyWord + DisplayName).Length)
                    {
                        //記録終わりを検知
                        string strTmpOLL = strOutputLogLines[j].Substring(nHeaderStrNum + (strKeyWord + DisplayName).Length);
                        for (int k = 0; k < strTmpOLL.Length; k++)
                        {
                            if (strTmpOLL[k] == ',')
                            {
                                float currenttime = float.Parse(strTmpOLL.Substring(0, k));
                                if (currenttime < beforetime)
                                {
                                    newLogLines.Add(nTargetCounter);
                                    newTargetLines.Add(j);
                                }
                                beforetime = currenttime;
                                break;
                            }
                        }
                        nTargetCounter++;//目的の行が何行あるか。
                    }
                    else
                    {
                        Debug.LogWarning("Length is not correct");
                    }
                }
            }
            newLogLines.Add(nTargetCounter);
            newTargetLines.Add(strOutputLogLines.Length);
            // Keyframeの生成
            if (nTargetCounter == 0)
            {
                Debug.LogWarning("Not exist Motion Data with [" + DisplayName + "] (Did you enter correct DisplayName ? or select correct log ?)");
                return;
            }

            for (int i = 0; i < newLogLines.Count - 1; i++)
            {
                int          nLineNum       = newLogLines[i + 1] - newLogLines[i];
                int          nTargetLineNum = newTargetLines[i + 1] - newTargetLines[i];
                Keyframe[][] Keyframes      = new Keyframe[4 * (HumanTrait.BoneName.Length + 1 /*time + hip position*/) - 1 /*time*/][];//[要素数]
                for (int j = 0; j < Keyframes.Length; j++)
                {
                    Keyframes[j] = new Keyframe[nLineNum];//[行数]
                }

                //Keyframeにログの値を入れていく
                {
                    string[] strDisplayNameOutputLogLines = new string[nLineNum];//目的の行の配列
                    int      nTargetLineCounter           = 0;
                    beforetime = 0;
                    for (int j = newTargetLines[i]; j < newTargetLines[i + 1]; j++)
                    {
                        //対象のログの行を抽出
                        if (strOutputLogLines[j].Contains(strKeyWord + DisplayName))
                        {
                            if (strOutputLogLines[j].Length > nHeaderStrNum + (strKeyWord + DisplayName).Length)
                            {
                                strDisplayNameOutputLogLines[nTargetLineCounter] = strOutputLogLines[j].Substring(nHeaderStrNum + (strKeyWord + DisplayName).Length);//時間,position,rotation,rotation,…
                                for (int k = 0; k < strDisplayNameOutputLogLines[nTargetLineCounter].Length; k++)
                                {
                                    if (strDisplayNameOutputLogLines[nTargetLineCounter][k] == ',')
                                    {
                                        float currenttime = float.Parse(strDisplayNameOutputLogLines[nTargetLineCounter].Substring(0, k));
                                        if (currenttime < beforetime)
                                        {
                                            Debug.LogAssertion("new record line is contained");
                                        }
                                        beforetime = currenttime;
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                Debug.LogWarning("Log Length is not correct");
                            }
                            //Debug.Log(DisplayNameOutputLogLines[nTargetLineCounter]);
                            string[] strSplitedOutPutLog = strDisplayNameOutputLogLines[nTargetLineCounter].Split(',');
                            if (strSplitedOutPutLog.Length == 4 * (HumanTrait.BoneName.Length + 1 /*time + hip position*/))
                            {
                                float   key_time      = float.Parse(strSplitedOutPutLog[0]);
                                Vector3 rootScale     = animator.transform.localScale;
                                Vector3 armatureScale = animator.GetBoneTransform((HumanBodyBones)0).parent.localScale;
                                Vector3 hippos        = new Vector3(float.Parse(strSplitedOutPutLog[1]), float.Parse(strSplitedOutPutLog[2]), float.Parse(strSplitedOutPutLog[3]));
                                transform.rotation = Quaternion.identity;                                                                                                                       //Avatarがrotation(0,0,0)でない可能性があるため
                                hippos             = Quaternion.Inverse(animator.GetBoneTransform((HumanBodyBones)0).parent.localRotation) * hippos;                                            //armatureがrotation(0,0,0)でない可能性があるため
                                hippos             = new Vector3(hippos.x / rootScale.x / armatureScale.x, hippos.y / rootScale.y / armatureScale.y, hippos.z / rootScale.z / armatureScale.z); //いる
                                Keyframes[0][nTargetLineCounter] = new Keyframe(key_time, hippos.x);
                                Keyframes[1][nTargetLineCounter] = new Keyframe(key_time, hippos.y);
                                Keyframes[2][nTargetLineCounter] = new Keyframe(key_time, hippos.z);
                                Quaternion[] boneWorldRotation = new Quaternion[HumanTrait.BoneName.Length];
                                for (int k = 0; k < HumanTrait.BoneName.Length; k++)
                                {
                                    boneWorldRotation[k] = new Quaternion(float.Parse(strSplitedOutPutLog[k * 4 + 4]), float.Parse(strSplitedOutPutLog[k * 4 + 5]), float.Parse(strSplitedOutPutLog[k * 4 + 6]), float.Parse(strSplitedOutPutLog[k * 4 + 7]));
                                }
                                for (int k = 0; k < HumanTrait.BoneName.Length; k++)
                                {
                                    if (animator.GetBoneTransform((HumanBodyBones)k) == null)
                                    {
                                        continue;
                                    }
                                    animator.GetBoneTransform((HumanBodyBones)k).rotation = boneWorldRotation[k];
                                }

                                for (int k = 0; k < HumanTrait.BoneName.Length; k++)
                                {
                                    if (animator.GetBoneTransform((HumanBodyBones)k) == null)
                                    {
                                        continue;
                                    }
                                    Quaternion localrot = animator.GetBoneTransform((HumanBodyBones)k).localRotation;
                                    Keyframes[k * 4 + 3][nTargetLineCounter] = new Keyframe(key_time, localrot.x);
                                    Keyframes[k * 4 + 4][nTargetLineCounter] = new Keyframe(key_time, localrot.y);
                                    Keyframes[k * 4 + 5][nTargetLineCounter] = new Keyframe(key_time, localrot.z);
                                    Keyframes[k * 4 + 6][nTargetLineCounter] = new Keyframe(key_time, localrot.w);
                                }
                            }
                            else
                            {
                                Debug.Log(strSplitedOutPutLog.Length);//228
                                Debug.LogAssertion("Key value length is not correct");
                            }
                            nTargetLineCounter++;
                        }
                    }
                }

                //AnimationClipにAnimationCurveを設定
                AnimationClip clip = new AnimationClip();
                {
                    // AnimationCurveの生成
                    AnimationCurve[] AnimCurves = new AnimationCurve[Keyframes.Length];

                    for (int l = 0; l < AnimCurves.Length; l++)//[行数-1]
                    {
                        AnimCurves[l] = new AnimationCurve(Keyframes[l]);
                    }
                    // AnimationCurveの追加
                    clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)0)), typeof(Transform), "localPosition.x", AnimCurves[0]);
                    clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)0)), typeof(Transform), "localPosition.y", AnimCurves[1]);
                    clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)0)), typeof(Transform), "localPosition.z", AnimCurves[2]);
                    for (int m = 0; m < (AnimCurves.Length - 3) / 4; m++)//[骨数]
                    {
                        if (animator.GetBoneTransform((HumanBodyBones)m) == null)
                        {
                            continue;
                        }
                        clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)m)),
                                      typeof(Transform), "localRotation.x", AnimCurves[m * 4 + 3]);
                        clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)m)),
                                      typeof(Transform), "localRotation.y", AnimCurves[m * 4 + 4]);
                        clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)m)),
                                      typeof(Transform), "localRotation.z", AnimCurves[m * 4 + 5]);
                        clip.SetCurve(GetHierarchyPath(animator.GetBoneTransform((HumanBodyBones)m)),
                                      typeof(Transform), "localRotation.w", AnimCurves[m * 4 + 6]);
                    }
                    clip.EnsureQuaternionContinuity();//これをしないとQuaternion補間してくれない
                }

                //GenericAnimation出力
                {
                    string animFolderPath = humrPath + @"/GenericAnimations";
                    CreateDirectoryIfNotExist(animFolderPath);
                    string displaynameFolderPath = animFolderPath + "/" + DisplayName;
                    CreateDirectoryIfNotExist(displaynameFolderPath);

                    string animationName = files[index].Substring(files[index].Length - 13).Remove(9) + "_" + i.ToString();
                    string animPath      = displaynameFolderPath + "/" + animationName + ".anim";
                    Debug.Log(animPath);

                    if (ExportGenericAnimation)
                    {
                        if (File.Exists(animPath))
                        {
                            AssetDatabase.DeleteAsset(animPath);
                            Debug.LogWarning("Same Name Generic Animation is existing. Overwritten!!");
                            foreach (var layer in controller.layers)//アニメーションを消したことにより空のアニメーションステートが出来てたら削除
                            {
                                foreach (var state in layer.stateMachine.states)
                                {
                                    if (state.state.motion == null)
                                    {
                                        layer.stateMachine.RemoveState(state.state);
                                    }
                                }
                            }
                        }
                        AssetDatabase.CreateAsset(clip, AssetDatabase.GenerateUniqueAssetPath(animPath));
                        AssetDatabase.SaveAssets();
                        AssetDatabase.Refresh();
                    }
                }

                //アニメーションをアバターのアニメーターに入れる
                {
                    controller.layers[0].stateMachine.AddState(clip.name).motion = clip;
                }
            }
            //FBXとして出力
            {
                animator.runtimeAnimatorController = controller;
                string exportFolderPath = humrPath + @"/FBXs";
                CreateDirectoryIfNotExist(exportFolderPath);
                string displaynameFBXFolderPath = exportFolderPath + "/" + ValidName(DisplayName);
                CreateDirectoryIfNotExist(displaynameFBXFolderPath);
                UnityEditor.Formats.Fbx.Exporter.ModelExporter.ExportObject(displaynameFBXFolderPath + "/" + files[index].Substring(files[index].Length - 13).Remove(9), this.gameObject);
            }
        }
Example #32
0
        public static string Assemble(KeyframeSequence sequence, List <Bone> rig)
        {
            StudioMdlWriter animWriter = new StudioMdlWriter();
            List <Keyframe> keyframes  = new List <Keyframe>();

            var boneLookup = new Dictionary <string, Bone>();
            var nodes      = animWriter.Nodes;

            foreach (Bone bone in rig)
            {
                Node node = bone.Node;

                if (node != null)
                {
                    string boneName = node.Name;

                    if (!boneLookup.ContainsKey(boneName))
                    {
                        boneLookup.Add(boneName, bone);
                    }

                    nodes.Add(node);
                }
            }

            foreach (Keyframe kf in sequence.GetChildrenOfClass <Keyframe>())
            {
                Pose rootPart = kf.FindFirstChild <Pose>("HumanoidRootPart");

                if (rootPart != null)
                {
                    // We don't need the rootpart for this.
                    foreach (Pose subPose in rootPart.GetChildrenOfClass <Pose>())
                    {
                        subPose.Parent = kf;
                    }

                    rootPart.Destroy();
                }

                kf.Time /= sequence.TimeScale;
                keyframes.Add(kf);
            }

            keyframes.Sort(0, keyframes.Count, sorter);

            Keyframe lastKeyframe = keyframes[keyframes.Count - 1];

            float fLength    = lastKeyframe.Time;
            int   frameCount = ToFrameRate(fLength);

            // As far as I can tell, models in Source require you to store poses for every
            // single frame, so I need to fill in the gaps with interpolated pose CFrames.

            var keyframeMap = new Dictionary <int, Dictionary <string, Pose> >();

            foreach (Keyframe kf in keyframes)
            {
                int frame = ToFrameRate(kf.Time);
                var poses = GatherPoses(kf);

                var poseMap = poses.ToDictionary(pose => pose.Name);
                keyframeMap[frame] = poseMap;
            }

            // Make sure there are no holes in the data.
            for (int i = 0; i < frameCount; i++)
            {
                if (!keyframeMap.ContainsKey(i))
                {
                    var emptyState = new Dictionary <string, Pose>();
                    keyframeMap.Add(i, emptyState);
                }
            }

            List <BoneKeyframe> boneKeyframes = animWriter.Skeleton;

            for (int i = 0; i < frameCount; i++)
            {
                BoneKeyframe frame = new BoneKeyframe(i);
                List <Bone>  bones = frame.Bones;

                if (sequence.AvatarType == AvatarType.R15)
                {
                    frame.BaseRig       = rig;
                    frame.DeltaSequence = true;
                }

                foreach (Node node in nodes)
                {
                    PosePair closestPoses = GetClosestPoses(keyframeMap, i, node.Name);

                    float min = closestPoses.Min.Frame;
                    float max = closestPoses.Max.Frame;

                    float alpha = (min == max ? 0 : (i - min) / (max - min));

                    Pose pose0 = closestPoses.Min.Pose;
                    Pose pose1 = closestPoses.Max.Pose;

                    CFrame lastCFrame = pose0.CFrame;
                    CFrame nextCFrame = pose1.CFrame;

                    Bone   baseBone = boneLookup[node.Name];
                    CFrame interp   = lastCFrame.Lerp(nextCFrame, alpha);

                    // Make some patches to the interpolation offsets. Unfortunately I can't
                    // identify any single fix that I can apply to each joint, so I have to get crafty.
                    // At some point in the future, I want to find a more practical solution for this problem,
                    // but it is extremely difficult to isolate if any single solution exists.

                    if (sequence.AvatarType == AvatarType.R6)
                    {
                        Vector3 pos = interp.Position;
                        CFrame  rot = interp - pos;

                        if (node.Name == "Torso")
                        {
                            // Flip the YZ axis of the Torso.
                            float[] ang = interp.ToEulerAnglesXYZ();
                            rot = CFrame.Angles(ang[0], ang[2], ang[1]);
                            pos = new Vector3(pos.X, pos.Z, pos.Y);
                        }
                        else if (node.Name.StartsWith("Right"))
                        {
                            // X-axis is inverted for the right arm/leg.
                            pos *= new Vector3(-1, 1, 1);
                        }

                        if (node.Name.EndsWith("Arm") || node.Name.EndsWith("Leg"))
                        {
                            // Rotate position offset of the arms & legs 90* counter-clockwise.
                            pos = new Vector3(-pos.Z, pos.Y, pos.X);
                        }

                        if (node.Name != "Head")
                        {
                            rot = rot.Inverse();
                        }

                        interp = new CFrame(pos) * rot;
                    }
                    else if (sequence.AvatarType == AvatarType.R15)
                    {
                        float[] ang = interp.ToEulerAnglesXYZ();

                        // Cancel out the rotations
                        interp *= CFrame.Angles(-ang[0], -ang[1], -ang[2]);

                        // Patch the Y-axis
                        PatchAngles(ref interp, 1, ang);

                        // Patch the Z-axis
                        PatchAngles(ref interp, 2, ang);

                        // Patch the X-axis
                        PatchAngles(ref interp, 0, ang);
                    }

                    Bone bone = new Bone(node, interp);
                    bones.Add(bone);
                }

                boneKeyframes.Add(frame);
            }

            return(animWriter.BuildFile());
        }
Example #33
0
 int KeyframeTimeSort(Keyframe a, Keyframe b) => a.time.CompareTo(b.time);
    public override void OnInspectorGUI()
    {
        Undo.RecordObject(target, "Look Animator Inspector");

        // Update component from last changes
        serializedObject.Update();

        FLookAnimator lookT = (FLookAnimator)target;

        #region Default Inspector
        if (drawDefaultInspector)
        {
            GUILayout.Space(10f);

            EditorGUILayout.BeginVertical(FEditor_Styles.GrayBackground);
            drawDefaultInspector = GUILayout.Toggle(drawDefaultInspector, "Draw default inspector");

            #region Exluding from view not needed properties

            List <string> excludedVars = new List <string>();

            if (lookT.BackBonesCount < 1)
            {
                excludedVars.Add("BackBonesTransforms");
                excludedVars.Add("BackBonesFalloff");
            }

            if (!lookT.AnimateWithSource)
            {
                excludedVars.Add("MonitorAnimator");
            }

            if (lookT.CompensationBones == null || lookT.CompensationBones.Count < 1)
            {
                excludedVars.Add("CompensationWeight");
            }

            #endregion

            GUILayout.Space(5f);

            if (GUILayout.Button("Auto Find Head Bone"))
            {
                FindHeadBone(lookT);
            }
            EditorGUILayout.EndVertical();
            GUILayout.Space(10f);

            if (lookT.BackBonesCount < 0)
            {
                lookT.BackBonesCount = 0;
            }

            // Draw default inspector without not needed properties
            DrawPropertiesExcluding(serializedObject, excludedVars.ToArray());
        }
        else
        #endregion
        {
            EditorGUILayout.BeginVertical(FEditor_Styles.GrayBackground);
            EditorGUILayout.BeginHorizontal();
            drawDefaultInspector = GUILayout.Toggle(drawDefaultInspector, "Default inspector");

            GUILayout.FlexibleSpace();
            EditorGUIUtility.labelWidth = 80;
            lookT.drawGizmos            = GUILayout.Toggle(lookT.drawGizmos, "Draw Gizmos");

            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();

            GUILayout.Space(5f);

            EditorGUILayout.BeginVertical(FEditor_Styles.GrayBackground);
            EditorGUI.indentLevel++;

            drawMain = EditorGUILayout.Foldout(drawMain, "Main Animation Parameters", true);

            #region Main tab

            if (drawMain)
            {
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                if (!lookT.ObjectToFollow)
                {
                    GUILayout.BeginHorizontal(FEditor_Styles.YellowBackground);
                }
                else
                {
                    GUILayout.Space(5f);
                    GUILayout.BeginHorizontal();
                }

                EditorGUIUtility.labelWidth = 133f;

                EditorGUILayout.PropertyField(sp_tofollow);

                GUILayout.EndHorizontal();


                GUILayout.BeginHorizontal();

                if (!lookT.LeadBone)
                {
                    GUILayout.BeginHorizontal(FEditor_Styles.RedBackground);
                }
                else
                {
                    GUILayout.BeginHorizontal();
                }

                EditorGUILayout.PropertyField(sp_leadbone);


                if (lookT.LeadBone != previousHead)
                {
                    previousHead = lookT.LeadBone;

                    lookT.UpdateForCustomInspector();
                }

                if (GUILayout.Button(new GUIContent("Auto Find", "By pressing this button, algorithm will go trough hierarchy and try to find object which name includes 'head' or 'neck', be aware, this bone can not be correct but sure it will help you find right one quicker"), new GUILayoutOption[2] {
                    GUILayout.MaxWidth(90), GUILayout.MaxHeight(15)
                }))
                {
                    FindHeadBone(lookT);
                    EditorUtility.SetDirty(target);
                }

                GUILayout.EndHorizontal();
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();

                if (lookT.BaseTransform != lookT.transform || !lookT.BaseTransform)
                {
                    if (!lookT.BaseTransform)
                    {
                        GUILayout.BeginHorizontal(FEditor_Styles.YellowBackground);
                    }
                    else
                    {
                        GUILayout.BeginHorizontal();
                    }

                    EditorGUILayout.PropertyField(sp_basetr);

                    if (GUILayout.Button("Try Find", new GUILayoutOption[2] {
                        GUILayout.MaxWidth(90), GUILayout.MaxHeight(15)
                    }))
                    {
                        lookT.FindBaseTransform();
                        EditorUtility.SetDirty(target);
                    }

                    GUILayout.EndHorizontal();
                }

                GUILayout.EndHorizontal();
                Color preColor = GUI.color;

                GUILayout.Space(3f);
                EditorGUILayout.PropertyField(sp_rotspd);
                GUILayout.Space(3f);
                if (lookT.BirdMode)
                {
                    GUI.color = new Color(1f, 0.88f, 0.88f, 0.95f);
                }
                EditorGUILayout.PropertyField(sp_usmooth);
                GUI.color = preColor;
                EditorGUILayout.PropertyField(sp_starttpose);


                if (!lookT.Prevent180Error)
                {
                    if (lookT.UltraSmoother > 0f)
                    {
                        GUI.color = new Color(1f, 1f, 0.35f, 0.8f);
                    }
                }

                GUILayout.Space(2f);
                EditorGUILayout.PropertyField(sp_180prev);
                GUI.color = preColor;

                EditorGUIUtility.labelWidth = 0f;

                GUILayout.Space(5f);

                EditorGUILayout.EndVertical();
                GUILayout.Space(5f);


                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                GUILayout.BeginHorizontal(FEditor_Styles.BlueBackground);
                EditorGUILayout.HelpBox("Using more bones (back bones) to help rotate head (head-neck-spine)", MessageType.None);
                GUILayout.EndHorizontal();


                GUILayout.BeginHorizontal();
                int preCount = lookT.BackBonesCount;

                EditorGUIUtility.labelWidth = 130f;
                EditorGUILayout.LabelField(new GUIContent("Backbones: (" + lookT.BackBonesCount + ")"));
                EditorGUIUtility.labelWidth = 0f;

                if (GUILayout.Button("+", new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(14)
                }))
                {
                    lookT.BackBonesCount++;
                    serializedObject.ApplyModifiedProperties();
                    if (!UpdateCustomInspector(lookT, false))
                    {
                        Debug.Log("[LOOK ANIMATOR] Don't change backbones count in playmode");
                    }
                    EditorUtility.SetDirty(target);
                }

                if (GUILayout.Button("-", new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(14)
                }))
                {
                    lookT.BackBonesCount--;
                    serializedObject.ApplyModifiedProperties();
                    if (!UpdateCustomInspector(lookT, false))
                    {
                        Debug.Log("[LOOK ANIMATOR] Don't change backbones count in playmode");
                    }
                    EditorUtility.SetDirty(target);
                }

                GUILayout.EndHorizontal();

                if (lookT.BackBonesCount < 0)
                {
                    lookT.BackBonesCount = 0;
                }

                if (preCount != lookT.BackBonesCount)
                {
                    UpdateCustomInspector(lookT);
                }

                if (lookT.BackBonesCount > 0)
                {
                    drawBackBones = EditorGUILayout.Foldout(drawBackBones, "View back bones", true);
                    if (drawBackBones)
                    {
                        EditorGUI.indentLevel++;
                        EditorGUIUtility.labelWidth = 150f;
                        for (int i = 0; i < lookT.BackBonesTransforms.Length; i++)
                        {
                            string weightString = " " + Mathf.Round(lookT.RotationWeights[i] * 100f * lookT.WeightsMultiplier) + "%";

                            Transform preTr = lookT.BackBonesTransforms[i];
                            Transform newTr = (Transform)EditorGUILayout.ObjectField("Back bone [" + i + "]" + weightString, lookT.BackBonesTransforms[i], typeof(Transform), true);

                            // If we assigned own bone
                            if (preTr != newTr)
                            {
                                lookT.BackBonesTransforms[i] = newTr;
                                lookT.AddCustomBackbone(lookT.BackBonesTransforms[i], i);
                                EditorUtility.SetDirty(target);
                            }
                        }
                        EditorGUIUtility.labelWidth = 0f;

                        EditorGUI.indentLevel--;
                    }

                    GUILayout.Space(5f);

                    EditorGUILayout.BeginHorizontal();

                    EditorGUIUtility.labelWidth = 105f;
                    EditorGUILayout.PropertyField(sp_usecurve);
                    EditorGUIUtility.labelWidth = 0f;

                    if (lookT.CurveSpread)
                    {
                        EditorGUILayout.PropertyField(sp_falloff, new GUIContent(""), new GUILayoutOption[2] {
                            GUILayout.MaxHeight(40f), GUILayout.MinHeight(30f)
                        });

                        bool curveChanged = false;
                        if (preKeyframes.Length != lookT.BackBonesFalloff.keys.Length)
                        {
                            curveChanged = true;
                        }

                        if (!curveChanged)
                        {
                            for (int i = 0; i < preKeyframes.Length; i++)
                            {
                                Keyframe pre  = preKeyframes[i];
                                Keyframe curr = lookT.BackBonesFalloff.keys[i];

                                if (pre.value != curr.value || pre.time != curr.time || pre.inTangent != curr.inTangent || pre.outTangent != curr.outTangent)
                                {
                                    curveChanged = true;
                                    break;
                                }
                            }
                        }

                        if (curveChanged)
                        {
                            if (preKeyframes != lookT.BackBonesFalloff.keys)
                            {
                                preKeyframes = lookT.BackBonesFalloff.keys;
                                UpdateCustomInspector(lookT);
                                EditorUtility.SetDirty(target);
                            }
                        }
                    }
                    else
                    {
                        EditorGUILayout.PropertyField(sp_fallvall, new GUIContent(""));
                    }

                    GUILayout.Space(8f);
                    EditorGUILayout.EndHorizontal();
                    GUILayout.Space(8f);
                }

                EditorGUILayout.EndHorizontal();

                GUILayout.Space(5f);

                UnderMainTab();

                #region Limiting angles

                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                GUILayout.BeginHorizontal(FEditor_Styles.GrayBackground);
                drawLimiting = EditorGUILayout.Foldout(drawLimiting, "Limiting & Others Tab", true);
                GUILayout.EndHorizontal();

                if (drawLimiting)
                {
                    #region Clamping angles

                    bool wrongLimit = false;
                    if (Mathf.Abs(lookT.XRotationLimits.x) > lookT.MaxRotationDiffrence)
                    {
                        wrongLimit = true;
                    }
                    if (Mathf.Abs(lookT.XRotationLimits.y) > lookT.MaxRotationDiffrence)
                    {
                        wrongLimit = true;
                    }

                    Color preCol = GUI.color;

                    GUILayout.Space(4f);
                    GUILayout.BeginVertical(FEditor_Styles.LBlueBackground);

                    if (lookT.MaximumDistance > 0f)
                    {
                        EditorGUILayout.PropertyField(sp_maxdist);
                    }
                    else
                    {
                        GUILayout.BeginHorizontal();
                        //GUILayout.FlexibleSpace();

                        //EditorGUIUtility.labelWidth = 80;
                        EditorGUILayout.PropertyField(sp_maxdist);
                        //EditorGUIUtility.labelWidth = 0;
                        EditorGUILayout.LabelField("(Infinity)", new GUILayoutOption[] { GUILayout.Width(70f) });

                        GUILayout.EndHorizontal();
                    }

                    GUILayout.Space(4f);
                    EditorGUILayout.PropertyField(sp_MinHeadLookAngle);

                    if (lookT.MaximumDistance < 0f)
                    {
                        lookT.MaximumDistance = 0f;
                        EditorUtility.SetDirty(target);
                    }

                    GUILayout.EndVertical();
                    GUILayout.Space(4f);

                    if (!wrongLimit)
                    {
                        GUI.color = new Color(0.55f, 0.9f, 0.75f, 0.8f);
                    }
                    else
                    {
                        GUI.color = new Color(0.9f, 0.55f, 0.55f, 0.8f);
                    }

                    // X
                    GUILayout.BeginVertical(FEditor_Styles.Emerald);

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("  Clamp Angle Horizontal (X)", GUILayout.MaxWidth(170f));
                    GUILayout.FlexibleSpace();
                    GUILayout.Label(Mathf.Round(lookT.XRotationLimits.x) + "°", FEditor_Styles.GrayBackground, GUILayout.MaxWidth(40f));
                    //FEditor_CustomInspectorHelpers.DrawMinMaxSphere(lookT.XRotationLimits.x, lookT.XRotationLimits.y, 14, lookT.XElasticRange);
                    FEditor_CustomInspectorHelpers.DrawMinMaxSphere(lookT.XRotationLimits.x, lookT.XRotationLimits.y, 14, lookT.XElasticRange);
                    GUILayout.Label(Mathf.Round(lookT.XRotationLimits.y) + "°", FEditor_Styles.GrayBackground, GUILayout.MaxWidth(40f));
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();

                    EditorGUILayout.MinMaxSlider(ref lookT.XRotationLimits.x, ref lookT.XRotationLimits.y, -180f, 180f);

                    //if (Mathf.Abs(lookT.XRotationLimits.x) > lookT.MaxRotationDiffrence) lookT.MaxRotationDiffrence = Mathf.Abs(lookT.XRotationLimits.x);
                    //if (Mathf.Abs(lookT.XRotationLimits.y) > lookT.MaxRotationDiffrence) lookT.MaxRotationDiffrence = Mathf.Abs(lookT.XRotationLimits.y);

                    bothX = EditorGUILayout.Slider("Adjust symmetrical", bothX, 1f, 180f);
                    EditorGUILayout.PropertyField(sp_elasticX);

                    if (lastBothX != bothX)
                    {
                        lookT.XRotationLimits.x = -bothX;
                        lookT.XRotationLimits.y = bothX;
                        lastBothX = bothX;
                        serializedObject.ApplyModifiedProperties();
                        EditorUtility.SetDirty(target);
                    }

                    GUILayout.EndVertical();

                    GUILayout.Space(7f);

                    GUI.color = new Color(0.6f, 0.75f, 0.9f, 0.8f);

                    // Y
                    GUILayout.BeginVertical(FEditor_Styles.LBlueBackground);

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("  Clamp Angle Vertical (Y)", GUILayout.MaxWidth(170f));
                    GUILayout.FlexibleSpace();
                    GUILayout.Label(Mathf.Round(lookT.YRotationLimits.x) + "°", FEditor_Styles.GrayBackground, GUILayout.MaxWidth(40f));
                    FEditor_CustomInspectorHelpers.DrawMinMaxVertSphere(-lookT.YRotationLimits.y, -lookT.YRotationLimits.x, 14, lookT.YElasticRange);
                    GUILayout.Label(Mathf.Round(lookT.YRotationLimits.y) + "°", FEditor_Styles.GrayBackground, GUILayout.MaxWidth(40f));
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();

                    EditorGUILayout.MinMaxSlider(ref lookT.YRotationLimits.x, ref lookT.YRotationLimits.y, -90f, 90f);
                    bothY = EditorGUILayout.Slider("Adjust symmetrical", bothY, 1f, 90f);
                    EditorGUILayout.PropertyField(sp_elasticY);

                    if (lastBothY != bothY)
                    {
                        lookT.YRotationLimits.x = -bothY;
                        lookT.YRotationLimits.y = bothY;
                        lastBothY = bothY;
                        serializedObject.ApplyModifiedProperties();
                        EditorUtility.SetDirty(target);
                    }

                    GUILayout.EndVertical();

                    #endregion

                    GUI.color = preCol;

                    GUILayout.Space(15f);

                    GUILayout.BeginHorizontal(FEditor_Styles.BlueBackground);
                    EditorGUILayout.HelpBox("If this angle is exceeded character will look forward", MessageType.None);
                    GUILayout.EndHorizontal();

                    if (!wrongLimit)
                    {
                        GUI.color = new Color(0.55f, 0.9f, 0.75f, 0.8f);
                    }
                    else
                    {
                        GUI.color = new Color(0.9f, 0.55f, 0.55f, 0.8f);
                    }

                    EditorGUILayout.BeginVertical(FEditor_Styles.Emerald);

                    GUILayout.BeginHorizontal();

                    lookT.MaxRotationDiffrence = EditorGUILayout.Slider("Max Angle Diff", lookT.MaxRotationDiffrence, 25f, 180f);
                    FEditor_CustomInspectorHelpers.DrawMinMaxSphere(-lookT.MaxRotationDiffrence, lookT.MaxRotationDiffrence, 14);
                    GUILayout.EndHorizontal();

                    lookT.DeltaAccelerationRange = EditorGUILayout.Slider(new GUIContent("Delta Accelerate", "If head have to rotate more than this value it's animation speed for rotating increases, small touch to make animation more realistic"), lookT.DeltaAccelerationRange, 25f, 70f);
                    EditorGUILayout.PropertyField(sp_chretspeed);
                    EditorGUILayout.PropertyField(sp_bigsmooth);

                    GUILayout.Space(8f);

                    EditorGUILayout.EndVertical();
                    GUI.color = preCol;
                    serializedObject.ApplyModifiedProperties();
                }

                GUILayout.EndVertical();
            }

            #endregion

            #endregion


            #region Correcting bones orientations


            EditorGUI.indentLevel--;
            EditorGUILayout.BeginVertical(FEditor_Styles.GrayBackground);
            EditorGUI.indentLevel++;

            drawCorrecting = EditorGUILayout.Foldout(drawCorrecting, "Correcting rotations", true);

            if (drawCorrecting)
            {
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                GUILayout.Space(3f);

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.PropertyField(sp_fixpres);

                EditorGUILayout.BeginVertical(new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(20)
                });

                if (GUILayout.Button("▲", new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(10)
                }))
                {
                    if ((int)lookT.FixingPreset == 0)
                    {
                        lookT.FixingPreset = (FLookAnimator.EFAxisFixOrder)(Enum.GetValues(typeof(FLookAnimator.EFAxisFixOrder)).Length - 1);
                    }
                    else
                    {
                        lookT.FixingPreset--;
                    }

                    EditorUtility.SetDirty(target);
                }

                if (GUILayout.Button("▼", new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(10)
                }))
                {
                    if ((int)lookT.FixingPreset + 1 >= Enum.GetValues(typeof(FLookAnimator.EFAxisFixOrder)).Length)
                    {
                        lookT.FixingPreset = 0;
                    }
                    else
                    {
                        lookT.FixingPreset++;
                    }

                    EditorUtility.SetDirty(target);
                }

                EditorGUILayout.EndVertical();
                EditorGUILayout.EndHorizontal();

                GUILayout.Space(3f);

                if (lookT.FixingPreset == FLookAnimator.EFAxisFixOrder.FullManual)
                {
                    EditorGUILayout.PropertyField(sp_axesmul);
                    GUILayout.Space(5f);
                    EditorGUILayout.PropertyField(sp_manfromax);
                    EditorGUILayout.PropertyField(sp_mantoax);
                    GUILayout.Space(5f);
                }

                if (lookT.FixingPreset == FLookAnimator.EFAxisFixOrder.FromBased)
                {
                    EditorGUILayout.LabelField("Auto Offset: " + RoundVector(lookT.OffsetAuto));
                    EditorGUILayout.LabelField("Auto From Axis: " + RoundVector(lookT.FromAuto));
                }

                EditorGUILayout.PropertyField(sp_angoff);
                EditorGUILayout.PropertyField(sp_backoff);
                GUILayout.Space(5f);

                EditorGUILayout.PropertyField(sp_dray);
                GUILayout.Space(5f);

                EditorGUILayout.EndVertical();
                GUILayout.Space(5f);
            }

            EditorGUILayout.EndVertical();


            #endregion


            #region Additional parameters


            EditorGUI.indentLevel--;
            EditorGUILayout.BeginVertical(FEditor_Styles.GrayBackground);
            EditorGUI.indentLevel++;

            drawAdditional = EditorGUILayout.Foldout(drawAdditional, "Additional controll parameters", true);

            if (drawAdditional)
            {
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                GUILayout.Space(5f);
                EditorGUIUtility.labelWidth = 140;

                //lookT.BlendToOriginal = EditorGUILayout.Slider(new GUIContent("Animation Blend", "Main blend value for new head look rotations"), lookT.BlendToOriginal, 0f, 1f);
                EditorGUILayout.PropertyField(sp_blend);

                EditorGUIUtility.labelWidth = 180;
                GUILayout.Space(3f);
                EditorGUILayout.PropertyField(sp_eyespos);

                EditorGUILayout.PropertyField(sp_ancheyes);

                if (lookT.AnchorReferencePoint)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.PropertyField(sp_anchrefr);
                    EditorGUI.indentLevel--;
                }

                GUILayout.Space(3f);
                EditorGUIUtility.labelWidth = 140;
                EditorGUILayout.PropertyField(sp_leadblend);

                GUILayout.Space(3f);

                bool wrong = false;
                if (!animatorDetected)
                {
                    if (lookT.AnimateWithSource)
                    {
                        wrong = true;
                    }
                }

                EditorGUILayout.BeginVertical(FEditor_Styles.GreenBackground);
                EditorGUIUtility.labelWidth = 160;

                Color preCol = GUI.color;
                if (wrong)
                {
                    EditorGUILayout.HelpBox("Component can't find animator attached to your character, you should untoggle this variable if there isn't any animator working on character's animation", MessageType.Warning);
                    GUI.color = new Color(1f, 1f, 0.35f, 0.8f);
                }

                EditorGUILayout.PropertyField(sp_animwithsource);

                if (lookT.AnimateWithSource)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.PropertyField(sp_monitor);
                    EditorGUI.indentLevel--;
                }

                GUI.color = preCol;


                EditorGUIUtility.labelWidth = 0;

                EditorGUILayout.EndVertical();

                GUILayout.Space(5f);


                // v1.0.7 - Bird Mode
                EditorGUILayout.BeginVertical(FEditor_Styles.LBlueBackground);
                EditorGUIUtility.labelWidth = 160;

                EditorGUILayout.PropertyField(sp_bird);

                if (lookT.BirdMode)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.PropertyField(sp_birdlag);
                    EditorGUILayout.PropertyField(sp_birdspd);
                    EditorGUILayout.PropertyField(sp_birdlagprog);
                    EditorGUILayout.PropertyField(sp_birdfreq);
                    EditorGUILayout.PropertyField(sp_birddel);
                    EditorGUILayout.PropertyField(sp_birmaxdist);
                    EditorGUILayout.PropertyField(sp_birddelgospeed);
                    EditorGUI.indentLevel--;
                }

                EditorGUIUtility.labelWidth = 0;

                EditorGUILayout.EndVertical();
                GUILayout.Space(5f);


                EditorGUILayout.EndVertical();
                GUILayout.Space(5f);


                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                GUILayout.BeginHorizontal(FEditor_Styles.BlueBackground);
                EditorGUILayout.HelpBox("If you don't want arms to be rotated when spine, bone is rotated by script", MessageType.None);
                GUILayout.EndHorizontal();

                #region Supporting list in custom editor

                if (lookT.CompensationBones != null)
                {
                    compensationBonesCount = lookT.CompensationBones.Count;
                }
                else
                {
                    compensationBonesCount = 0;
                }

                GUILayout.BeginHorizontal();
                compensationBonesCount = EditorGUILayout.IntField("Compensation Bones", compensationBonesCount);
                if (GUILayout.Button(new GUIContent("Find", "By pressing this button, algorithm will try to find bones with names 'Shoulder', 'Upper Arm' be aware, because you can have other objects inside including this names"), new GUILayoutOption[2] {
                    GUILayout.MaxWidth(58), GUILayout.MaxHeight(14)
                }))
                {
                    FindCompensationBones(lookT);
                }
                if (GUILayout.Button("+", new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(14)
                }))
                {
                    serializedObject.ApplyModifiedProperties();
                    compensationBonesCount++;
                    EditorUtility.SetDirty(target);
                }

                if (GUILayout.Button("-", new GUILayoutOption[2] {
                    GUILayout.MaxWidth(28), GUILayout.MaxHeight(14)
                }))
                {
                    if (lookT.CompensationBones.Count == 1)
                    {
                        lookT.CompensationBones = new List <Transform>();
                        compensationBonesCount  = 0;
                        //lookT.BackBonesCount = 0;
                    }
                    else
                    {
                        compensationBonesCount--;
                    }

                    serializedObject.ApplyModifiedProperties();
                    EditorUtility.SetDirty(target);
                }

                GUILayout.EndHorizontal();

                if (compensationBonesCount <= 0)
                {
                    compensationBonesCount = 0;
                }
                else
                {
                    if (compensationBonesCount > lookT.CompensationBones.Count)
                    {
                        for (int i = lookT.CompensationBones.Count; i < compensationBonesCount; i++)
                        {
                            lookT.CompensationBones.Add(null);
                        }
                    }
                    else if (compensationBonesCount < lookT.CompensationBones.Count)
                    {
                        for (int i = lookT.CompensationBones.Count - 1; i >= compensationBonesCount; i--)
                        {
                            lookT.CompensationBones.RemoveAt(i);
                        }
                    }

                    if (lookT.CompensationBones.Count > 0)
                    {
                        EditorGUI.indentLevel++;

                        for (int i = 0; i < lookT.CompensationBones.Count; i++)
                        {
                            lookT.CompensationBones[i] = (Transform)EditorGUILayout.ObjectField("Bone [" + i + "]", lookT.CompensationBones[i], typeof(Transform), true);
                        }

                        EditorGUI.indentLevel--;

                        GUILayout.Space(5f);

                        EditorGUILayout.PropertyField(sp_compensblend);
                        EditorGUILayout.PropertyField(sp_poscompens);
                    }
                }

                #endregion

                EditorGUILayout.EndVertical();
                GUILayout.Space(5f);
            }

            EditorGUILayout.EndVertical();


            #endregion


            #region Optional parameters


            EditorGUI.indentLevel--;
            EditorGUILayout.BeginVertical(FEditor_Styles.GrayBackground);
            EditorGUI.indentLevel++;

            drawOptional = EditorGUILayout.Foldout(drawOptional, "Optional parameters", true);

            if (drawOptional)
            {
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                GUILayout.Space(10f);

                EditorGUILayout.PropertyField(sp_weighmul);

                GUILayout.Space(3f);

                GUILayout.BeginHorizontal();
                EditorGUILayout.HelpBox("If animation is not animating some head bones (very rare case)", MessageType.None);
                GUILayout.EndHorizontal();

                EditorGUILayout.PropertyField(sp_bonesnotanim);
                EditorGUILayout.PropertyField(sp_animphys);

                GUILayout.Space(5f);

                EditorGUILayout.EndVertical();
                GUILayout.Space(5f);
            }

            EditorGUILayout.EndVertical();

            #endregion

            EditorGUILayout.EndVertical();
        }

        // Apply changed parameters variables
        serializedObject.ApplyModifiedProperties();
    }
Example #35
0
 /// <summary>
 /// Comparison function for sorting keyframes into ascending time order.
 /// </summary>
 /// <param name="a">
 /// The a.
 /// </param>
 /// <param name="b">
 /// The b.
 /// </param>
 /// <returns>
 /// The compare keyframe times.
 /// </returns>
 private static int CompareKeyframeTimes(Keyframe a, Keyframe b)
 {
     return(a.Time.CompareTo(b.Time));
 }
Example #36
0
        public override void OnInspectorGUI()
        {
            EditorGUILayout.Space();

            Rect weightCurveRect = GUILayoutUtility.GetAspectRect(2.0f);

            Color previousGUIColor = GUI.color;

            GUI.color = Color.black;

            GUI.DrawTexture(
                new Rect(
                    weightCurveRect.x - 1.0f,
                    weightCurveRect.y - 1.0f,
                    weightCurveRect.width + 2.0f,
                    weightCurveRect.height + 2.0f),
                this.lineTexture);

            GUI.color = Color.grey;

            GUI.Box(weightCurveRect, "");

            GUI.color = previousGUIColor;

            string error = null;

            if (this.targets.Length <= 1)
            {
                Effect targetEffect = (Effect)this.target;

                if (targetEffect.Duration != 0.0f)
                {
                    Keyframe[] weightCurveKeyframes = new Keyframe[(int)(weightCurveRect.width * 0.4f)];

                    for (int i = 0; i < weightCurveKeyframes.Length; ++i)
                    {
                        float time = targetEffect.SimulatedTime - targetEffect.Duration + (i / (float)weightCurveKeyframes.Length) * targetEffect.Duration * 2.0f;

                        weightCurveKeyframes[i] = new Keyframe(time, targetEffect.CalculateWeight(time));
                    }

                    for (int i = 0; i < weightCurveKeyframes.Length - 1; ++i)
                    {
                        weightCurveKeyframes[i].outTangent =
                            (weightCurveKeyframes[i + 1].value - weightCurveKeyframes[i].value)
                            / (weightCurveKeyframes[i + 1].time - weightCurveKeyframes[i].time);
                        weightCurveKeyframes[i + 1].inTangent =
                            (weightCurveKeyframes[i].value - weightCurveKeyframes[i + 1].value)
                            / (weightCurveKeyframes[i].time - weightCurveKeyframes[i + 1].time);
                    }

                    AnimationCurve weightCurve = new AnimationCurve(weightCurveKeyframes);

                    EditorGUIUtility.DrawRegionSwatch(
                        weightCurveRect,
                        weightCurve,
                        AnimationCurve.Linear(
                            targetEffect.SimulatedTime - targetEffect.Duration,
                            0.0f,
                            targetEffect.SimulatedTime + targetEffect.Duration,
                            0.0f),
                        Color.cyan,
                        Color.grey,
                        new Rect(
                            targetEffect.SimulatedTime - targetEffect.Duration,
                            -MAX_WEIGHT,
                            targetEffect.Duration * 2.0f,
                            MAX_WEIGHT * 2.0f));

                    GUI.color = new Color(0.0f, 0.0f, 0.0f, 0.3f);

                    float topLineY = weightCurveRect.y + weightCurveRect.height * ((MAX_WEIGHT - 1.0f) / (MAX_WEIGHT * 2.0f));

                    // Top Line
                    GUI.DrawTexture(
                        new Rect(
                            weightCurveRect.x,
                            topLineY,
                            weightCurveRect.width,
                            1.0f),
                        this.lineTexture);

                    float bottomLineY = weightCurveRect.y + weightCurveRect.height * ((2.0f + MAX_WEIGHT - 1.0f) / (MAX_WEIGHT * 2.0f));

                    // Bottom Line
                    GUI.DrawTexture(
                        new Rect(
                            weightCurveRect.x,
                            bottomLineY,
                            weightCurveRect.width,
                            1.0f),
                        this.lineTexture);

                    GUI.color = new Color(0.0f, 0.0f, 0.0f, 1.0f);

                    // Middle Horizontal Line
                    float middleLineThickness = 1.0f + (weightCurveRect.height % 2.0f == 1.0f ? 0.0f : 1.0f);
                    GUI.DrawTexture(
                        new Rect(
                            weightCurveRect.x,
                            weightCurveRect.y + weightCurveRect.height * 0.5f - (int)(middleLineThickness / 2.0f),
                            weightCurveRect.width,
                            middleLineThickness),
                        this.lineTexture);

                    //Middle Vertical Line
                    middleLineThickness = 1.0f + (weightCurveRect.width % 2.0f == 1.0f ? 0.0f : 1.0f);
                    GUI.DrawTexture(
                        new Rect(
                            weightCurveRect.x + weightCurveRect.width * 0.5f - (int)(middleLineThickness / 2.0f),
                            weightCurveRect.y,
                            middleLineThickness,
                            weightCurveRect.height),
                        this.lineTexture);

                    if (targetEffect.IsSleeping)
                    {
                        GUI.color = new Color(1.0f, 0.3f, 0.3f, 0.6f);

                        // Time Text
                        GUI.Box(
                            new Rect(
                                weightCurveRect.x + weightCurveRect.width - 5.0f - 40.0f,
                                bottomLineY - 5.0f - 20.0f,
                                40.0f,
                                20.0f),
                            "Zzz");
                    }

                    GUI.color = new Color(0.0f, 0.0f, 0.0f, 0.5f);

                    // Time Text
                    EditorGUI.LabelField(
                        new Rect(
                            weightCurveRect.x + 5.0f,
                            topLineY + 5.0f,
                            95.0f,
                            16.0f),
                        "Time: " + targetEffect.SimulatedTime.ToString("0.00"));

                    // Weight Text
                    EditorGUI.LabelField(
                        new Rect(
                            weightCurveRect.x + 5.0f,
                            topLineY + 21.0f,
                            95.0f,
                            16.0f),
                        "Weight: " + targetEffect.CalculateWeight().ToString("0.00"));
                }
                else
                {
                    error = "zero duration";
                }
            }
            else
            {
                error = "multiple objects selected";
            }

            if (error != null)
            {
                if (this.errorStyle == null)
                {
                    this.errorStyle = new GUIStyle(GUI.skin.label);

                    this.errorStyle.alignment = TextAnchor.MiddleCenter;
                }

                GUI.color = Color.black;

                this.errorStyle.fontSize = 72;
                EditorGUI.LabelField(weightCurveRect, "X", this.errorStyle);

                GUI.color = new Color(1.0f, 1.0f, 1.0f, 0.5f);

                this.errorStyle.fontSize = 16;
                EditorGUI.LabelField(
                    new Rect(
                        weightCurveRect.x,
                        weightCurveRect.y + weightCurveRect.height * 0.5f,
                        weightCurveRect.width,
                        weightCurveRect.height * 0.5f),
                    error,
                    this.errorStyle);
            }

            EditorGUILayout.Space();

            GUI.color = previousGUIColor;

            base.OnInspectorGUI();
        }
        public void DeserializeBeforeRef(UABUnpacker unpacker, UABField field, ref object value, List <ISerializer> serializers)
        {
            var keyFrame = new Keyframe();

            value = unpacker.Deserialize(keyFrame, field.fields, serializers);
        }
Example #38
0
    public static Vector3[] SmoothLine(Vector3[] inputPoints, float segmentSize)
    {
        //create curves
        AnimationCurve curveX = new AnimationCurve();
        AnimationCurve curveY = new AnimationCurve();
        AnimationCurve curveZ = new AnimationCurve();

        //create keyframe sets
        Keyframe[] keysX = new Keyframe[inputPoints.Length];
        Keyframe[] keysY = new Keyframe[inputPoints.Length];
        Keyframe[] keysZ = new Keyframe[inputPoints.Length];

        //set keyframes
        for (int i = 0; i < inputPoints.Length; i++)
        {
            keysX[i] = new Keyframe(i, inputPoints[i].x);
            keysY[i] = new Keyframe(i, inputPoints[i].y);
            keysZ[i] = new Keyframe(i, inputPoints[i].z);
        }

        //apply keyframes to curves
        curveX.keys = keysX;
        curveY.keys = keysY;
        curveZ.keys = keysZ;

        //smooth curve tangents
        for (int i = 0; i < inputPoints.Length; i++)
        {
            curveX.SmoothTangents(i, 0);
            curveY.SmoothTangents(i, 0);
            curveZ.SmoothTangents(i, 0);
        }

        //list to write smoothed values to
        List <Vector3> lineSegments = new List <Vector3>();

        //find segments in each section
        for (int i = 0; i < inputPoints.Length; i++)
        {
            //add first point
            lineSegments.Add(inputPoints[i]);

            //make sure within range of array
            if (i + 1 < inputPoints.Length)
            {
                //find distance to next point
                float distanceToNext = Vector3.Distance(inputPoints[i], inputPoints[i + 1]);

                //number of segments
                int segments = (int)(distanceToNext / segmentSize);

                //add segments
                for (int s = 1; s < segments; s++)
                {
                    //interpolated time on curve
                    float time = ((float)s / (float)segments) + (float)i;

                    //sample curves to find smoothed position
                    Vector3 newSegment = new Vector3(curveX.Evaluate(time), curveY.Evaluate(time), curveZ.Evaluate(time));

                    //add to list
                    lineSegments.Add(newSegment);
                }
            }
        }

        return(lineSegments.ToArray());
    }
Example #39
0
 public override GradientColor GetValue(Keyframe <GradientColor> keyframe, float keyframeProgress)
 {
     _gradientColor.Lerp(keyframe.StartValue, keyframe.EndValue, keyframeProgress);
     return(_gradientColor);
 }
Example #40
0
 internal static void SetKeyBroken(ref Keyframe key, bool broken)
 {
     Internal_SetKeyBroken(ref key, broken);
 }
 private void SetConstantCurve(CurveWrapper cw, float constantValue)
 {
     Keyframe[] keyframeArray = new Keyframe[1];
     keyframeArray[0].time = 0f;
     keyframeArray[0].value = constantValue;
     cw.curve.keys = keyframeArray;
     cw.changed = true;
 }
Example #42
0
 extern private static void Internal_SetKeyBroken(ref Keyframe key, bool broken);
Example #43
0
 bool GetKeyBroken(Keyframe key)
 {
     return((key.tangentMode & kBrokenMask) != 0);
 }
Example #44
0
 float CalculateLinearTangent(Keyframe from, Keyframe to)
 {
     return((from.value - to.value) / (from.time - to.time));
 }
Example #45
0
        //!
        //! sets the keyframe at the current time of the animation to a new value for the currently animated object
        //! automatically adds keyframe if there is none at this time of the animation
        //!
        public void setKeyframe()
        {
            bool movedSuccessfully = false;
            int  keyIndex          = -1;

            //x value
            Keyframe key = new Keyframe(animationController.currentAnimationTime, this.transform.position.x);

            for (int i = 0; i < this.transCurves[0].length; i++)
            {
                if (Mathf.Abs(this.transCurves[0].keys[i].time - animationController.currentAnimationTime) < 0.04)
                {
                    this.transCurves[0].MoveKey(i, key);
                    keyIndex          = i;
                    movedSuccessfully = true;
                }
            }
            if (!movedSuccessfully)
            {
                keyIndex          = this.transCurves[0].AddKey(key);
                movedSuccessfully = false;
            }
            if (transCurves[0].keys.Length > 1)
            {
                if (keyIndex == 0)
                {
                    this.transCurves[0].SmoothTangents(1, 0);
                }
                if (keyIndex == transCurves[0].keys.Length - 1)
                {
                    this.transCurves[0].SmoothTangents(transCurves[0].keys.Length - 2, 0);
                }
            }
            this.transCurves[0].SmoothTangents(keyIndex, 0);

            //y value
            key = new Keyframe(animationController.currentAnimationTime, this.transform.position.y);
            for (int i = 0; i < this.transCurves[1].length; i++)
            {
                if (Mathf.Abs(this.transCurves[1].keys[i].time - animationController.currentAnimationTime) < 0.04)
                {
                    this.transCurves[1].MoveKey(i, key);
                    keyIndex          = i;
                    movedSuccessfully = true;
                }
            }
            if (!movedSuccessfully)
            {
                keyIndex          = this.transCurves[1].AddKey(key);
                movedSuccessfully = false;
            }
            if (transCurves[1].keys.Length > 1)
            {
                if (keyIndex == 0)
                {
                    this.transCurves[1].SmoothTangents(1, 0);
                }
                if (keyIndex == transCurves[1].keys.Length - 1)
                {
                    this.transCurves[1].SmoothTangents(transCurves[1].keys.Length - 2, 0);
                }
            }
            this.transCurves[1].SmoothTangents(keyIndex, 0);

            //z value
            key = new Keyframe(animationController.currentAnimationTime, this.transform.position.z);
            for (int i = 0; i < this.transCurves[2].length; i++)
            {
                if (Mathf.Abs(this.transCurves[2].keys[i].time - animationController.currentAnimationTime) < 0.04)
                {
                    this.transCurves[2].MoveKey(i, key);
                    keyIndex          = i;
                    movedSuccessfully = true;
                }
            }
            if (!movedSuccessfully)
            {
                keyIndex          = this.transCurves[2].AddKey(key);
                movedSuccessfully = false;
            }

            if (transCurves[2].keys.Length > 1)
            {
                if (keyIndex == 0)
                {
                    this.transCurves[2].SmoothTangents(1, 0);
                }
                if (keyIndex == transCurves[2].keys.Length - 1)
                {
                    this.transCurves[2].SmoothTangents(transCurves[2].keys.Length - 2, 0);
                }
            }
            this.transCurves[2].SmoothTangents(keyIndex, 0);

            animData.changeAnimationCurve(animData.getAnimationClips(target.gameObject)[0], typeof(Transform), "m_LocalPosition.x", transCurves[0]);
            animData.changeAnimationCurve(animData.getAnimationClips(target.gameObject)[0], typeof(Transform), "m_LocalPosition.y", transCurves[1]);
            animData.changeAnimationCurve(animData.getAnimationClips(target.gameObject)[0], typeof(Transform), "m_LocalPosition.z", transCurves[2]);

            updateAnimationCurves();
        }
Example #46
0
 internal static void SetKeyRightTangentMode(ref Keyframe key, TangentMode tangentMode)
 {
     Internal_SetKeyRightTangentMode(ref key, tangentMode);
 }
Example #47
0
        public void AddTangentMenuItems(GenericMenu menu, List <KeyIdentifier> keyList)
        {
            bool flag  = keyList.Count > 0;
            bool on    = flag;
            bool on2   = flag;
            bool on3   = flag;
            bool on4   = flag;
            bool flag2 = flag;
            bool flag3 = flag;
            bool flag4 = flag;
            bool flag5 = flag;
            bool flag6 = flag;
            bool flag7 = flag;

            foreach (KeyIdentifier current in keyList)
            {
                Keyframe    keyframe        = current.keyframe;
                TangentMode keyTangentMode  = CurveUtility.GetKeyTangentMode(keyframe, 0);
                TangentMode keyTangentMode2 = CurveUtility.GetKeyTangentMode(keyframe, 1);
                bool        keyBroken       = CurveUtility.GetKeyBroken(keyframe);
                if (keyTangentMode != TangentMode.Smooth || keyTangentMode2 != TangentMode.Smooth)
                {
                    on = false;
                }
                if (keyBroken || keyTangentMode != TangentMode.Editable || keyTangentMode2 != TangentMode.Editable)
                {
                    on2 = false;
                }
                if (keyBroken || keyTangentMode != TangentMode.Editable || keyframe.inTangent != 0f || keyTangentMode2 != TangentMode.Editable || keyframe.outTangent != 0f)
                {
                    on3 = false;
                }
                if (!keyBroken)
                {
                    on4 = false;
                }
                if (!keyBroken || keyTangentMode != TangentMode.Editable)
                {
                    flag2 = false;
                }
                if (!keyBroken || keyTangentMode != TangentMode.Linear)
                {
                    flag3 = false;
                }
                if (!keyBroken || keyTangentMode != TangentMode.Stepped)
                {
                    flag4 = false;
                }
                if (!keyBroken || keyTangentMode2 != TangentMode.Editable)
                {
                    flag5 = false;
                }
                if (!keyBroken || keyTangentMode2 != TangentMode.Linear)
                {
                    flag6 = false;
                }
                if (!keyBroken || keyTangentMode2 != TangentMode.Stepped)
                {
                    flag7 = false;
                }
            }
            if (flag)
            {
                menu.AddItem(EditorGUIUtility.TextContent("Auto"), on, new GenericMenu.MenuFunction2(this.SetSmooth), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Free Smooth"), on2, new GenericMenu.MenuFunction2(this.SetEditable), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Flat"), on3, new GenericMenu.MenuFunction2(this.SetFlat), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Broken"), on4, new GenericMenu.MenuFunction2(this.SetBroken), keyList);
                menu.AddSeparator(string.Empty);
                menu.AddItem(EditorGUIUtility.TextContent("Left Tangent/Free"), flag2, new GenericMenu.MenuFunction2(this.SetLeftEditable), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Left Tangent/Linear"), flag3, new GenericMenu.MenuFunction2(this.SetLeftLinear), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Left Tangent/Constant"), flag4, new GenericMenu.MenuFunction2(this.SetLeftConstant), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Right Tangent/Free"), flag5, new GenericMenu.MenuFunction2(this.SetRightEditable), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Right Tangent/Linear"), flag6, new GenericMenu.MenuFunction2(this.SetRightLinear), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Right Tangent/Constant"), flag7, new GenericMenu.MenuFunction2(this.SetRightConstant), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Both Tangents/Free"), flag5 && flag2, new GenericMenu.MenuFunction2(this.SetBothEditable), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Both Tangents/Linear"), flag6 && flag3, new GenericMenu.MenuFunction2(this.SetBothLinear), keyList);
                menu.AddItem(EditorGUIUtility.TextContent("Both Tangents/Constant"), flag7 && flag4, new GenericMenu.MenuFunction2(this.SetBothConstant), keyList);
            }
            else
            {
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Auto"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Free Smooth"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Flat"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Broken"));
                menu.AddSeparator(string.Empty);
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Left Tangent/Free"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Left Tangent/Linear"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Left Tangent/Constant"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Right Tangent/Free"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Right Tangent/Linear"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Right Tangent/Constant"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Both Tangents/Free"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Both Tangents/Linear"));
                menu.AddDisabledItem(EditorGUIUtility.TextContent("Both Tangents/Constant"));
            }
        }
Example #48
0
 extern private static bool Internal_GetKeyBroken(Keyframe key);
Example #49
0
 public static string FromKeyframe(Keyframe k)
 {
     return(FromKeyFrameImpl(k).ToString());
 }
Example #50
0
 extern private static TangentMode Internal_GetKeyRightTangentMode(Keyframe key);
        /// <summary>
        /// beginObject will already be called on the keyframe so it can be differentiated with
        /// a non animated value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="composition"></param>
        /// <param name="reader"></param>
        /// <param name="scale"></param>
        /// <param name="valueParser"></param>
        /// <returns></returns>
        private static Keyframe <T> ParseKeyframe <T>(LottieComposition composition, JsonReader reader, float scale, IValueParser <T> valueParser)
        {
            Vector2?      cp1        = null;
            Vector2?      cp2        = null;
            float         startFrame = 0;
            T             startValue = default(T);
            T             endValue   = default(T);
            bool          hold       = false;
            IInterpolator interpolator;

            // Only used by PathKeyframe
            Vector2?pathCp1 = null;
            Vector2?pathCp2 = null;

            reader.BeginObject();
            while (reader.HasNext())
            {
                switch (reader.NextName())
                {
                case "t":
                    startFrame = reader.NextDouble();
                    break;

                case "s":
                    startValue = valueParser.Parse(reader, scale);
                    break;

                case "e":
                    endValue = valueParser.Parse(reader, scale);
                    break;

                case "o":
                    cp1 = JsonUtils.JsonToPoint(reader, scale);
                    break;

                case "i":
                    cp2 = JsonUtils.JsonToPoint(reader, scale);
                    break;

                case "h":
                    hold = reader.NextInt() == 1;
                    break;

                case "to":
                    pathCp1 = JsonUtils.JsonToPoint(reader, scale);
                    break;

                case "ti":
                    pathCp2 = JsonUtils.JsonToPoint(reader, scale);
                    break;

                default:
                    reader.SkipValue();
                    break;
                }
            }
            reader.EndObject();

            if (hold)
            {
                endValue = startValue;
                // TODO: create a HoldInterpolator so progress changes don't invalidate.
                interpolator = LinearInterpolator;
            }
            else if (cp1 != null && cp2 != null)
            {
                cp1 = new Vector2(MiscUtils.Clamp(cp1.Value.X, -scale, scale),
                                  MiscUtils.Clamp(cp1.Value.Y, -MaxCpValue, MaxCpValue));
                cp2 = new Vector2(MiscUtils.Clamp(cp2.Value.X, -scale, scale),
                                  MiscUtils.Clamp(cp2.Value.Y, -MaxCpValue, MaxCpValue));

                int hash = Utils.Utils.HashFor(cp1.Value.X, cp1.Value.Y, cp2.Value.X, cp2.Value.Y);
                if (GetInterpolator(hash, out var interpolatorRef) == false ||
                    interpolatorRef.TryGetTarget(out interpolator) == false)
                {
                    interpolator = new PathInterpolator(cp1.Value.X / scale, cp1.Value.Y / scale, cp2.Value.X / scale, cp2.Value.Y / scale);
                    try
                    {
                        PutInterpolator(hash, new WeakReference <IInterpolator>(interpolator));
                    }
                    catch
                    {
                        // It is not clear why but SparseArrayCompat sometimes fails with this:
                        //     https://github.com/airbnb/lottie-android/issues/452
                        // Because this is not a critical operation, we can safely just ignore it.
                        // I was unable to repro this to attempt a proper fix.
                    }
                }
            }
            else
            {
                interpolator = LinearInterpolator;
            }

            var keyframe = new Keyframe <T>(composition, startValue, endValue, interpolator, startFrame, null)
            {
                PathCp1 = pathCp1,
                PathCp2 = pathCp2
            };

            return(keyframe);
        }
Example #52
0
 internal static bool GetKeyBroken(Keyframe key)
 {
     return(Internal_GetKeyBroken(key));
 }
        //private static GameObject go;
        public static void Draw(InAudioNode node)
        {
            if (Application.isPlaying)
            {
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Play Node"))
                {
                    var link = node.GetBank();
                    if (link != null && link.IsLoaded)
                    {
                        if (preview != null)
                        {
                            preview.Stop();
                        }
                        preview = InAudio.Play(InAudioInstanceFinder.Instance.gameObject, node);
                        preview.SpatialBlend = 0.0f;
                        preview.OnCompleted  = (go, audioNode) => preview = null;
                    }
                    else
                    {
                        Debug.Log("InAudio: Cannot preview node as its beloning bank is not loaded");
                    }
                }
                if (GUILayout.Button("Stop Playing Node") && preview != null)
                {
                    InAudio.StopAll(InAudioInstanceFinder.Instance.gameObject);
                }
                if (GUILayout.Button("Stop All Instances"))
                {
                    InAudio.StopAllOfNode(node);
                }
                EditorGUILayout.EndHorizontal();
            }

            InAudioNodeData baseData = (InAudioNodeData)node._nodeData;

            EditorGUILayout.Separator();

            DrawSelectedArea(node, baseData);

            Seperators(2);

            if (baseData.SelectedArea == 0)
            {
                EditorGUIHelper.DrawID(node._guid);

                #region Volume

                DataDrawerHelper.DrawVolume(baseData, ref baseData.MinVolume, ref baseData.MaxVolume, ref baseData.RandomVolume);
                #endregion

                Seperators(2);

                #region Parent pitch

                SetPitch(baseData);

                #endregion
                Seperators(2);
                #region Spatial blend

                SetSpatialBlend(baseData);

                #endregion

                Seperators(2);

                #region Delay

                GUILayout.BeginHorizontal();

                GUILayout.BeginVertical();

                InUndoHelper.GUIUndo(baseData, "Randomize Delay", ref baseData.RandomizeDelay, () =>
                                     EditorGUILayout.Toggle("Randomize Delay", baseData.RandomizeDelay));
                if (baseData.RandomizeDelay)
                {
                    InUndoHelper.GUIUndo(baseData, "Delay Change", ref baseData.InitialDelayMin, ref baseData.InitialDelayMax,
                                         (out float v1, out float v2) =>
                    {
                        v1 = Mathf.Clamp(EditorGUILayout.FloatField("Min delay", baseData.InitialDelayMin), 0, baseData.InitialDelayMax);
                        v2 = Mathf.Clamp(EditorGUILayout.FloatField("Max delay", baseData.InitialDelayMax), baseData.InitialDelayMin, float.MaxValue);
                    });
                }
                else
                {
                    InUndoHelper.GUIUndo(baseData, "Delay", ref baseData.InitialDelayMin, () =>
                    {
                        float delay = Mathf.Max(EditorGUILayout.FloatField("Initial delay", baseData.InitialDelayMin), 0);
                        if (delay > baseData.InitialDelayMax)
                        {
                            baseData.InitialDelayMax = baseData.InitialDelayMin + 0.001f;
                        }
                        return(delay);
                    });
                }

                GUILayout.EndVertical();

                GUILayout.BeginVertical();

                GUILayout.EndVertical();

                GUILayout.EndHorizontal();
                #endregion

                Seperators(2);

                #region Audio bus

                DataDrawerHelper.DrawMixer(node);

                #endregion

                Seperators(2);

                #region Loops

                GUI.enabled = true;
                GUILayout.BeginVertical();

                InUndoHelper.GUIUndo(baseData, "Use looping", ref baseData.Loop, () => EditorGUILayout.Toggle("Loop", baseData.Loop));
                if (baseData.Loop)
                {
                    GUI.enabled = baseData.Loop;

                    InUndoHelper.GUIUndo(baseData, "Loop Infinite", ref baseData.LoopInfinite,
                                         () => EditorGUILayout.Toggle("Loop Infinite", baseData.LoopInfinite));
                    if (baseData.Loop)
                    {
                        GUI.enabled = !baseData.LoopInfinite;
                    }

                    InUndoHelper.GUIUndo(baseData, "Loop Randomize", ref baseData.RandomizeLoops,
                                         () => EditorGUILayout.Toggle("Randomize Loop Count", baseData.RandomizeLoops));

                    if (!baseData.RandomizeLoops)
                    {
                        InUndoHelper.GUIUndo(baseData, "Loop Count",
                                             ref baseData.MinIterations, () => (byte)Mathf.Clamp(EditorGUILayout.IntField("Loop Count", baseData.MinIterations), 0, 255));
                    }
                    else
                    {
                        GUILayout.BeginHorizontal();
                        InUndoHelper.GUIUndo(baseData, "Loop Count", ref baseData.MinIterations, ref baseData.MaxIterations,
                                             (out byte v1, out byte v2) =>
                        {
                            v1 = (byte)Mathf.Clamp(EditorGUILayout.IntField("Min Loop Count", baseData.MinIterations), 0, 255);
                            v2 = (byte)Mathf.Clamp(EditorGUILayout.IntField("Max Loop Count", baseData.MaxIterations), 0, 255);

                            //Clamp to 0-255 and so that min/max doesn't overlap
                            v2 = (byte)Mathf.Clamp(v2, v1, 255);
                            v1 = (byte)Mathf.Clamp(v1, 0, v2);
                        });

                        GUILayout.EndHorizontal();
                    }
                }

                GUI.enabled = true;

                GUILayout.EndVertical();

                #endregion

                Seperators(2);

                #region Instance limiting
                InUndoHelper.GUIUndo(baseData, "Limit Instances (Global)", ref baseData.LimitInstances, () => EditorGUILayout.Toggle("Limit Instances", baseData.LimitInstances));
                GUI.enabled = baseData.LimitInstances;
                if (baseData.LimitInstances)
                {
                    InUndoHelper.GUIUndo(baseData, "Max Instance Cont", ref baseData.MaxInstances, () => Math.Max(EditorGUILayout.IntField("Max Instance Count", baseData.MaxInstances), 0));
                    InUndoHelper.GUIUndo(baseData, "Stealing Type", ref baseData.InstanceStealingTypes, () => (InstanceStealingTypes)EditorGUILayout.EnumPopup("Stealing Type", baseData.InstanceStealingTypes));
                }
                GUI.enabled = true;

                #endregion

                Seperators(2);

                #region Priority
                InUndoHelper.GUIUndo(baseData, "Priority", ref baseData.Priority, () => EditorGUILayout.IntSlider("Priority", baseData.Priority, 0, 255));
                #endregion

                Seperators(2);

                #region Sample offset
                InUndoHelper.GUIUndo(baseData, "Random Second Offset", ref baseData.RandomSecondsOffset, () =>
                                     EditorGUILayout.Toggle("Random Second Offset", baseData.RandomSecondsOffset));

                if (baseData.RandomSecondsOffset)
                {
                    InUndoHelper.GUIUndo(baseData, "First item offset", ref baseData.MinSecondsOffset, ref baseData.MaxSecondsOffset,
                                         (out float v1, out float v2) =>
                    {
                        v1 = Mathf.Clamp(EditorGUILayout.FloatField("Min offset", baseData.MinSecondsOffset), 0, baseData.MaxSecondsOffset);
                        v2 = Mathf.Clamp(EditorGUILayout.FloatField("Max offset", baseData.MaxSecondsOffset), baseData.MinSecondsOffset, float.MaxValue);
                    });
                }
                else
                {
                    InUndoHelper.GUIUndo(baseData, "Delay", ref baseData.MinSecondsOffset, () =>
                    {
                        var delay = Mathf.Max(EditorGUILayout.FloatField("First clip offset", baseData.MinSecondsOffset), 0);
                        if (delay > baseData.MaxSecondsOffset)
                        {
                            baseData.MaxSecondsOffset = baseData.MinSecondsOffset + 1;
                        }
                        return(delay);
                    });
                }

                if (node._type == AudioNodeType.Audio)
                {
                    var nodeData = node._nodeData as InAudioData;
                    if (nodeData._clip != null)
                    {
                        float length = nodeData._clip.ExactLength();
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PrefixLabel("Clip length");
                        EditorGUILayout.SelectableLabel(length.ToString(), GUILayout.Height(EditorGUIUtility.singleLineHeight));
                        EditorGUILayout.EndHorizontal();
                        if (baseData.RandomSecondsOffset && (baseData.MinSecondsOffset > length || baseData.MaxSecondsOffset > length))
                        {
                            EditorGUILayout.HelpBox("Offset exceeds sound clip length", MessageType.Warning);
                        }
                        else if (baseData.MinSecondsOffset > length)
                        {
                            EditorGUILayout.HelpBox("Offset exceeds sound clip length", MessageType.Warning);
                        }
                    }
                }
                #endregion
            }
            else
            {
                #region Attenuation

                if (!node._parent.IsRootOrFolder)
                {
                    InUndoHelper.GUIUndo(baseData, "Override Parent", ref baseData.OverrideAttenuation, () => GUILayout.Toggle(baseData.OverrideAttenuation, "Override Parent"));
                }
                GUI.enabled = baseData.OverrideAttenuation;
                if (node._parent.IsRootOrFolder)
                {
                    GUI.enabled = true;
                }

                InUndoHelper.GUIUndo(node, "Rolloff Mode", ref baseData.RolloffMode, () => (AudioRolloffMode)EditorGUILayout.EnumPopup("Volume Rolloff", baseData.RolloffMode));

                InUndoHelper.GUIUndo(baseData, "Set Rolloff Distance", ref baseData.MinDistance, ref baseData.MaxDistance,
                                     (out float v1, out float v2) =>
                {
                    if (baseData.RolloffMode != AudioRolloffMode.Custom)
                    {
                        v1 = EditorGUILayout.FloatField("Min Distance", baseData.MinDistance);
                    }
                    else
                    {
                        v1 = baseData.MinDistance;
                    }
                    v2 = EditorGUILayout.FloatField("Max Distance", baseData.MaxDistance);
                    v1 = Mathf.Max(v1, 0.00001f);
                    v2 = Mathf.Max(v2, v1 + 0.01f);
                });



                if (baseData.RolloffMode == AudioRolloffMode.Custom)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel("Rolloff");

                    InUndoHelper.GUIUndo(baseData, "Set Rolloff Curve", ref baseData.FalloffCurve, () => EditorGUILayout.CurveField(baseData.FalloffCurve, GUILayout.Height(200), GUILayout.Width(200)));
                    //baseData.FalloffCurve = EditorGUILayout.CurveField(baseData.FalloffCurve, GUILayout.Height(200), GUILayout.Width(200));
                    EditorGUILayout.EndHorizontal();

                    var keys     = baseData.FalloffCurve.keys;
                    int keyCount = keys.Length;
                    for (int i = 0; i < keyCount; i++)
                    {
                        Keyframe key = keys[i];

                        key.time  = Mathf.Clamp01(key.time);
                        key.value = Mathf.Clamp01(key.value);
                        try
                        {
                            baseData.FalloffCurve.MoveKey(i, key);
                        }
                        catch (Exception)
                        {
                        }
                    }
                    if (GUILayout.Button("Reset curve", GUILayout.Width(150)))
                    {
                        InUndoHelper.RecordObject(baseData, "Reset Curve");
                        baseData.FalloffCurve = new AnimationCurve(new Keyframe(0, 1), new Keyframe(0.1f, 1), new Keyframe(1, 0));
                    }

                    if (Selection.activeObject == null)
                    {
                        EditorGUILayout.HelpBox("Please select any game object in the scene.\nIt fixes a bug in Unity Editor API",
                                                MessageType.Info, true);
                    }

                    EditorGUILayout.HelpBox("Unity does not support setting custom rolloff via scripts. This will perform slower than a log/linear rolloff curve", MessageType.Warning, true);
                    GUI.enabled = false;
                }

                #endregion

                GUI.enabled = true;
            }
        }
Example #54
0
 internal static TangentMode GetKeyRightTangentMode(Keyframe key)
 {
     return(Internal_GetKeyRightTangentMode(key));
 }
        public static AnimationClip CreateDefaultPose(RigBuilder rigBuilder)
        {
            if (rigBuilder == null)
            {
                throw new ArgumentNullException("It is not possible to bake curves without an RigBuilder.");
            }

            var defaultPoseClip = new AnimationClip()
            {
                name = "DefaultPose"
            };

            if (!AnimationMode.InAnimationMode())
            {
                return(defaultPoseClip);
            }

            var bindings = new List <EditorCurveBinding>();

            var gameObjects = new Queue <GameObject>();

            gameObjects.Enqueue(rigBuilder.gameObject);

            while (gameObjects.Count > 0)
            {
                var gameObject = gameObjects.Dequeue();

                EditorCurveBinding[] allBindings = AnimationUtility.GetAnimatableBindings(gameObject, rigBuilder.gameObject);
                foreach (var binding in allBindings)
                {
                    if (binding.isPPtrCurve)
                    {
                        continue;
                    }

                    if (binding.type == typeof(GameObject))
                    {
                        continue;
                    }

                    UnityEngine.Object target = gameObject.GetComponent(binding.type);
                    if (!AnimationMode.IsPropertyAnimated(target, binding.propertyName))
                    {
                        continue;
                    }

                    bindings.Add(binding);
                }

                // Iterate over all child GOs
                for (int i = 0; i < gameObject.transform.childCount; i++)
                {
                    Transform childTransform = gameObject.transform.GetChild(i);
                    gameObjects.Enqueue(childTransform.gameObject);
                }
            }

            // Flush out animation mode modifications
            AnimationMode.BeginSampling();
            AnimationMode.EndSampling();

            foreach (var binding in bindings)
            {
                float floatValue;
                AnimationUtility.GetFloatValue(rigBuilder.gameObject, binding, out floatValue);

                var key   = new Keyframe(0f, floatValue);
                var curve = new AnimationCurve(new Keyframe[] { key });
                defaultPoseClip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
            }

            return(defaultPoseClip);
        }
Example #56
0
    IEnumerator coReverseAtAngle(float seconds, float forwardAngle, float backwardAngle, int fames, bool isSlowInSlowOut, bool isStopAndGo)
    {
        while (currentBoard != null)
        {
            if (isStopAndGo)
            {
                rotationType = new AnimationCurve(new Keyframe(0, 0), new Keyframe(seconds, 180f), new Keyframe(seconds + stopWaitTime, 180f),
                                                  new Keyframe(seconds * 2, 360f), new Keyframe((seconds * 2) + stopWaitTime, 360f));
                rotationType.preWrapMode  = WrapMode.Loop;
                rotationType.postWrapMode = WrapMode.Loop;

                SetCurveLinear(rotationType);

                currentBoard.transform.eulerAngles = new Vector3(currentBoard.transform.eulerAngles.x, currentBoard.transform.eulerAngles.y, rotationType.Evaluate(Time.time));
                yield return(null);
            }
            else
            {
                rotationType = new AnimationCurve();
                Keyframe[] newKeys      = new Keyframe[fames];
                int        multiplier   = 0;
                float      currentAngle = 0;

                for (int i = 0; i < newKeys.Length; i++)
                {
                    if (i == 0)
                    {
                        newKeys[i].time  = 0;
                        newKeys[i].value = 0;
                    }
                    else if (i % 2 != 0)
                    {
                        newKeys[i].time  = seconds * multiplier;
                        currentAngle    += forwardAngle;
                        newKeys[i].value = currentAngle;
                    }
                    else
                    {
                        newKeys[i].time  = seconds * multiplier;
                        currentAngle    -= backwardAngle;
                        newKeys[i].value = currentAngle;
                    }

                    multiplier++;

                    rotationType.AddKey(newKeys[i]);
                }

                rotationType.preWrapMode  = WrapMode.Loop;
                rotationType.postWrapMode = WrapMode.Loop;

                if (isSlowInSlowOut)
                {
                    currentBoard.transform.eulerAngles = new Vector3(currentBoard.transform.eulerAngles.x, currentBoard.transform.eulerAngles.y, rotationType.Evaluate(Time.time));
                    yield return(null);
                }
                else
                {
                    SetCurveLinear(rotationType);

                    currentBoard.transform.eulerAngles = new Vector3(currentBoard.transform.eulerAngles.x, currentBoard.transform.eulerAngles.y, rotationType.Evaluate(Time.time));
                    yield return(null);
                }
            }
        }
    }
        public static AnimationCurve[] CompressCurves(AnimationCurve[] curves,
                                                      Func <AnimationCurve[], AnimationCurve[], float, bool> isGood,
                                                      int checkSteps = 8)
        {
            var keyframes        = new Keyframe[curves.Length][];
            var position         = new int[curves.Length];
            var nextFrame        = new int[curves.Length];
            var compressedCurves = new AnimationCurve[curves.Length];

            for (int i = 0; i < curves.Length; i++)
            {
                var keys = curves[i].keys;

                compressedCurves[i] = new AnimationCurve(keys);

                for (int j = 0; j < keys.Length; j++)
                {
                    var leftT  = AnimationUtility.GetKeyLeftTangentMode(curves[i], j);
                    var rightT = AnimationUtility.GetKeyRightTangentMode(curves[i], j);

                    AnimationUtility.SetKeyLeftTangentMode(compressedCurves[i], j, leftT);
                    AnimationUtility.SetKeyRightTangentMode(compressedCurves[i], j, rightT);
                }

                keyframes[i] = keys;
                position[i]  = keys.Length - 2;
                nextFrame[i] = keys.Length - 1;
            }

            do
            {
                for (int i = 0; i < curves.Length; i++)
                {
                    if (position[i] > 0)
                    {
                        Keyframe nextKeyframe = keyframes[i][nextFrame[i]];
                        Keyframe currKeyframe = keyframes[i][position[i]];
                        Keyframe prevKeyframe = keyframes[i][position[i] - 1];

                        var leftT  = AnimationUtility.GetKeyLeftTangentMode(compressedCurves[i], position[i]);
                        var rightT = AnimationUtility.GetKeyRightTangentMode(compressedCurves[i], position[i]);
                        compressedCurves[i].RemoveKey(position[i]);

                        for (int k = 0; k < checkSteps; k++)
                        {
                            float percent = k / (checkSteps - 1.0f);

                            float prevTime = Mathf.Lerp(currKeyframe.time, prevKeyframe.time, percent);
                            float nextTime = Mathf.Lerp(currKeyframe.time, nextKeyframe.time, percent);

                            bool isPrevGood = isGood(curves, compressedCurves, prevTime);
                            bool isNextgood = isGood(curves, compressedCurves, nextTime);

                            if (!isPrevGood || !isNextgood)
                            {
                                int index = compressedCurves[i].AddKey(currKeyframe);
                                AnimationUtility.SetKeyLeftTangentMode(compressedCurves[i], index, leftT);
                                AnimationUtility.SetKeyRightTangentMode(compressedCurves[i], index, rightT);

                                nextFrame[i] = position[i];
                                break;
                            }
                        }

                        position[i]--;
                    }
                }
            } while (position.Query().Any(p => p > 0));

            return(compressedCurves);
        }
Example #58
0
 extern private static void Internal_SetKeyRightTangentMode(ref Keyframe key, TangentMode tangentMode);
 private void SetCurve(CurveWrapper cw, AnimationCurve curve)
 {
     Keyframe[] destinationArray = new Keyframe[curve.keys.Length];
     Array.Copy(curve.keys, destinationArray, destinationArray.Length);
     cw.curve.keys = destinationArray;
     cw.changed = true;
 }
        public void AddTangentMenuItems(GenericMenu menu, List <KeyIdentifier> keyList)
        {
            bool anyKeys = (keyList.Count > 0);
            // Find out which qualities apply to all the keys
            bool allClampedAuto   = anyKeys;
            bool allAuto          = anyKeys;
            bool allFreeSmooth    = anyKeys;
            bool allFlat          = anyKeys;
            bool allBroken        = anyKeys;
            bool allLeftWeighted  = anyKeys;
            bool allLeftFree      = anyKeys;
            bool allLeftLinear    = anyKeys;
            bool allLeftConstant  = anyKeys;
            bool allRightWeighted = anyKeys;
            bool allRightFree     = anyKeys;
            bool allRightLinear   = anyKeys;
            bool allRightConstant = anyKeys;

            foreach (KeyIdentifier sel in keyList)
            {
                Keyframe    key       = sel.keyframe;
                TangentMode leftMode  = AnimationUtility.GetKeyLeftTangentMode(key);
                TangentMode rightMode = AnimationUtility.GetKeyRightTangentMode(key);
                bool        broken    = AnimationUtility.GetKeyBroken(key);
                if (leftMode != TangentMode.ClampedAuto || rightMode != TangentMode.ClampedAuto)
                {
                    allClampedAuto = false;
                }
                if (leftMode != TangentMode.Auto || rightMode != TangentMode.Auto)
                {
                    allAuto = false;
                }
                if (broken || leftMode != TangentMode.Free || rightMode != TangentMode.Free)
                {
                    allFreeSmooth = false;
                }
                if (broken || leftMode != TangentMode.Free || key.inTangent != 0 || rightMode != TangentMode.Free || key.outTangent != 0)
                {
                    allFlat = false;
                }
                if (!broken)
                {
                    allBroken = false;
                }
                if (!broken || leftMode != TangentMode.Free)
                {
                    allLeftFree = false;
                }
                if (!broken || leftMode != TangentMode.Linear)
                {
                    allLeftLinear = false;
                }
                if (!broken || leftMode != TangentMode.Constant)
                {
                    allLeftConstant = false;
                }
                if (!broken || rightMode != TangentMode.Free)
                {
                    allRightFree = false;
                }
                if (!broken || rightMode != TangentMode.Linear)
                {
                    allRightLinear = false;
                }
                if (!broken || rightMode != TangentMode.Constant)
                {
                    allRightConstant = false;
                }


                if ((key.weightedMode & WeightedMode.In) == WeightedMode.None)
                {
                    allLeftWeighted = false;
                }
                if ((key.weightedMode & WeightedMode.Out) == WeightedMode.None)
                {
                    allRightWeighted = false;
                }
            }
            if (anyKeys)
            {
                menu.AddItem(EditorGUIUtility.TrTextContent("Clamped Auto"), allClampedAuto, SetClampedAuto, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Auto"), allAuto, SetAuto, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Free Smooth"), allFreeSmooth, SetEditable, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Flat"), allFlat, SetFlat, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Broken"), allBroken, SetBroken, keyList);
                menu.AddSeparator("");
                menu.AddItem(EditorGUIUtility.TrTextContent("Left Tangent/Free"), allLeftFree, SetLeftEditable, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Left Tangent/Linear"), allLeftLinear, SetLeftLinear, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Left Tangent/Constant"), allLeftConstant, SetLeftConstant, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Left Tangent/Weighted"), allLeftWeighted, ToggleLeftWeighted, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Right Tangent/Free"), allRightFree, SetRightEditable, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Right Tangent/Linear"), allRightLinear, SetRightLinear, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Right Tangent/Constant"), allRightConstant, SetRightConstant, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Right Tangent/Weighted"), allRightWeighted, ToggleRightWeighted, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Both Tangents/Free"), allRightFree && allLeftFree, SetBothEditable, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Both Tangents/Linear"), allRightLinear && allLeftLinear, SetBothLinear, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Both Tangents/Constant"), allRightConstant && allLeftConstant, SetBothConstant, keyList);
                menu.AddItem(EditorGUIUtility.TrTextContent("Both Tangents/Weighted"), allRightWeighted && allLeftWeighted, ToggleBothWeighted, keyList);
            }
            else
            {
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Weighted"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Auto"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Free Smooth"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Flat"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Broken"));
                menu.AddSeparator("");
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Left Tangent/Free"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Left Tangent/Linear"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Left Tangent/Constant"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Left Tangent/Weighted"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Right Tangent/Free"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Right Tangent/Linear"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Right Tangent/Constant"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Right Tangent/Weighted"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Both Tangents/Free"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Both Tangents/Linear"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Both Tangents/Constant"));
                menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Both Tangents/Weighted"));
            }
        }