hypar-io / Elements

The smallest useful BIM.
https://www.hypar.io
MIT License
349 stars 74 forks source link

Error Material #1088

Open HoNgocQuocSang2721 opened 4 weeks ago

HoNgocQuocSang2721 commented 4 weeks ago

Describe the bug When I try create Mesh & Box (have same material) , Material in View is not same.

To Reproduce Use package [Elements] => Create Mesh & Box (have same material)

Expected behavior When I try create Mesh & Box (have same material) , Material in View is not same. I need show material of Mesh same material of Box

Screenshots var material = new Elements.Geometry.Color(System.Drawing.Color.FromArgb(128, 128, 0)),0, 0, null, false, true, true, null, true, null,0, false);

Desktop (please complete the following information):

Additional context None


Please reply


My Code


    public static Elements.Material MaterialDefault = new Elements.Material("Default",
    new Elements.Geometry.Color(System.Drawing.Color.FromArgb(128, 128, 0)), 0, 0, null, false, true, true, null, true, null, 0, false);

static void Main(string[] args)
{
    Console.Title = "Convert IFC/IfcZip to glTF...";
    var continues = true;
    do
    {
        Console.WriteLine("-----------------------------------");
        Console.WriteLine("Drop file IFC/IfcZip and Enter convert...");
        var path2 = Console.ReadLine();
        if (path2.Length > 0)
        {
            var pathaa = path2.Replace("\"", "");
            if (File.Exists(pathaa))
            {
                var stopwatch = new Stopwatch();

                stopwatch.Start();
                Console.WriteLine("Start converting...");
                FileInfo ifc = new FileInfo(pathaa);

                var x = 0.0;
                var y = 0.0;
                var z = 0.0;
                var specularFactor = 0.0;
                var glossinessFactor = 0.0;

                var textData = new List<(Vector3, Vector3, Vector3, string, Color?)>();

                var sphere = Mesh.Sphere(0.5, 20);

                #region Box
                // Tạo một danh sách các điểm để tạo các đỉnh của hộp
                var points = new List<Vector3>
 {
     new Vector3(0, 0, 0),    // Điểm 0
     new Vector3(1, 0, 0),    // Điểm 1
     new Vector3(1, 1, 0),   // Điểm 2
     new Vector3(0, 1, 0),   // Điểm 3
     new Vector3(0, 0, 1),    // Điểm 4
     new Vector3(1, 0, 1),    // Điểm 5
     new Vector3(1, 1, 1),   // Điểm 6
     new Vector3(0, 1, 1)    // Điểm 7
 };

                // Tạo lưới tam giác
                var mesh = new Mesh();

                // Thêm các đỉnh vào lưới và lưu lại để sử dụng sau
                var vertices = new List<Elements.Geometry.Vertex>();
                foreach (var point in points)
                {
                    var vertex = new Elements.Geometry.Vertex(point);
                    mesh.AddVertex(vertex);
                    mesh.AddVertex(vertex);
                    vertices.Add(vertex);
                }

                // Thêm các tam giác vào lưới
                mesh.AddTriangle(vertices[0], vertices[1], vertices[5]); // Mặt trước
                mesh.AddTriangle(vertices[0], vertices[5], vertices[4]);

                mesh.AddTriangle(vertices[1], vertices[2], vertices[6]); // Mặt phải
                mesh.AddTriangle(vertices[1], vertices[6], vertices[5]);

                mesh.AddTriangle(vertices[2], vertices[3], vertices[7]); // Mặt sau
                mesh.AddTriangle(vertices[2], vertices[7], vertices[6]);

                mesh.AddTriangle(vertices[3], vertices[0], vertices[4]); // Mặt trái
                mesh.AddTriangle(vertices[3], vertices[4], vertices[7]);

                mesh.AddTriangle(vertices[4], vertices[5], vertices[6]); // Mặt trên
                mesh.AddTriangle(vertices[4], vertices[6], vertices[7]);

                mesh.AddTriangle(vertices[0], vertices[3], vertices[2]); // Mặt dưới
                mesh.AddTriangle(vertices[0], vertices[2], vertices[1]);

                mesh.ComputeNormals();

                #endregion

                #region box extrude
                // Tạo một hình hộp kích thước 1x1x1
                var profile = Polygon.Rectangle(0.5, 0.5);
                var extrude = new Extrude(profile, 0.5, Vector3.ZAxis, false);
                #endregion

                #region lamina
                var lu1 = new Lamina(new Polygon(new List<Vector3>() { vertices[0].Position, vertices[1].Position, vertices[5].Position }));
                var lu2 = new Lamina(new Polygon(new List<Vector3>() { vertices[0].Position, vertices[5].Position, vertices[4].Position }));

                var lu3 = new Lamina(new Polygon(new List<Vector3>() { vertices[1].Position, vertices[2].Position, vertices[6].Position }));
                var lu4 = new Lamina(new Polygon(new List<Vector3>() { vertices[1].Position, vertices[6].Position, vertices[5].Position }));

                var lu5 = new Lamina(new Polygon(new List<Vector3>() { vertices[2].Position, vertices[3].Position, vertices[7].Position }));
                var lu6 = new Lamina(new Polygon(new List<Vector3>() { vertices[2].Position, vertices[7].Position, vertices[6].Position }));

                var lu7 = new Lamina(new Polygon(new List<Vector3>() { vertices[3].Position, vertices[0].Position, vertices[4].Position }));
                var lu8 = new Lamina(new Polygon(new List<Vector3>() { vertices[3].Position, vertices[4].Position, vertices[7].Position }));

                var lu9 = new Lamina(new Polygon(new List<Vector3>() { vertices[4].Position, vertices[5].Position, vertices[6].Position }));
                var lu10 = new Lamina(new Polygon(new List<Vector3>() { vertices[4].Position, vertices[6].Position, vertices[7].Position }));

                var lu11 = new Lamina(new Polygon(new List<Vector3>() { vertices[0].Position, vertices[3].Position, vertices[2].Position }));
                var lu12 = new Lamina(new Polygon(new List<Vector3>() { vertices[0].Position, vertices[2].Position, vertices[1].Position }));

                var representation = new Representation(new List<SolidOperation>() { lu1, lu2, lu3, lu4, lu5, lu6, lu7, lu8, lu9, lu10, lu11, lu12 });

                #endregion

                var model = new Model();

                var index1 = 0;
                for (var r = 0.0; r <= 1.0; r += 0.2)
                {
                    if (index1 == 0) { }
                    for (var g = 0.0; g <= 1.0; g += 0.2)
                    {
                        if (r == 0)
                        {
                            textData.Add((new Vector3(-1.5, y), Vector3.ZAxis, Vector3.XAxis, $"roughness: {1 - glossinessFactor:f2}", Colors.Black));
                        }
                        if (g == 0)
                        {
                            textData.Add((new Vector3(x, -1), Vector3.ZAxis, Vector3.XAxis, $"specular: {specularFactor:f2}", Colors.Black));
                        }
                        for (var b = 0.0; b <= 1.0; b += 0.2)
                        {
                            var color = new Color(r, g, b, 1 - b);
                            if (r == 1.0 && g == 0.0)
                            {
                                textData.Add((new Vector3(x + 1.5, y, z), Vector3.YAxis.Negate(), Vector3.XAxis, $"alpha: {color.Alpha:f2}", Colors.Black));
                            }

                            index1++;
                            var material = new Material($"{r}_{g}_{b}", color, specularFactor, glossinessFactor, null, false, false, false, null, true, null, 0, false);
                            var box = new GeometricElement(new Transform(new Vector3(x, y, z)), material, representation, false);
                            //model.AddElement(box);
                            //model.AddElement(new GeometricElement(new Transform(new Vector3(x, y, z)), material, new Representation(new List<SolidOperation>() { extrude}  ), false));
                            //model.AddElement(new MeshElement(sphere, new Transform(new Vector3(x, y, z)), material));
                            model.AddElement(new MeshElement(mesh, new Transform(new Vector3(x, y, z)), material));
                            z += 2.0;
                        }
                        z = 0;
                        y += 2.0;
                        glossinessFactor += 0.2;
                    }
                    glossinessFactor = 0.0;
                    y = 0;
                    x += 2.0;
                    specularFactor += 0.2;
                }

                // Lưu mô hình dưới dạng GLTF
                var gltfPath = Path.ChangeExtension(ifc.FullName, ".glb");
                model.UpdateRepresentations();
                model.UpdateBoundsAndComputedSolids();

                model.ToGlTF(gltfPath, true, false);

                stopwatch.Stop();
                Console.WriteLine("Converting finished.");
                Console.WriteLine("Elapsed: " + stopwatch.Elapsed);
            }
        }

    }
    while (continues);
}
andrewheumann commented 4 weeks ago

