如何在Unity中使用JSON文件中的时间戳数据
我目前正在处理一个JSON文件文件夹,这些文件是通过无人机跟踪实验收集的。数据包含无人机在跟踪系统内移动和悬浮时的位置、旋转和时间戳。 我现在正在做的是用这些数据模拟Unity内部无人驾驶飞机的运动。到目前为止,我已经成功地将位置和旋转从数据解析到Unity中的对象,并将时间戳提取到Unity中的System.DateTime。 但是,我不知道如何使用时间戳。我想使用时间戳来匹配对象的位置和旋转(即:在这个时间戳,无人机应该在这个位置(x,y,z)并具有旋转(x,y,z,w))。有人能帮我解决这个问题吗,非常感谢你的帮助:D这是我当前的代码:如何在Unity中使用JSON文件中的时间戳数据,json,unity3d,time,timestamp,Json,Unity3d,Time,Timestamp,我目前正在处理一个JSON文件文件夹,这些文件是通过无人机跟踪实验收集的。数据包含无人机在跟踪系统内移动和悬浮时的位置、旋转和时间戳。 我现在正在做的是用这些数据模拟Unity内部无人驾驶飞机的运动。到目前为止,我已经成功地将位置和旋转从数据解析到Unity中的对象,并将时间戳提取到Unity中的System.DateTime。 但是,我不知道如何使用时间戳。我想使用时间戳来匹配对象的位置和旋转(即:在这个时间戳,无人机应该在这个位置(x,y,z)并具有旋转(x,y,z,w))。有人能帮我解决这
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);
}
}
void Update()
{
如果(已加载)
{
对于(int i=0;i,如果我理解正确,您得到的是真实世界无人机的样本,该无人机以某种速率存储其运动的关键帧
现在,您已经成功加载了json数据,但想知道如何相应地设置Unity对象的动画
您根本无法使用的时间戳本身!^^
它很可能就在过去的某个地方;)你不能只给它分配一些东西
但是,您可以做的是获取第一个样本的时间戳(我将假设您的样本在该时间点之前已经全部订购),然后计算与下一个样本的差异,以此类推
然后,您可以使用该差异,以便始终使用给定的时间增量在当前和下一个采样变换之间进行插值
目前,您只需在一个帧中执行all采样,因此根本不会有任何动画
另请注意:
for(int i = 0; i <= pos_data.Count; i+= 10)
然后
// 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;
}
嗨,德胡戈,首先,我想说谢谢你令人惊讶的回答。它真的帮助我理解了很多我在解决问题时从未想过的事情。我确实尝试过使用你的解决方案,到目前为止,它工作得很有魅力。真的感谢你的帮助:)
// 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;
}
// 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
}