static Scene MakeScene(GenericMaterial.Parameters parameters) { Scene scene = new(); // Create a quad scene.Meshes.Add(new Mesh(new Vector3[] { new(-10, -10, -2), new(10, -10, -2), new(10, 10, -2), new(-10, 10, -2), }, new int[] {
/// <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>());