Как сериализовать объект в JSON в Unity - PullRequest
0 голосов
/ 23 января 2019

Я пытаюсь сериализовать огромный класс с вложенными классами, AudioClip и texture2D.Я реализовал интерфейс ISerializable и пометил все классы с помощью SerializableAttribute.Я использую JsonUtility для преобразования в Json и обратно.

Все работает хорошо, кроме Textures2D, Textures2D [] и AudioClip.Ниже описана реализация метода ISerializable:

[Serializable]
public class Illustration : ISerializable
{
    public Texture2D Image = new Texture2D(256, 256);

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(nameof(Image), Image.EncodeToPNG(), typeof(byte[]));
    }

    private Illustration(SerializationInfo info, StreamingContext context)
    {
        Image.LoadImage(info.GetValue(nameof(Image), typeof(byte[])) as byte[]);
    }
}

[Serializable]
public class CustomAnimation : ISerializable
{
    public Texture2D[] Images;

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(nameof(Images), Images.Select(x => x.EncodeToPNG()).ToArray(), typeof(byte[][]));
    }

    private CustomAnimation(SerializationInfo info, StreamingContext context)
    {
        var textures = info.GetValue(nameof(Images), typeof(byte[][])) as byte[][];
        if (textures != null)
        {
            var imagesAndTextures = Images.Zip(textures, (i, t) => new {Images = i, textures = t});
            foreach (var it in imagesAndTextures)
            {
                it.Images.LoadImage(it.textures);
            }
        }
    }
}

Я ожидаю, что этот код создаст JSON с байтовыми массивами текстур, но я получаю это:

"Illustrations": [
                {
                    "Image": {
                        "instanceID": 34540
                    }
                }
]

Почему у меня этоINSTANCEID?Мне нужна бинарная текстура, чтобы сохранить ее в текстовом файле.Это не объект времени выполнения.

Ответы [ 3 ]

0 голосов
/ 23 января 2019

ваш подход выглядит хорошо - я думаю, что он не работает из-за внутренней работы UnityEngine, где части данных находятся на стороне управляемого / c #, а части на стороне native / c ++. Это становится еще сложнее для текстур, которые могут жить как на GPU, так и на Ram / GPU, если они помечены как читаемые. Самый причудливый случай - rendertextures, которые прекрасно живут на грани и имеют некоторые странные поведения (то есть они не собирают мусор, даже когда вы теряете ссылку).

Обходной путь кажется довольно тривиальным - создайте сериализуемое поле byte [], заполните его закодированной текстурой (или почтовым индексом, как вы делаете) - возможно, даже заранее (перед сериализацией).

0 голосов
/ 23 января 2019

Хранить текстуру в виде байтового массива в json не очень хорошая идея, никто этого не делает, и для этого должна быть причина.

Если вам это действительно нужно, тогда вам нужен байтовый массивиз вашей текстуры, скорее всего, как jpeg, поэтому он меньше:

byte [] tex = texture.EncodeToJpg();
var str = System.Text.Encoding.Default.GetString(tex);
JsonObject json = new JsonObject();   // pseudo code for a json parser
json.Add("Illustration", str);

и наоборот:

string str = json.GetString("Illustration");
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);

Но, как это на самом деле делается, JSON содержит URLтолько изображения.

Нет особой цели сохранить текстуру в виде строкового байтового массива, поскольку jpg - это уже текстовый файл, содержащий байтовый массив, скорее всего, в двоичном виде.Итак, со вторым подходом вы бы разбили свой JSON и сделали бы его действительно читабельным.

0 голосов
/ 23 января 2019

Я думаю, что вы не можете сериализовать само изображение. Он был загружен в память, и изображение является справочным.

Другое дело, что если вы измените какое-либо свойство текстуры, оно создаст новое, потеряв также ссылку на исходное.

Что вы можете сделать, это создать еще один массив с именем текстуры и затем применить его при загрузке JSon.

...