First of all can I say I've never encountered by total chance someone encountering such an incredibly specific issue that I also encountered, so good job on that, universe.
So as you've already discovered, Unity's model importers discard all edges and points.
I haven't completely solved this problem myself for a similar project, but I have a partial workaround and an alternate solution you could try.
The stuff I was working on only applied to edges, but all of this can be extended to point meshes as well.
My workaround
My workaround I used in my experimental project recently: In Blender, before exporting my edges mesh to FBX, I add a Screw modifier and I enter 0 in all the text fields (screw, angle, steps, render step). Some of the values round up to 2. This creates two quads for each edge in the mesh, but they're all degenerate quads with two identical edges and two 0-length edges. I give the mesh object a name with "lines" in it, to identify it and tell it apart from normal meshes in the asset processing.
In Unity, I have a class LinesMesh that extends AssetPostProcessor. It disables welding vertices on the import settings to prevent the degenerate polygons from being removed by the model importer. After the mesh is processed, I recursively iterate over the transforms in the processed model to find any meshes with "lines" in their name. I change the topology to lines, and create new line indices based on the triangle indices.
I haven't done the work of collapsing all the duplicated verts down, so with this method you'll get 12 lines when all you needed/wanted was 1. This code is obviously really unfinished on that count. But, it preserves all per-vertex data like if you somehow managed to assign vertex colors and UVs to your edges in your 3D program.
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class LinesMesh : AssetPostprocessor
{
void OnPreprocessModel()
{
ModelImporter modelImporter = (ModelImporter)assetImporter;
modelImporter.weldVertices = false;
//modelImporter.addCollider = false;
}
void OnPostprocessModel(GameObject g)
{
Apply(g.transform);
}
void Apply(Transform t)
{
if (t.name.ToLower().Contains("lines") && t.GetComponent<MeshFilter>())
{
Mesh mesh = t.GetComponent<MeshFilter>().sharedMesh;
if (mesh)
{
// Toooons of duplicated and degenerate lines in this method. investigate optimizations.
for (int submesh = 0; submesh < mesh.subMeshCount; submesh++)
{
if (mesh.GetTopology(submesh) == MeshTopology.Triangles)
{
int[] triIndices = mesh.GetIndices(submesh);
int[] lineIndices = new int[triIndices.Length * 2];
for (int tri = 0; tri < triIndices.Length; tri += 3)
{
lineIndices[tri * 2] = triIndices[tri];
lineIndices[tri * 2 + 1] = triIndices[tri + 1];
lineIndices[tri * 2 + 2] = triIndices[tri + 1];
lineIndices[tri * 2 + 3] = triIndices[tri + 2];
lineIndices[tri * 2 + 4] = triIndices[tri + 2];
lineIndices[tri * 2 + 5] = triIndices[tri];
}
mesh.SetIndices(lineIndices, MeshTopology.Lines, submesh);
}
else
{
Debug.LogErrorFormat("Unhandled mesh topology ({0}) in mesh {1}", mesh.GetTopology(submesh), mesh.name);
}
}
}
else
{
Debug.LogWarningFormat("Failed to get mesh for object {0}", t.name);
}
}
// Recurse
foreach (Transform child in t)
Apply(child);
}
}
The above code should work on any mesh, not just line-like polygonal meshes, and turn them into a wireframe mesh, with about 2x the optimal number of lines.
But maybe don't use that stuff
You could make it work with more tweaks on top of the above kludge to get rid of the duplicated edges, but the extra steps in Blender of adding the modifiers, naming objects and such adds a lot of work to each mesh you need to import. If you don't care about performance at all, you could even use the above code as-is, and just ignore that you're sending 2-3 times as much vertex data to the GPU and 6-12 times as many edges than you need.
What I would suggest instead is renaming the exported model's file extension to something that Unity won't process as a model, something like mymodel.linesobj
. Then you have to produce a mesh by parsing the file yourself, since Unity doesn't give you the power to hook into the importer during the import process.
You can reference the above code for how to create a meshpart with lines topology, it should be way easier than what I did if you're parsing the obj file yourself.
The legacy way of writing custom importers:
In an asset postprocessor, you can use OnPostProcessAllAssets
to detect when a .linesobj file finished importing, and write your own OBJ parser to produce a new model with meshes with Lines topology similar to above. Then you can call AssetDatabase.CreateAsset
with the model to create a .asset file containing the model generated by your custom obj processor.
The currently experimental way to write custom importers in new versions of Unity
This is marked as experimental currently, but if this API gets completed it should be a much less janky way of custom asset processing: https://docs.unity3d.com/Manual/ScriptedImporters.html
If you do end up writing a custom importer or fixing up the mesh data, I would appreciate if you posted it here as its own answer, as I would like to revisit my project and fix the excessive geometry and tedious blender export process.