簡體   English   中英

如何在 Unity 中使用 JSON 文件中的時間戳數據

[英]How to use the Timestamp data from JSON file in Unity

我目前正在使用 JSON 文件的文件夾,這些文件是通過無人機的跟蹤實驗收集的。 數據包含 position、無人機在跟蹤系統內移動和懸浮時的旋轉和時間戳。 我目前正在做的是嘗試使用這些數據來模擬 Unity 中無人機的運動。 到目前為止,我已經成功解析了 position 並將數據旋轉到 Unity 中的 object 並將時間戳提取到 Unity 中的 System.DateTime。 但是,我不知道如何使用時間戳。 我想使用時間戳來匹配 position 和 object 的旋轉(即:在這個時間戳,無人機應該在這個位置(x,y,z)並且具有旋轉(x,y,z,w)) . 有人可以幫我解決這個問題嗎,非常感謝您的幫助:D 這是我當前的代碼:

void Update()
 {
     if (loaded)
     {
         for(int i = 0; i <= pos_data.Count; i+= 10)
         {
             Cube.transform.position = pos_data[i];
             Cube.transform.rotation = rot_data[i];
         }
     }
     else
     {
         LoadJson();
         //startTime = datetime[0];
         loaded = true;
     }
 }
 public void LoadJson()
 {
     string HeadPath = @Application.dataPath + "/Data/" + "drone_data_1.json";
     string HeadJsonhold = File.ReadAllText(HeadPath);
     var data_ = JSON.Parse(HeadJsonhold);
     
     for (int rows = 0; rows <= data_.Count; rows += 10)
     {
         pos_data.Add(new Vector3(data_[rows]["location"]["x"].AsFloat, data_[rows]["location"]["y"].AsFloat, data_[rows]["location"]["z"].AsFloat));
         rot_data.Add(new Quaternion(data_[rows]["rotation"]["x"].AsFloat, data_[rows]["rotation"]["y"].AsFloat, data_[rows]["rotation"]["z"].AsFloat, data_[rows]["rotation"]["w"].AsFloat));
         Time = System.DateTime.ParseExact(data_[rows]["Timestamp"], "yyyyMMddHHmmss",null);
         //Debug.Log(Time);
     }    
 }

如果我理解正確的話,你得到的是真實世界無人機的樣本,它以某種速度存儲其運動的關鍵幀。

現在您已經成功加載了 json 數據,但想知道如何相應地為 Unity object 設置動畫。


您根本無法使用的時間戳本身! ^^

它很可能位於過去的某個地方;)而且您不能只為Time分配一些東西。

但是,您可以做的是獲取第一個樣本的時間戳(我假設您的樣本都已按時間排序)並計算與下一個樣本的差異,依此類推。

然后,您可以使用該差異,以便始終使用給定的時間增量在當前和下一個樣本轉換之間進行插值。

目前,您只是在一個幀中完成所有樣本,因此根本不會有任何 animation。

也正如旁注:

for(int i = 0; i <= pos_data.Count; i+= 10)

錯了兩次:

  • a)您在加載數據時已經跳過了 10 個樣本 -> 您確定現在要再次跳過其中的 10 個 => 每次總共跳過 100 個樣本嗎?
  • b) 由於索引是基於0的最后一個可訪問的索引將是pos_data.Count - 1所以通常在迭代列表/數組時它應該是i < pos_data.Count ;)

首先,我建議您使用更好的數據結構並使用一個列表來保存屬於一起的信息而不是多個並行列表,而是加載您的 json ,例如

[Serializable]
public class Sample 
{
    public readonly Vector3 Position;
    public readonly Quaternion Rotation;
    public readonly float TimeDelta;

    public Sample(Vector3 position, Quaternion rotation, float timeDelta)
    {
        Position = position;
        Rotation = rotation;
        TimeDelta = timeDelta;
    }
}

接着

// Just making this serialized so you can immediately see in the Inspector
// if your data loaded correctly
[SerializeField] private readonly List<Sample> _samples = new List<Sample>();

