json Unity API返回Vector3,但值错误

8ehkhllq  于 2023-05-30  发布在  其他
关注(0)|答案(1)|浏览(289)

我正在使用Replicate API尝试在Unity中获取点云。我最后使用API返回一个JSON文件,我非常确定它返回的是每个点位置的vector3。然而,当我把它转换成一个vector 3时,所有的值都变得不正常,每个数字都像6.852349e-43,甚至一些“NaN”,当在API上它们看起来都是小于0的值时。
这是他们在副本页面上的样子,

"coords": [
    [
      -0.039118800312280655,
      -0.25740715861320496,
      0.28050559759140015
    ],
    [
      0.13176295161247253,
      0.23972494900226593,
      -0.06013050675392151
    ],

然而,当我在Unity中将它们转换为vector3时,它们会像这样返回,x1c 0d1x我假设我不应该将它们转换为vector3?Replicate的页面上说“坐标”是一个[N x 3]数组(X,Y,Z)点坐标”,经过广泛的谷歌搜索,我不知道NX 3是什么意思。我尝试了float[,]float[,,]float[][]而不是vector3,但vector3是唯一一个从JSON文件中正确分配的(使用JsonUtility.FromJson
这是我调用API的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using SimpleJSON;

public class Prompt
{
    public string prompt;
}

public class PostResponse
{

    public string completed_at;
    public string created_at;
    public string error;
    public string id;
    public Prompt input;
    public string[] logs;
    public string metrics;
    public Output output;
    public string started_at;
    public string status;
    public string version;

}

public class ReplicateAPI : MonoBehaviour
{
    private string API_ENDPOINT = "https://api.replicate.com/v1/predictions";
    private string REPLICATE_API_TOKEN = "r8_DhOE6C7LuA7edPvLh7Io0ukwbmXCLEY450vc3";

    [SerializeField] PointEResponse response;

    public string prompt = "dog";

    [SerializeField] Material material;

    [SerializeField] MeshFilter meshFilter;

    private void Start()
    {
        StartCoroutine(Predict());
    }

    IEnumerator Predict()
    {
        string requestData = $@"{{
    ""version"": ""1a4da7adf0bc84cd786c1df41c02db3097d899f5c159f5fd5814a11117bdf02b"",
    ""input"": {{
        ""prompt"": ""{prompt}"",
        ""output_format"": ""json_file""
    }}
}}";

        UnityWebRequest request = UnityWebRequest.Put(API_ENDPOINT, requestData);
        request.method = "POST";
        request.SetRequestHeader("Authorization", "Token " + REPLICATE_API_TOKEN);
        request.SetRequestHeader("Content-Type", "application/json");

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError("Error " + request.responseCode + ": " + request.error);
            StartCoroutine(Predict());
        }
        else
        {
            Debug.Log(request.downloadHandler.text);
            PostResponse response = JsonUtility.FromJson<PostResponse>(request.downloadHandler.text);

            StartCoroutine(GetResult(response.id));
        }
    }

    IEnumerator GetResult(string id)
    {
        yield return new WaitForSeconds(5);
        UnityWebRequest request = UnityWebRequest.Get(API_ENDPOINT + "/" + id);
        request.SetRequestHeader("Authorization", "Token " + REPLICATE_API_TOKEN);
        request.SetRequestHeader("Content-Type", "application/json");


        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError("Error " + request.responseCode + ": " + request.error);
            yield break;
        }
        else
        {
            response = JsonUtility.FromJson<PointEResponse>(request.downloadHandler.text);


            Debug.Log(request.downloadHandler.text);
        }

        if (response.status != "succeeded") StartCoroutine(GetResult(id));
        else
        {

            if (response.output.json_file.colors != null && response.output.json_file.colors.Length > 0)
            {

                for (int i = 0; i < response.output.json_file.colors.Length; i++)
                {

                    GameObject g = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    g.transform.localScale = Vector3.one / 100;
                    g.transform.position = new Vector3(response.output.json_file.coords[i].x, response.output.json_file.coords[i].y, response.output.json_file.coords[i].z);
                    Material m = new Material(material);
                    m.color = new Color(response.output.json_file.colors[i].x, response.output.json_file.colors[i].y, response.output.json_file.colors[i].z);
                    g.GetComponent<MeshRenderer>().material = m;
                }

            }
            else
            {
                StartCoroutine(GetResult(id));
            }
        }
    }

}

“响应”类看起来像这样,

using System;
using UnityEngine;

[Serializable]
public class PointEResponse
{
    public string id;
    public string version;
    public Urls urls;
    public DateTime created_at;
    public DateTime started_at;
    public DateTime completed_at;
    public string source;
    public string status;
    public Prompt input;
    public Output output;
    public object error;
    public string[] logs;
    public Metrics metrics;
}

[Serializable]
public class Output
{
    public JsonFile json_file;
}

[Serializable]
public class JsonFile
{
    public Vector3[] coords;
    public Vector3[] colors;

}

public class Urls
{
    public string get;
    public string cancel;
}

public class Metrics
{
    public float predict_time;
}

其中输出包含坐标和每个坐标的颜色。我假设我不应该将这些转换为Vector 3,但我已经尝试了我所知道的所有其他方法,这是唯一一个甚至返回任何形式的方法。
如何解决此问题?

mtb9vblg

mtb9vblg1#

您在这里得到的JSON不会直接匹配Vector3
例如,Vector3不能直接进行JSON(反)序列化。

"coords": [
    [
      -0.039118800312280655,
      -0.25740715861320496,
      0.28050559759140015
    ],
    [
      0.13176295161247253,
      0.23972494900226593,
      -0.06013050675392151
    ],

意味着你得到的东西看起来像

[Serializable]
public class JsonFile
{
    public float[][] coords;

    // assuming same layout for those
    public float[][] colors;
}

如果以及如何将其在内存中布局成Vector3结构体,我猜是黑魔法。
然而,内置的JsonUtility/Unity的序列化器也不支持这种复杂的集合!
您可能需要第三方库,例如。Newtonsoft Json.NET,作为package via Package Manager提供
如果你用它来代替,你会去例如。

using UnityEngine.Scripting;
using Newtonsoft.Json;

...

[Serializable]
public class JsonFile
{
    public Vector3[] coords;
    public Color[] colors;
    
    // using a JsonConstructor you can directly here ensure your given Json data format is 
    // translated in usable types and structure
    // If this attribute is present Newtonsoft will automatically not directly assign the fields but rather use this constructor 
    // The [Preserve] is to ensure this constructor is not stripped of while building since nothing else will be ever using it
    [Preserve]
    [JsonConstructor]
    public JsonFile(float[][] coords, float[][] colors)
    {
        this.coords = new Vector3[coords.GetLength(0)];
        for (var i = 0; i < this.coords.Length; i++)
        {
            this.coords[i] = new Vector3(coords[i][0], coords[i][1], coords[i][2]);
        }

        this.colors = new Color[colors.GetLength(0)];
        for(var i = 0; i < this.colors.Length; i++)
        {
            this.colors[i] = new Color(colors[i][0], colors[i][1], colors[i][2]);
        }
    }
}

然后离开

var response = JsonConvert.DeserializeObject<PostResponse>(request.downloadHandler.text);

顺便说一句,因为Vector3是一个结构体,你可以简单地做

g.transform.position = response.output.json_file.coords[i];
...
m.color = nresponse.output.json_file.colors[i];

相关问题