unity3d - MRTK 2.4 - 在运行时保存空间网格
问题描述
现在我正在尝试将我的 hololens 上的空间网格保存为 obj 文件。我的问题是,当尝试在 Blender(或 3D 查看器)中打开 obj 文件时,我收到一条错误消息IndexError: List index out of range
。所以我想我给我的三角形提供了错误的索引(在最后一部分MeshToString()
),但我不知道如何以正确的方式去做。
什么有效:例如,如果我只从第一个网格过滤器中取出一个网格并切掉它+ lastFaceIndex
,MeshToString()
它就可以正常工作。但这只是我房间的一部分。我想要房间里的整个网格,所以我必须遍历所有网格过滤器并获取我的网格,然后将它们写入一个 obj 文件,但我不知道如何为三角形提供正确的索引。
我还注意到,如果我通过设备门户下载网格,它大约有 4.8MB,但我通过统一应用程序下载的网格只有 1.4MB。
我的设置:
Unity 2019.3.14 MRTK 2.4 HoloLens 2nd Gen
GetSpatialMesh():
private void GetSpatialMesh()
{
if (_observer == null)
return;
List<Mesh> meshes = new List<Mesh>();
// Loop through all known Meshes
foreach (SpatialAwarenessMeshObject meshObject in _observer.Meshes.Values)
meshes.Add(meshObject.Filter.mesh);
WriteMeshToFile("MyMesh.obj", meshes);
}
WriteMeshToFile():
public static void WriteMeshToFile(string fileName, IEnumerable<Mesh> meshes)
{
string path = Path.Combine(Application.persistentDataPath, fileName);
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write))
{
faceCount = 0;
using (var writer = new StreamWriter(file, Encoding.UTF8))
{
int o = 0;
foreach (Mesh mesh in meshes)
{
o++;
writer.WriteLine("o Object." + o);
writer.Write(MeshToString(mesh, faceCount));
writer.WriteLine("");
}
}
}
}
MeshToString():
public static string MeshToString(Mesh m, int lastFaceIndex = 0)
{
StringBuilder sb = new StringBuilder();
foreach (Vector3 v in m.vertices)
{
sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z));
}
sb.Append("\n");
foreach (Vector3 v in m.normals)
{
sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
}
sb.Append("\n");
foreach (Vector3 v in m.uv)
{
sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));
}
for (int material = 0; material < m.subMeshCount; material++)
{
int[] triangles = m.GetTriangles(material);
for (int i = 0; i < triangles.Length; i += 3)
{
faceCount += 3;
sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n",
triangles[i] + 1 + lastFaceIndex, triangles[i + 1] + 1 + lastFaceIndex, triangles[i + 2] + 1 + lastFaceIndex));
}
}
return sb.ToString();
}
解决方案:
场景理解示例项目对我不起作用,所以我只是通过统一的nuget manager获得了sdk。我使用了来自SceneUnderstandingManager的代码(它是示例项目的一部分),Hernando-MSFT 在下面的回答中引用了该代码。
解决方案
嗨,我知道这有点老了,Perazim 已经解决了他的问题,但我还需要将 hololens 2 Mesh 转换为 obj,所以......也许它将来对其他人有用:),这就是为什么我我提出了我的解决方案。
不幸的是,我没有设法将代码与场景理解一起使用,正如 Hernando 所提出的那样(免责声明这是我第一次尝试对 Hololens 进行编程,所以......我很确定这是我的错)。当我尝试打电话时
SceneBuffer serializedScene = SceneObserver.ComputeSerializedAsync(querySettings, 10.0f).GetAwaiter().GetResult();
我遇到了一个错误,实际上我的应用程序不再工作了!
我所做和工作的是“手动”创建 obj,对我有用的功能如下:
private void exportScene(String targetFileName)
{
var spatialAwarenessSystem = CoreServices.SpatialAwarenessSystem;
spatialAwarenessSystem.SuspendObservers();
var observer = CoreServices.GetSpatialAwarenessSystemDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();
System.Text.StringBuilder objFileContent = new System.Text.StringBuilder(4096);
objFileContent.Append("# Automatic export of Hololens 2 scanned mesh scan. \r\n\r\n");
// Collects the spread objects
foreach (SpatialAwarenessMeshObject meshObject in observer.Meshes.Values)
{
meshes.Add(meshObject.Filter);
}
int adjust = 1;
MeshFilter[] mf = meshes.ToArray();
int countVertex = 0;
// for each object gets the vertexes normals and faces
for (int i = 0; i < mf.Length; i++)
{
Mesh m = mf[i].sharedMesh;
objFileContent.Append("o Object." + (i + 1) + "\r\n");
// inverts x as the coordinates are different from the ones of regular obj
foreach (Vector3 v in m.vertices)
{
float x = -v.x;
float z = v.z;
objFileContent.Append("v " + x.ToString("0.000000", CultureInfo.InvariantCulture) + " " + v.y.ToString("0.000000", CultureInfo.InvariantCulture) + " " + z.ToString("0.000000", CultureInfo.InvariantCulture) + "\r\n");
}
objFileContent.Append("\r\n\r\n");
foreach (Vector3 n in m.normals)
{
float x = n.x;
float z = n.z;
objFileContent.Append("vn " + x.ToString("0.000000", CultureInfo.InvariantCulture) + " " + n.y.ToString("0.000000", CultureInfo.InvariantCulture) + " " + z.ToString("0.000000", CultureInfo.InvariantCulture) + "\r\n");
}
objFileContent.Append("\r\n\r\n");
// the count of the faces starts with 1 and is cumulative for
// all objects on the scene this is why it is add
// adjust + countVertex as the id of the vertexes
for (int ti = 0; ti < m.triangles.Length; ti += 3)
{
objFileContent.Append("f " + (m.triangles[ti] + adjust + countVertex ) + "//" + (m.triangles[ti] + adjust + countVertex) + " " + (m.triangles[ti + 1] + adjust + countVertex) + "//" + (m.triangles[ti + 1] + adjust + countVertex) + " " + (m.triangles[ti + 2] + adjust + countVertex) + "//" + (m.triangles[ti + 2] + adjust + countVertex) + "\r\n");
}
objFileContent.Append("\r\n\r\n");
countVertex += m.vertexCount;
}
// string objPath = Path.Combine(sceneFolderPath, sceneName + ".obj");
using (StreamWriter sw = File.AppendText(targetFileName))
{
sw.WriteLine(objFileContent.ToString());
}
}
推荐阅读
- firebase - 如何使用 map 方法省略具有不存在键或空值的文档的迭代
- omnet++ - 静脉行人模拟 (omnet++/sumo)
- sql - 在 Select 中创建 DateFirst
- cypress - 如何在赛普拉斯测试执行期间捕获意外错误消息?
- pic - Mikrocontroller (PIC16F1827) ADC 加扰输出与 MPLAB 中的 MCC
- python - Tensorflow,如何存储变量?
- python - 使用python从字符串中提取确切的单词
- python - 为什么服务器中的套接字绑定需要它的 IP 地址 >
- odata - odata 跳过和热门问题
- java - 电梯:用户输入