public void LoadJson()
{
     // start fresh
     _samples.Clear();

     // See https://docs.microsoft.com/dotnet/api/system.io.path.combine
     var path = Path.Combine(Application.dataPath, "Data", "drone_data_1.json");
     var json = File.ReadAllText(path);
     var data = JSON.Parse(json);
     
     DateTime lastTime = default;

     for (var i = 0; i <= data.Count; i += 10)
     {
         // First I would pre-cache these values 
         var sample = data[i];
         var sampleLocation = sample["location"];
         var sampleRotation = sample["rotation"];
         var sampleTime = sample["Timestamp"];

         // Get your values as you did already
         var position = new Vector3(sampleLocation["x"].AsFloat, sampleLocation["y"].AsFloat, sampleLocation["z"].AsFloat));
         var rotation = new Quaternion(sampleRotation["x"].AsFloat, sampleRotation["y"].AsFloat, sampleRotation["z"].AsFloat, sampleRotation["w"].AsFloat));
         
         var time = System.DateTime.ParseExact(sampleTime, "yyyyMMddHHmmss", null);
          
         // Now for the first sample there is no deltaTime
         // for all others calculate the difference in seconds between the
         // last and current sample
         // See https://docs.microsoft.com/dotnet/csharp/language-reference/operators/conditional-operator
         var deltaTime = i == 0 ? 0f : GetDeltaSeconds(lastTime, time);
         // and of course store it for the next iteration
         lastTime = time;

         // Now you can finally add the sample to the list of samples
         // instead of having multiple parallel lists 
         _samples.Add(new Sample(position, rotation, deltaTime));
     }    
 }

private float GetDeltaSeconds(DateTime first, DateTime second)
{
    // See https://docs.microsoft.com/dotnet/api/system.datetime.op_subtraction#System_DateTime_op_Subtraction_System_DateTime_System_DateTime_
    var deltaSpan = second - first;
    // See https://docs.microsoft.com/dotnet/api/system.timespan.totalseconds#System_TimeSpan_TotalSeconds
    return (float)deltaSpan.TotalSeconds;
}

那么現在如何處理這些信息呢?

您現在有樣本(仍然假設按時間排序)包含所有必需的信息,以便能夠在它們之間進行插值。

我會使用Coroutines而不是Update ,在我看來它們更容易理解和維護

// Do your loading **once** in Start
private void Start()
{
    LoadJson();

    // Then start the animation routine
    // I just make it a method so you could also start it later e.g. via button etc
    StartAnimation();
}

// A flag just in case to avoid concurrent animations
private bool alreadyAnimating;

// As said just making this a method so you could also remove it from Start
// and call it in any other moment you like
public void StartAnimation()
{
    // Only start an animation if there isn't already one running
    // See https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
    if(!alreadyAnimating) StartCoroutine(AnimationRoutine());
}

private IEnumerator AnimationRoutine()
{
    // Just in case abort if there is already another animation running
    if(alreadyAnimating) yield break;

    // Block concurrent routine
    alreadyAnimating = true;

    // Initially set your object to the first sample
    var lastSample = _samples[0];
    Cube.transform.position = lastSample.Position;
    Cube.transform.rotation = lastSample.Rotation;

    // This tells Unity to "pause" the routine here, render this frame
    // and continue from here in the next frame
    yield return null;

    // then iterate through the rest of samples
    for(var i = 1; i < _samples.Count; i++)
    {
        var lastPosition = lastSample.Position;
        var lastRottaion = lastSample.Rottaion;

        var currentSample = _samples[i];
        var targetPosition = sample.Position;
        var targetRotation = sample.Rotation; 

        // How long this interpolation/animation will take
        var duration = currentSample.TimeDelta;
       
        // You never know ;)
        // See https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html
        if(Mathf.Approximately(duration, 0f))
        {
            Cube.transform.position = targetPosition;
            Cube.transform.rotation = targetRotation;
            lastSample = currentSample;
            continue;
        }
     
        // And this is where the animation magic happens
        var timePassed = 0f; 
        while(timePassed < duration)
        {
            // this factor will be growing linear between 0 and 1
            var factor = timePassed / duration;

            // Interpolate between the "current" transforms (the ones it had at beginning of this iteration)
            // towards the next sample target transforms using the factor between 0 and 1
            // See https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
            Cube.transform.position = Vector3.Lerp(lastPosition, targetPosition, factor);
            // See https://docs.unity3d.com/ScriptReference/Quaternion.Slerp.html
            Cube.transform.rotation = Quaternion.Slerp(lastRotation, targetRotation, factor);

            // This tells Unity to "pause" the routine here, render this frame
            // and continue from here in the next frame
            yield return null;

            // increase by the time passed since the last frame was rendered
            timePassed += Time.deltaTime;
        }

        // just to be sure to end with clean values
        Cube.transform.position = targetPosition;
        Cube.transform.rotation = targetRotation;
        lastSample = currentSample;
    }

    // Allow the next animation to start (or restart this one)
    alreadyAnimating = false;

    // Additional stuff to do once the animation is done
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM