0

I have the following JSON scene description:

{
  "$type": "SceneHandler.SceneDescription, SceneHandler",
  "Camera": {
    "$type": "RenderDataStructures.Cameras.Camera, RenderDataStructures",
    "Origin": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": 3.0,
      "Y": 3.0,
      "Z": 2.0
    },
    "LowerLeftCorner": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": -0.9216876,
      "Y": -0.7480924,
      "Z": 0.6697793
    },
    "Horizontal": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": 2.5914667,
      "Y": 0.0,
      "Z": -2.5914667
    },
    "Vertical": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": -0.74809206,
      "Y": 1.4961841,
      "Z": -0.74809206
    },
    "U": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": 0.70710677,
      "Y": 0.0,
      "Z": -0.70710677
    },
    "V": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": -0.4082483,
      "Y": 0.8164966,
      "Z": -0.4082483
    },
    "W": {
      "$type": "System.Numerics.Vector3, System.Private.CoreLib",
      "X": 0.5773503,
      "Y": 0.5773503,
      "Z": 0.5773503
    },
    "LensRadius": 5E-05,
    "Rng": {
      "$type": "System.Random, System.Private.CoreLib"
    }
  },
  "SceneEntities": {
    "$type": "System.Collections.Generic.List`1[[RenderDataStructures.Shapes.IIntersectionTarget, RenderDataStructures]], System.Private.CoreLib",
    "$values": [
      {
        "$type": "RenderDataStructures.Shapes.Sphere, RenderDataStructures",
        "Material": {
          "$type": "RenderDataStructures.Materials.Diffuse, RenderDataStructures",
          "Albedo": {
            "$type": "System.Numerics.Vector3, System.Private.CoreLib",
            "X": 0.8,
            "Y": 0.3,
            "Z": 0.3
          }
        },
        "Center": {
          "$type": "System.Numerics.Vector3, System.Private.CoreLib",
          "X": 0.0,
          "Y": 0.0,
          "Z": -1.0
        },
        "Radius": 0.5,
        "RadiusSquared": 0.25
      },
      {
        "$type": "RenderDataStructures.Shapes.Sphere, RenderDataStructures",
        "Material": {
          "$type": "RenderDataStructures.Materials.Diffuse, RenderDataStructures",
          "Albedo": {
            "$type": "System.Numerics.Vector3, System.Private.CoreLib",
            "X": 0.8,
            "Y": 0.8,
            "Z": 0.0
          }
        },
        "Center": {
          "$type": "System.Numerics.Vector3, System.Private.CoreLib",
          "X": 0.0,
          "Y": -100.5,
          "Z": -1.0
        },
        "Radius": 100.0,
        "RadiusSquared": 10000.0
      },
      {
        "$type": "RenderDataStructures.Shapes.Sphere, RenderDataStructures",
        "Material": {
          "$type": "RenderDataStructures.Materials.Glossy, RenderDataStructures",
          "Albedo": {
            "$type": "System.Numerics.Vector3, System.Private.CoreLib",
            "X": 0.8,
            "Y": 0.6,
            "Z": 0.2
          },
          "Roughness": 0.3
        },
        "Center": {
          "$type": "System.Numerics.Vector3, System.Private.CoreLib",
          "X": 1.0,
          "Y": 0.0,
          "Z": -1.0
        },
        "Radius": 0.5,
        "RadiusSquared": 0.25
      },
      {
        "$type": "RenderDataStructures.Shapes.Sphere, RenderDataStructures",
        "Material": {
          "$type": "RenderDataStructures.Materials.Dielectric, RenderDataStructures",
          "Albedo": {
            "$type": "System.Numerics.Vector3, System.Private.CoreLib",
            "X": 0.95,
            "Y": 0.95,
            "Z": 0.95
          },
          "IndexOfRefraction": 1.33333,
          "Roughness": 0.0001,
          "Rng": {
            "$type": "System.Random, System.Private.CoreLib"
          }
        },
        "Center": {
          "$type": "System.Numerics.Vector3, System.Private.CoreLib",
          "X": -1.0,
          "Y": 0.0,
          "Z": -1.0
        },
        "Radius": 0.5,
        "RadiusSquared": 0.25
      },
      {
        "$type": "RenderDataStructures.Shapes.Sphere, RenderDataStructures",
        "Material": {
          "$type": "RenderDataStructures.Materials.Dielectric, RenderDataStructures",
          "Albedo": {
            "$type": "System.Numerics.Vector3, System.Private.CoreLib",
            "X": 0.95,
            "Y": 0.95,
            "Z": 0.95
          },
          "IndexOfRefraction": 1.33333,
          "Roughness": 0.0,
          "Rng": {
            "$type": "System.Random, System.Private.CoreLib"
          }
        },
        "Center": {
          "$type": "System.Numerics.Vector3, System.Private.CoreLib",
          "X": -1.0,
          "Y": 0.0,
          "Z": -1.0
        },
        "Radius": -0.495,
        "RadiusSquared": 0.24502501
      }
    ]
  }
}