Các vật liệu là giống nhau, nhưng hình học giữa các ví dụ của bạn có sự khác biệt tinh tế.

Khi bạn sử dụng Extrude, bạn nhận được kết quả hợp lý cho các hộp của mình:

image

Khi bạn sử dụng Lamina, bạn đang tạo ra một hình dạng với hình học không hợp lệ. Representation cố gắng thực hiện một phép hợp boolean của tất cả các SolidOperation mà bạn cung cấp, và Lamina là rất mỏng, vì vậy chúng không hoạt động tốt trong boolean. Điều này dẫn đến kết quả hiển thị kỳ lạ mà bạn thấy:

image

Bạn có thể làm cho Representation ngừng cố gắng thực hiện hợp boolean bằng cách sử dụng cờ SkipCSGUnion:

new Representation(solidOperations)
{
    SkipCSGUnion = true
}

Điều này giúp cải thiện tình trạng trong ví dụ của bạn, nhưng vẫn có sự khác biệt với các hộp trong suốt:

image

Tôi nghĩ điều này là do Lamina có hai mặt, vì vậy bạn đang nhận được nhiều mặt bên trong hộp hơn.

Để tạo ra một SolidOperation tùy chỉnh, như bạn đang cố gắng làm ở đây, tôi khuyên bạn nên sử dụng kiểu ConstructedSolid:

