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 } }