#c# #json #.net #json.net
#c# #json #.net #json.net
Вопрос:
У меня есть следующее описание сцены JSON:
{
"$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
}
]
}
}
который был сериализован из объекта, подобного этому:
public class SceneDescription
{
public SceneDescription()
{
SceneEntities = new List<IIntersectionTarget>();
}
public Camera Camera { get; set; }
public List<IIntersectionTarget> SceneEntities { get; set; }
}
Камера сериализует и десериализует просто отлично, но когда объекты сцены десериализуются, все они в конечном итоге имеют нулевые / все 0’d данные для каждого поля. Ошибки не выдаются. Что я делаю не так?
Метод сериализации:
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 });
}
Метод десериализации:
public static SceneDescription LoadScene(string p_filePath)
{
var scene = File.ReadAllText(p_filePath);
return JsonConvert.DeserializeObject<SceneDescription>(scene, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All
});
}
РЕДАКТИРОВАТЬ: добавление дополнительных определений
IIntersectionTarget:
public interface IIntersectionTarget
{
public IMaterial Material { get; }
public bool WasHit(Ray p_ray, float p_tMin, float p_tMax, ref HitRecord p_record);
}
Сфера:
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 amp;amp; 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 amp;amp; 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;
}
}
Камера:
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;
}
}
Инициализация сцены:
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)));
Комментарии:
1.
File.WriteAllLines(p_outputPath, new[] { serializedScene });
—File.WriteAllText
доступно. learn.microsoft.com/en-us/dotnet/api /…2. На самом деле, это не помогает решить проблему.
3. Имеет ли
TypeNameHandling.All
какое-либо значение? Я не помню, чтобы у меня были какие-либо проблемы с этим в прошлом.4. Авто и все оба вызывают одну и ту же проблему
5. Рисунки. Вы можете добавить обработчик ошибок, посмотреть, не выскочит ли там что-нибудь. newtonsoft.com/json/help/html/SerializationErrorHandling.htm
Ответ №1:
Свойства вашего класса Sphere доступны только для чтения, вы должны сделать их, как показано ниже ({get;set;}):
public IMaterial Material { get;set; }
public Vector3 Center { get; set; }
public float Radius { get; set; }
public float RadiusSquared {get; set;}
В качестве альтернативы вы можете сделать сеттер закрытым, но пометить свойство атрибутом [JsonProperty]:
[JsonProperty]
public float Radius {get; private set;}