var solid = new Solid();
solid.AddFace(new Polygon(vertices[4].Position, vertices[5].Position, vertices[6].Position, vertices[7].Position));
solid.AddFace(new Polygon(vertices[0].Position, vertices[1].Position, vertices[5].Position, vertices[4].Position));
solid.AddFace(new Polygon(vertices[1].Position, vertices[2].Position, vertices[6].Position, vertices[5].Position));
solid.AddFace(new Polygon(vertices[2].Position, vertices[3].Position, vertices[7].Position, vertices[6].Position));
solid.AddFace(new Polygon(vertices[3].Position, vertices[0].Position, vertices[4].Position, vertices[7].Position));
solid.AddFace(new Polygon(vertices[0].Position, vertices[3].Position, vertices[2].Position, vertices[1].Position));
var customRepresentation = new Representation(new ConstructedSolid(solid));

Điều này tạo ra kết quả giống hệt với Extrude:

Screenshot 2024-08-15 at 8 13 29 AM

Cuối cùng, lý do Mesh của bạn trông như thế này:

image

Là do các vector pháp tuyến của chúng không đúng. Bạn đã xây dựng một lưới được gọi là “welded” mesh, được dùng để biểu diễn các bề mặt mịn liên tục, trong đó các vector pháp tuyến của điểm là trung bình của các vector pháp tuyến của mặt, như thế này: image

Để khắc phục điều này, hãy tạo ra các đỉnh riêng biệt cho từng mặt, như sau:

// Tạo lưới tam giác
var mesh = new Mesh();

var boxTriangles = new List<int>{
    0, 1, 5, // Mặt trước
    0, 5, 4,
    1, 2, 6, // Mặt phải
    1, 6, 5,
    2, 3, 7, // Mặt sau
    2, 7, 6,
    3, 0, 4, // Mặt trái
    3, 4, 7,
    4, 5, 6, // Mặt trên
    4, 6, 7,
    0, 3, 2, // Mặt dưới
    0, 2, 1
};

