Пример #1
0
 static XElement MapTextureOrColor(TextureRgb texture, string name)
 {
     if (texture.IsConstant)
     {
         var clr = texture.Lookup(Vector2.Zero);
         return(new XElement("rgb", MakeNameValue(name, $"{clr.R}, {clr.G}, {clr.B}")));
     }
     else
     {
         texCounter++;
         string filename = $"Textures/texture-{texCounter:0000}.exr";
         texture.Image.WriteToFile(filename);
         return(new("texture", new XAttribute("type", "bitmap"), new XAttribute("name", name),
                    new XElement("string", MakeNameValue("filename", filename))
                    ));
     }
 }
Пример #2
0
        /// <summary>
        /// Converts a parsed .obj file into one or more triangle meshes and adds it to the scene.
        /// We are using our own code and not Assimp.NET, as the latter does not correctly handle meshes
        /// with multiple materials assigned to different faces.
        /// </summary>
        /// <param name="mesh">The parsed .obj mesh</param>
        /// <param name="scene">The scene to which the mesh should be added</param>
        /// <param name="materialOverride">
        ///     Materials from the .obj with a name matching one of the keys in this dictionary will be
        ///     replaced by the corresponding dictionary entry
        /// </param>
        /// <param name="emissionOverride">
        ///     If a material name is a key in this dictionary, all meshes with that material will be
        ///     converted to diffuse emitters. The value from the dictionary determines their emitted radiance.
        /// </param>
        public static void AddToScene(ObjMesh mesh, Scene scene, Dictionary <string, Material> materialOverride,
                                      Dictionary <string, RgbColor> emissionOverride = null)
        {
            // Create a dummy constant texture color for incorrect texture references
            var dummyColor    = new TextureRgb(RgbColor.White);
            var dummyMaterial = new GenericMaterial(new GenericMaterial.Parameters {
                BaseColor = dummyColor
            });

            // Create the materials for this OBJ file
            var errors    = new List <string>();
            var materials = new Dictionary <string, Material>();
            var emitters  = new Dictionary <string, RgbColor>();

            for (int i = 1, n = mesh.Contents.Materials.Count; i < n; i++)
            {
                // Try to find the correct material
                string           materialName = mesh.Contents.Materials[i];
                ObjMesh.Material objMaterial;
                if (!mesh.Contents.MaterialLib.TryGetValue(materialName, out objMaterial))
                {
                    errors.Add($"Cannot find material '{materialName}'. Replacing by dummy.");
                    materials[materialName] = dummyMaterial;
                    continue;
                }

                // Roughly match the different illumination modes to the right parameters of our material.
                GenericMaterial.Parameters materialParameters;
                switch (objMaterial.illuminationModel)
                {
                case 5: // perfect mirror
                    materialParameters = new GenericMaterial.Parameters {
                        BaseColor            = new TextureRgb(objMaterial.specular),
                        SpecularTintStrength = 1.0f,
                        Metallic             = 1,
                        Roughness            = new TextureMono(0),
                    };
                    break;

                case 7: // perfect glass
                    materialParameters = new GenericMaterial.Parameters {
                        BaseColor             = new TextureRgb(objMaterial.specular),
                        Metallic              = 0,
                        Roughness             = new TextureMono(0),
                        IndexOfRefraction     = objMaterial.indexOfRefraction,
                        SpecularTransmittance = 1.0f,
                        SpecularTintStrength  = 1.0f
                    };
                    break;

                case 2:
                default: // We pretend that anything else would be "2", aka, a phong shader
                    TextureRgb baseColor;
                    baseColor = string.IsNullOrEmpty(objMaterial.diffuseTexture)
                        ? new TextureRgb(objMaterial.diffuse)
                        : new TextureRgb(System.IO.Path.Join(mesh.BasePath, objMaterial.diffuseTexture));

                    // We coarsely map the "ns" term to roughness, use the diffuse color as base color,
                    // and ignore everything else.
                    materialParameters = new GenericMaterial.Parameters {
                        BaseColor = baseColor,
                        Roughness = new TextureMono(
                            objMaterial.specularIndex == 0
                            ? 1
                            : 1 / objMaterial.specularIndex),
                        Metallic = 0.5f
                    };
                    break;
                }
                materials[materialName] = new GenericMaterial(materialParameters);

                // Check if the material is emissive
                if (objMaterial.emission != RgbColor.Black)
                {
                    emitters[materialName] = objMaterial.emission;
                }
            }

            // Convert the faces to triangles & build the new list of indices
            foreach (var obj in mesh.Contents.Objects)
            {
                // Mapping from material index to triangle definition, per group
                var triangleGroups = new List <Dictionary <int, List <TriIdx> > >();

                // Triangulate faces and group triangles by material
                bool has_normals   = false;
                bool has_texcoords = false;
                bool empty         = true;
                foreach (var group in obj.Groups)
                {
                    // Create the mapping from material index to triangle definition for this group.
                    triangleGroups.Add(new Dictionary <int, List <TriIdx> >());

                    foreach (var face in group.Faces)
                    {
                        int mtl_idx = face.Material;
                        triangleGroups[^ 1].TryAdd(mtl_idx, new List <TriIdx>());