which has been serialized from an object like this:

public class SceneDescription
    {
        public SceneDescription()
        {
            SceneEntities = new List<IIntersectionTarget>();
        }

        public Camera Camera { get; set; }

        public List<IIntersectionTarget> SceneEntities { get; set; }
    }

Camera serializes and deserializes just fine, but when the scene entities are deserialized, they all end up with null/all 0'd data for every field. No errors are thrown. What am I doing wrong?

Serialize method:

public static void ExportScene(SceneDescription p_scene, string p_outputPath)
        {
            var serializedScene = JsonConvert.SerializeObject(p_scene, new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                Formatting = Formatting.Indented
            });

            File.WriteAllLines(p_outputPath, new[] { serializedScene });
        }

Deserialize method:

public static SceneDescription LoadScene(string p_filePath)
        {
            var scene = File.ReadAllText(p_filePath);
            return JsonConvert.DeserializeObject<SceneDescription>(scene, new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All
            });
        }

EDIT: Adding additional definitions

IIntersectionTarget:

public interface IIntersectionTarget
    {
        public IMaterial Material { get; }
        public bool WasHit(Ray p_ray, float p_tMin, float p_tMax, ref HitRecord p_record);
    }

Sphere:

public class Sphere : IIntersectionTarget
    {
        public Sphere(Vector3 p_center, float p_radius, IMaterial p_material)
        {
            Center = p_center;
            Radius = p_radius;
            RadiusSquared = Radius * Radius;
            Material = p_material;
        }

        public IMaterial Material { get; }
        public Vector3 Center { get; }
        public float Radius { get; }
        public float RadiusSquared {get;}

        public bool WasHit(Ray p_ray, float p_tMin, float p_tMax, ref HitRecord p_record)
        {
            var originCenter = p_ray.Origin - Center;

            var a = Vector3.Dot(p_ray.Direction, p_ray.Direction);
            var b = Vector3.Dot(originCenter, p_ray.Direction);
            var c = Vector3.Dot(originCenter, originCenter) - RadiusSquared;

            var discriminant = b * b - a * c;
            var sqrtDiscriminant = MathF.Sqrt(discriminant);

            if (discriminant > 0)
            {
                var temp = (-b - sqrtDiscriminant) / a;
                if (temp < p_tMax && temp > p_tMin)
                {
                    p_record.T = temp;
                    p_record.P = p_ray.PointAt(p_record.T);
                    p_record.Normal = (p_record.P - Center) / Radius;
                    p_record.Material = Material;
                    return true;
                }

                temp = (-b + sqrtDiscriminant) / a;
                if (temp < p_tMax && temp > p_tMin)
                {
                    p_record.T = temp;
                    p_record.P = p_ray.PointAt(p_record.T);
                    p_record.Material = Material;
                    p_record.Normal = (p_record.P - Center) / Radius;
                    p_record.Material = Material;
                    return true;
                }
            }
            return false;
        }

IMaterial:

public interface IMaterial
    {

        public bool Scatter(Ray p_rayIn, ref HitRecord p_record, out Vector3 p_attenuation, out Ray p_scattered);

        public static Vector3 GetRandomInUnitSphere()
        {
            var rng = new Random();
            var p = Vector3.Zero;
            do
            {
                p = 2.0f * new Vector3((float)rng.NextDouble(), (float)rng.NextDouble(), (float)rng.NextDouble()) - Vector3.One;
            }
            while (p.LengthSquared() >= 1.0f);

            return p;
        }
    }

Camera:

public class Camera
    {
        public Camera()
        {

        }

        [JsonConstructor]
        public Camera(Vector3 p_origin, Vector3 p_target, Vector3 p_upVector, float p_vFov, float p_aspect, float p_aperture, float p_focalDistance)
        {
            LensRadius = p_aperture / 2;
            var theta = p_vFov * MathF.PI / 180;
            var halfHeight = MathF.Tan(theta / 2);
            var halfWidth = p_aspect * halfHeight;
            Origin = p_origin;
            W = Vector3.Normalize(Origin - p_target);
            U = Vector3.Normalize(Vector3.Cross(p_upVector, W));
            V = Vector3.Cross(W, U);
            LowerLeftCorner = Origin - halfWidth * p_focalDistance * U - halfHeight * p_focalDistance * V - p_focalDistance * W;
            Horizontal = 2 * halfWidth * p_focalDistance * U;
            Vertical = 2 * halfHeight * p_focalDistance * V;

            Rng = new Random();
        }

        public static Camera CopyCamera(Camera p_camera)
        {
            var newCamera = new Camera();
            newCamera.LensRadius = p_camera.LensRadius;
            newCamera.Origin = p_camera.Origin;
            newCamera.LowerLeftCorner = p_camera.LowerLeftCorner;
            newCamera.Horizontal = p_camera.Horizontal;
            newCamera.Vertical = p_camera.Vertical;
            newCamera.U = p_camera.U;
            newCamera.V = p_camera.V;
            newCamera.W = p_camera.W;

            newCamera.Rng = new Random();

            return newCamera;
        }

        public Vector3 Origin { get; set; }
        public Vector3 LowerLeftCorner { get; set; }
        public Vector3 Horizontal { get; set; }
        public Vector3 Vertical { get; set; }
        public Vector3 U { get; set; }
        public Vector3 V { get; set; }
        public Vector3 W { get; set; }
        public float LensRadius { get; set; }

        [JsonIgnore]
        public Random Rng { get; set; }

        public Ray GetRay(float p_s, float p_t)
        {
            var rd = LensRadius * GetRandomInUnitDisk();
            var offset = U * rd.X + V * rd.Y;
            return new Ray(Origin + offset, LowerLeftCorner + p_s * Horizontal + p_t * Vertical - Origin - offset);
            //return new Ray(Origin, LowerLeftCorner + p_s * Horizontal + p_t * Vertical - Origin);
        }

        private Vector3 GetRandomInUnitDisk()
        {
            var p = Vector3.Zero;
            do
            {
                p = 2.0f * new Vector3((float)Rng.NextDouble(), (float)Rng.NextDouble(), 0) - new Vector3(1.0f, 1.0f, 0.0f);
            }
            while (Vector3.Dot(p, p) >= 1.0f);

            return p;
        }
    }

Initialization of the scene:

var parameters = new RenderParemeters(1280, 640, 64);

            var lookFrom = new Vector3(3.0f, 3.0f, 2.0f);
            var lookAt = new Vector3(0.0f, 0.0f, -1.0f);
            var distance = (lookFrom - lookAt).Length();

            var scene = new SceneDescription();

            scene.Camera = new Camera(lookFrom,
                                lookAt,
                                new Vector3(0.0f, 1.0f, 0.0f),
                                20.0f,
                                (float)parameters.XResolution / parameters.YResolution,
                                0.0001f,
                                distance);

            scene.SceneEntities.Add(new Sphere(new Vector3(0.0f, 0.0f, -1.0f), 0.5f, new Diffuse(new Vector3(0.8f, 0.3f, 0.3f))));
            scene.SceneEntities.Add(new Sphere(new Vector3(0.0f, -100.5f, -1.0f), 100.0f, new Diffuse(new Vector3(0.8f, 0.8f, 0.0f))));
            scene.SceneEntities.Add(new Sphere(new Vector3(1.0f, 0.0f, -1.0f), 0.5f, new Glossy(new Vector3(0.8f, 0.6f, 0.2f), 0.3f)));
            scene.SceneEntities.Add(new Sphere(new Vector3(-1.0f, 0.0f, -1.0f), 0.5f, new Dielectric(new Vector3(0.95f, 0.95f, 0.95f), 1.33333f, 0.0001f)));
            scene.SceneEntities.Add(new Sphere(new Vector3(-1.0f, 0.0f, -1.0f), -0.495f, new Dielectric(new Vector3(0.95f, 0.95f, 0.95f), 1.33333f, 0.0f)));
9
  • File.WriteAllLines(p_outputPath, new[] { serializedScene }); - File.WriteAllText is available. learn.microsoft.com/en-us/dotnet/api/… Commented Oct 30, 2020 at 20:50
  • Indeed, doesn't help the issue though. Commented Oct 30, 2020 at 20:53
  • Does TypeNameHandling.All make any difference? I don't recall having any issues with this in the past. Commented Oct 30, 2020 at 20:55
  • Auto and All both cause the same issue Commented Oct 30, 2020 at 20:56
  • Figures. You can add an error handler, see if something pops out there. newtonsoft.com/json/help/html/SerializationErrorHandling.htm Commented Oct 30, 2020 at 20:59

1 Answer 1

2

Properties of your Sphere class are readonly, you should do them like below ({get;set;}):

    public IMaterial Material { get;set; }
    public Vector3 Center { get; set; }
    public float Radius { get; set; }
    public float RadiusSquared {get; set;}

Alternatively you can make setter private but mark property with [JsonProperty] attribute:

   [JsonProperty] 
public float Radius {get; private set;}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.