Why aren't the mesh collider and mesh filter meshes saved in prefab children?

I am procedurally generating a large terrain as a group of overlapping power-of-two sized meshes, where the meshes are all attached to individual GameObjects which in turn are all children of a single GameObject. This works fine in my project. I saved the parent GameObject as a prefab. When I load it with:

bathyhead = Instantiate(Resources.Load(“FullGridBoss”)) as GameObject;

the bathyhead GameObject is generated, along with all its children, but, the Mesh Filter and Mesh Collider mesh return as “None (Mesh)” in their respective boxes in the inspector. So, of course, the terrain is not visible, unless I generate it with each play.

Since everything else appears to make it back from the prefab in the inspector, including the Mesh Renderer material, I’m wondering why the collider and filter meshes don’t?

Here is the code that generates the meshes:

		Bathy = new GameObject[x_meshes,z_meshes];
		for (int i=0; i<x_meshes; i++) {
			for (int j=0; j<z_meshes; j++){

				// Generate named gameobjects and make them children of bathyBoss object.
				// It isn't strictly necessary to provide names for the GameObjects
				// generated by the script, but, they show up in the hierarcy at run
				// time so they look cleaner, and being able to find by name helps in 
				// clean up for regenerations and such.

				string goname = System.String.Format("Bathy_{0}{1}",i,j);
				Bathy[i,j] = new GameObject(goname);                     
				Bathy[i,j].transform.parent = bathyBoss.transform;    

				Material bathmat = Resources.Load("Materials/BathyMaterial",typeof(Material)) as Material;
				if(bathmat != null) {
				  MeshRenderer mr = Bathy[i,j].GetComponent<MeshRenderer>();  // already has albedo image, and
				  mr.material = bathmat;                                      // UVs pull out the proper segment
				} else {                                                      // so this works for all meshes
					Debug.Log("couldn't find bathmat");                       // maybe update albedo image in
				}                                                             // script someday so can change
					                                                          // region
				Mesh bathy = new Mesh(); 

				bathy.vertices = GenVertices(i,j);    
				Bathy[i,j].GetComponent<MeshFilter>().sharedMesh = bathy;  

				// make sure the gameobject is at the same location (centered) on each mesh
				Bounds bathybounds = Bathy[i,j].GetComponent<MeshFilter>().sharedMesh.bounds;
				Vector3 gopos = new Vector3(0f,0f,0f);
				Vector3 offset = Bathy[i,j].transform.position - Bathy[i,j].transform.TransformPoint(bathybounds.center);
				Bathy[i,j].transform.position = gopos + offset;

				// position mesh's gameobject for correct overlap

		             10 | 11
                     00 | 01

				float x_off = (float)i*x_cells*x_cell_size; 
				float z_off = (float)j*z_cells*z_cell_size;

				Bathy[i,j].transform.position = new Vector3(x_off,0f,z_off);

				bathy.triangles = GenTriangles ();
				bathy.uv = GenUVs (i,j);
				bathy.RecalculateNormals ();

				// add a mesh collider for flythrough terrain avoidance
				MeshCollider mshcol = Bathy[i,j].AddComponent(typeof(MeshCollider)) as MeshCollider;
				mshcol.sharedMesh = bathy;

	Vector3[] GenVertices(int mx, int mz) { // generate vertices for mesh mx,mz
		//Debug.Log ("gen " + mx + " " + mz); 
		int w = x_cells + 1;                     
		int l = z_cells + 1;
		Vector3[] vertices = new Vector3[w*l];
		for (int x=0; x<w; x++) {
			for (int z=0; z<l; z++) {
				// calculate full grid x,y from current mesh x,y to map to Get_Y() vertice pool
				int gx = x + mx * x_cells;
				int gz = z + mz * z_cells;
				float ve = x_cell_size*VertExag/1000f; // compensate for (square) cell size world units (smaller means less)
				float height = grid.Get_Y(gx,gz,ve);
				vertices[x*l+z] = new Vector3(x*x_cell_size,height,z*z_cell_size); 
		return vertices;

	// linear array of indices that point into the vertex array - same for all multiple meshes
	int[] GenTriangles(){
		int verts_per_tri = 3;
		int tris_per_cell = 2;
		int num_cells = x_cells*z_cells;
		int[] triangles = new int[num_cells*tris_per_cell*verts_per_tri];
		int tindex=0;
		for (int cx=0; cx<x_cells; cx++) {
			for (int cz=0; cz<z_cells; cz++) {
				int n = cx*(z_cells+1)+cz;
				triangles[tindex] = n;
				triangles[tindex+1] = n+1;
				triangles[tindex+2] = n+z_cells+2;
				triangles[tindex] = n;
				triangles[tindex+1] = n+z_cells+2;
				triangles[tindex+2] = n+z_cells+1;
		return triangles;

	// UVs are mapping of each point on the 3D surface to a vertex in the mesh - segmented for each mesh
	Vector2[] GenUVs(int mx,int mz) {   
		int w = x_cells + 1;                     
		int l = z_cells + 1;
		Vector2[] uvs = new Vector2[w*l];

		float minx = (float)mx/x_meshes;            // current segment UV value ranges
		float maxx = ((float)mx + 1.0f)/x_meshes;   // +1 since mesh count, not cell count
		float xdif = maxx-minx;

		float minz = (float)mz/z_meshes;
		float maxz = ((float)mz + 1.0f)/z_meshes;
		float zdif = maxz-minz;

		for (int ux=0; ux<w; ux++) {
			for (int uz=0; uz<l; uz++) {
				uvs[ux*l+uz] = new Vector2(minx + xdif*(float)ux/x_cells,
					                       minz + zdif*(float)uz/z_cells);

		return uvs;

Meshes are asset types, inheriting UnityEngine.Object. The are different from traditional GameObjects. You can think of them like ScriptableObjects if you want. You will need to save out the mesh asset.

From [Editor scripting] How to save a script generated mesh as an asset/FBX? - Questions & Answers - Unity Discussions

AssetDatabase.CreateAsset( [mesh object here], [path to asset] );

That looks like it might be a bit complicated to keep everything properly associated for a whole bunch of position registered gameobjects contained in the prefab…sometimes Unity is like that…;^) But, there is some mention of writing the meshes into the prefab, too, so that may do. I’ll give it a try. Thanks!