Search code examples
c#godotgodot4

Unity to Godot: MeshFilter


I'm working on porting a unity project that I made a while ago over to Godot.

In Unity I have a class that looks like this:

public class MeshGenerator 
{

    public SquareGrid squareGrid;
    public MeshFilter walls;

    void CreateWallMesh(int[,] map, float squareSize, int tileAmount){
        MeshCollider currentColliders = walls.gameObject.GetComponent<MeshCollider>();
        Destroy(currentColliders);
        CalculateMeshOutlines();

        List<Vector3> wallVertices = new List<Vector3>();
        List<int> wallTriangles = new List<int>();
        Mesh wallMesh = new Mesh();
        float wallHeight = 5;

        foreach(List<int> outline in outlines){
            for(int i = 0; i < outline.Count-1; i++){
                int startIndex = wallVertices.Count;
                wallVertices.Add(vertices[outline[i]]); // left vertex
                wallVertices.Add(vertices[outline[i+1]]); // right vertex
                wallVertices.Add(vertices[outline[i]] - Vector3.up * wallHeight); // bottom left vertex
                wallVertices.Add(vertices[outline[i+1]] - Vector3.up * wallHeight); // bottom right vertex

                wallTriangles.Add(startIndex + 0);
                wallTriangles.Add(startIndex + 2);
                wallTriangles.Add(startIndex + 3);

                wallTriangles.Add(startIndex + 3);
                wallTriangles.Add(startIndex + 1);
                wallTriangles.Add(startIndex + 0);
            }
        }
        wallMesh.vertices = wallVertices.ToArray();
        wallMesh.triangles = wallTriangles.ToArray();

        MeshCollider wallCollider = walls.gameObject.AddComponent<MeshCollider>();
        wallCollider.sharedMesh = wallMesh;

        float textureScale = walls.gameObject.GetComponentInChildren<MeshRenderer> ().material.mainTextureScale.x;
        float increment = (textureScale / map.GetLength(0));
        Vector2[] uvs = new Vector2[wallMesh.vertices.Length];
        float[] uvEntries = new float[]{0.5f,increment}; 

        for (int i = 0; i < wallMesh.vertices.Length; i++) 
        {
            float percentY = Mathf.InverseLerp ((-wallHeight) * squareSize, 0, wallMesh.vertices [i].y) * tileAmount * (wallHeight / map.GetLength(0));
            uvs [i] = new Vector2(uvEntries[i % 2],percentY);
        }

        wallMesh.uv = uvs;
        wallCollider.sharedMesh = wallMesh;
        walls.mesh = wallMesh;
    }

And I'm getting an error that says

The type or namespace name 'MeshFilter' could not be found (are you missing a using directive or an assembly reference?)

I believe it's referencing this unity mesh, and I'm curious what the correct way to do it in Godot is.

enter image description here

Edit:
In case it helps, what the class does is takes a random 2D map and builds up walls around the area the player is supposed to travel through. Here's a sample:

enter image description here


Solution

  • For creating a Mesh in runtime in Godot see ImmediateMesh, MeshDataTool or SurfaceTool. With any of those you can get a Mesh that you can display using a MeshInstance3D or for other uses.

    Although ImmediateMesh name and interface evoke the old OpenGL immediate mode, it is only an usability façade.


    The code suggest you also want a collider. That means you want a Shape3D that you can use with a CollisionShape3D child of an Area3D, StaicBody3D, CharacterBody3D, RigidBody3D... Note: they can have multiple CollisionShape3D or CollisionPolygon3D children, so you do not need to make a single collider.

    The Shape3D can be one of the many primitive shapes (e.g. BoxShape3D), which are the most performant.

    Alternatively you can pick between ConcavePolygonShape3D and ConvexPolygonShape3D. You can create them from a Mesh using create_trimesh_shape and create_convex_shape respectively.

    ConcavePolygonShape3D is THE WORSE. You have been warned.


    See also create_convex_collision, create_multiple_convex_collisions and create_trimesh_collision from MeshInstance3D. In particular create_multiple_convex_collisions will do decomposition for you.

    Be aware that these method will create StaticBody3D children of the MeshInstance3D. If you do not want StaticBody3D, you can always take the colliders, remove them from their parent, and add them where you need them.


    Addendum

    After looking at the picture, I believe using CSG nodes this would be easy for you.

    CSG stands for Constructive Solid Geometry, it is making boolean operations with 3D shapes.

    So you can have a CSGCombiner3D with a child CSGBox3D for the exterior volume. And then to substract a CSGPolygon3D from it, you add it as second child and set its operation to OPERATION_SUBTRACTION.

    To define the CSGPolygon3D all you need is to figure out the polygon in 2D since it extends it to 3D using a depth you can configure.

    Once you have it setup, you can use get_meshes which gives you an array with a Transform3D and a Mesh (which you can use in a MeshInstance3D, from which you can also generate a physics body as explained above).

    Or, alternatively, you can use the CSG nodes directly. Since you can set use_collision to true to enable physics.