for (var i = 0; i < boxTriangles.Count; i += 3)
{
    var a = mesh.AddVertex(points[boxTriangles[i]]);
    var b = mesh.AddVertex(points[boxTriangles[i + 1]]);
    var c = mesh.AddVertex(points[boxTriangles[i + 2]]);
    mesh.AddTriangle(a, b, c);
}
mesh.ComputeNormals();

Điều này sẽ tạo ra các lưới trông giống hệt với hai ví dụ khác ở trên.

Screenshot 2024-08-15 at 8 30 47 AM

(English version:)

The materials are identical, but the geometry across your various examples is subtly different.

When you use Extrudes, you get sensible results for your boxes:

image

When you use Laminas, you are constructing a representation with invalid geometry. The Representation attempts to perform a boolean union of all the SolidOperations you provide, and Laminas are infinitely thin, so they do not work well in the boolean. This results in the strange appearance you see:

image

You can cause the representation to stop trying to perform a boolean union by passing the SkipCSGUnion flag:

new Representation(solidOperations)
{
    SkipCSGUnion = true
}

And this helps a bit in your example, but it still looks different for the transparent boxes:

image

I think this is because Laminas are two-sided, so you're getting a bunch of extra faces on the inside of the box.

To construct a custom SolidOperation, as you are trying to do here, I would recommend using the ConstructedSolid type:

var solid = new Solid();
solid.AddFace(new Polygon(vertices[4].Position, vertices[5].Position, vertices[6].Position, vertices[7].Position));
solid.AddFace(new Polygon(vertices[0].Position, vertices[1].Position, vertices[5].Position, vertices[4].Position));
solid.AddFace(new Polygon(vertices[1].Position, vertices[2].Position, vertices[6].Position, vertices[5].Position));
solid.AddFace(new Polygon(vertices[2].Position, vertices[3].Position, vertices[7].Position, vertices[6].Position));
solid.AddFace(new Polygon(vertices[3].Position, vertices[0].Position, vertices[4].Position, vertices[7].Position));
solid.AddFace(new Polygon(vertices[0].Position, vertices[3].Position, vertices[2].Position, vertices[1].Position));
var customRepresentation = new Representation(new ConstructedSolid(solid));

This produces identical results to the Extrude:

Screenshot 2024-08-15 at 8 13 29 AM

Finally, the reason your Meshes look like this:

image

Is because their normals are incorrect. You have built what is referred to as a "welded" mesh, meant for representing continuous smooth surfaces, where the vertex normals are the average of the face normals like this: image

To correct this, add separate vertices for each face, like so:

// Tạo lưới tam giác
var mesh = new Mesh();

var boxTriangles = new List<int>{
    0, 1, 5, // Mặt trước
    0, 5, 4,
    1, 2, 6, // Mặt phải
    1, 6, 5,
    2, 3, 7, // Mặt sau
    2, 7, 6,
    3, 0, 4, // Mặt trái
    3, 4, 7,
    4, 5, 6, // Mặt trên
    4, 6, 7,
    0, 3, 2, // Mặt dưới
    0, 2, 1
};

for (var i = 0; i < boxTriangles.Count; i += 3)
{
    var a = mesh.AddVertex(points[boxTriangles[i]]);
    var b = mesh.AddVertex(points[boxTriangles[i + 1]]);
    var c = mesh.AddVertex(points[boxTriangles[i + 2]]);
    mesh.AddTriangle(a, b, c);
}
mesh.ComputeNormals();

This will result in meshes that look identical to the other two examples above.

Screenshot 2024-08-15 at 8 30 47 AM
HoNgocQuocSang2721 commented 4 weeks ago

If i use old method => File small size file .glb, but i use new method => File x3 size file .glb. File .IFC has large size file => File .glb very large size file. Because new method has each triangle include 3 vertices. => File has very large triangle => very large size file .glb. Is there a way to reduce the file size while still ensuring the geometry material?