using GLTF.Extensions;
using GLTF.Math;
using Newtonsoft.Json;
namespace GLTF.Schema
{
///
/// The material appearance of a primitive.
///
public class GLTFMaterial : GLTFChildOfRootProperty
{
///
/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
///
public PbrMetallicRoughness PbrMetallicRoughness;
///
/// A set of parameter values used to light flat-shaded materials
///
public MaterialCommonConstant CommonConstant;
///
/// A tangent space normal map. Each texel represents the XYZ components of a
/// normal vector in tangent space.
///
public NormalTextureInfo NormalTexture;
///
/// The occlusion map is a greyscale texture, with white indicating areas that
/// should receive full indirect lighting and black indicating no indirect
/// lighting.
///
public OcclusionTextureInfo OcclusionTexture;
///
/// The emissive map controls the color and intensity of the light being emitted
/// by the material. This texture contains RGB components in sRGB color space.
/// If a fourth component (A) is present, it is ignored.
///
public TextureInfo EmissiveTexture;
///
/// The RGB components of the emissive color of the material.
/// If an emissiveTexture is specified, this value is multiplied with the texel
/// values.
///
/// 0.0
/// 1.0
///
/// 3
/// 3
///
public Color EmissiveFactor = Color.Clear;
///
/// The material's alpha rendering mode enumeration specifying the interpretation of the
/// alpha value of the main factor and texture. In `OPAQUE` mode, the alpha value is
/// ignored and the rendered output is fully opaque. In `MASK` mode, the rendered output
/// is either fully opaque or fully transparent depending on the alpha value and the
/// specified alpha cutoff value. In `BLEND` mode, the alpha value is used to composite
/// the source and destination areas. The rendered output is combined with the background
/// using the normal painting operation (i.e. the Porter and Duff over operator).
///
public AlphaMode AlphaMode = AlphaMode.OPAQUE;
///
/// Specifies the cutoff threshold when in `MASK` mode. If the alpha value is greater than
/// or equal to this value then it is rendered as fully opaque, otherwise, it is rendered
/// as fully transparent. This value is ignored for other modes.
///
public double AlphaCutoff = 0.5;
///
/// Specifies whether the material is double sided. When this value is false, back-face
/// culling is enabled. When this value is true, back-face culling is disabled and double
/// sided lighting is enabled. The back-face must have its normals reversed before the
/// lighting equation is evaluated.
///
public bool DoubleSided;
public GLTFMaterial()
{
}
public GLTFMaterial(GLTFMaterial material, GLTFRoot gltfRoot) : base(material, gltfRoot)
{
if (material == null) return;
if (material.PbrMetallicRoughness != null)
{
PbrMetallicRoughness = new PbrMetallicRoughness(material.PbrMetallicRoughness, gltfRoot);
}
if (material.CommonConstant != null)
{
CommonConstant = new MaterialCommonConstant(material.CommonConstant, gltfRoot);
}
if (material.NormalTexture != null)
{
NormalTexture = new NormalTextureInfo(material.NormalTexture, gltfRoot);
}
if (material.OcclusionTexture != null)
{
OcclusionTexture = new OcclusionTextureInfo(material.OcclusionTexture, gltfRoot);
}
if (material.EmissiveTexture != null)
{
EmissiveTexture = new TextureInfo(material.EmissiveTexture, gltfRoot);
}
EmissiveFactor = material.EmissiveFactor;
AlphaMode = material.AlphaMode;
AlphaCutoff = material.AlphaCutoff;
DoubleSided = material.DoubleSided;
}
public static GLTFMaterial Deserialize(GLTFRoot root, JsonReader reader)
{
var material = new GLTFMaterial();
while (reader.Read() && reader.TokenType == JsonToken.PropertyName)
{
var curProp = reader.Value.ToString();
switch (curProp)
{
case "pbrMetallicRoughness":
material.PbrMetallicRoughness = PbrMetallicRoughness.Deserialize(root, reader);
break;
case "commonConstant":
material.CommonConstant = MaterialCommonConstant.Deserialize(root, reader);
break;
case "normalTexture":
material.NormalTexture = NormalTextureInfo.Deserialize(root, reader);
break;
case "occlusionTexture":
material.OcclusionTexture = OcclusionTextureInfo.Deserialize(root, reader);
break;
case "emissiveTexture":
material.EmissiveTexture = TextureInfo.Deserialize(root, reader);
break;
case "emissiveFactor":
var emissiveColor = reader.ReadAsRGBColor();
emissiveColor.A = 0;
material.EmissiveFactor = emissiveColor;
break;
case "alphaMode":
material.AlphaMode = reader.ReadStringEnum();
break;
case "alphaCutoff":
material.AlphaCutoff = reader.ReadAsDouble().Value;
break;
case "doubleSided":
material.DoubleSided = reader.ReadAsBoolean().Value;
break;
default:
material.DefaultPropertyDeserializer(root, reader);
break;
}
}
return material;
}
public override void Serialize(JsonWriter writer)
{
writer.WriteStartObject();
if (PbrMetallicRoughness != null)
{
writer.WritePropertyName("pbrMetallicRoughness");
PbrMetallicRoughness.Serialize(writer);
}
if (CommonConstant != null)
{
writer.WritePropertyName("commonConstant");
CommonConstant.Serialize(writer);
}
if (NormalTexture != null)
{
writer.WritePropertyName("normalTexture");
NormalTexture.Serialize(writer);
}
if (OcclusionTexture != null)
{
writer.WritePropertyName("occlusionTexture");
OcclusionTexture.Serialize(writer);
}
if (EmissiveTexture != null)
{
writer.WritePropertyName("emissiveTexture");
EmissiveTexture.Serialize(writer);
}
if (EmissiveFactor != Color.Clear && !(EmissiveFactor.R == 0 && EmissiveFactor.G == 0 && EmissiveFactor.B == 0))
{
writer.WritePropertyName("emissiveFactor");
writer.WriteStartArray();
writer.WriteValue(EmissiveFactor.R);
writer.WriteValue(EmissiveFactor.G);
writer.WriteValue(EmissiveFactor.B);
writer.WriteEndArray();
}
if (AlphaMode != AlphaMode.OPAQUE)
{
writer.WritePropertyName("alphaMode");
writer.WriteValue(AlphaMode.ToString());
}
if (AlphaCutoff != 0.5)
{
writer.WritePropertyName("alphaCutoff");
var sanitizedCutoff = AlphaCutoff < 0.0 ? 0.0 : AlphaCutoff > 1.0 ? 1.0 : AlphaCutoff;
writer.WriteValue(sanitizedCutoff);
}
if (DoubleSided)
{
writer.WritePropertyName("doubleSided");
writer.WriteValue(true);
}
base.Serialize(writer);
writer.WriteEndObject();
}
}
public enum AlphaMode
{
OPAQUE,
MASK,
BLEND
}
}