387 lines
11 KiB
C#
387 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Oculus.Spatializer.Propagation;
|
|
using UnityEngine;
|
|
|
|
public class ONSPPropagationGeometry : MonoBehaviour
|
|
{
|
|
private struct MeshMaterial
|
|
{
|
|
public MeshFilter meshFilter;
|
|
|
|
public ONSPPropagationMaterial[] materials;
|
|
}
|
|
|
|
private struct TerrainMaterial
|
|
{
|
|
public Terrain terrain;
|
|
|
|
public ONSPPropagationMaterial[] materials;
|
|
}
|
|
|
|
public static string GeometryAssetDirectory = "AudioGeometry";
|
|
|
|
public string filePathRelative = string.Empty;
|
|
|
|
public bool fileEnabled;
|
|
|
|
public bool includeChildMeshes = true;
|
|
|
|
private IntPtr geometryHandle = IntPtr.Zero;
|
|
|
|
public static int OSPSuccess;
|
|
|
|
private static int terrainDecimation = 4;
|
|
|
|
public static string GeometryAssetPath
|
|
{
|
|
get
|
|
{
|
|
return Application.streamingAssetsPath + "/" + GeometryAssetDirectory;
|
|
}
|
|
}
|
|
|
|
public string filePath
|
|
{
|
|
get
|
|
{
|
|
return GeometryAssetPath + "/" + filePathRelative;
|
|
}
|
|
}
|
|
|
|
public static string GetPath(Transform current)
|
|
{
|
|
if (current.parent == null)
|
|
{
|
|
return current.gameObject.scene.name + "/" + current.name;
|
|
}
|
|
return GetPath(current.parent) + "-" + current.name;
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
CreatePropagationGeometry();
|
|
}
|
|
|
|
private void CreatePropagationGeometry()
|
|
{
|
|
if (ONSPPropagation.Interface.CreateAudioGeometry(out geometryHandle) != OSPSuccess)
|
|
{
|
|
throw new Exception("Unable to create geometry handle");
|
|
}
|
|
if (filePath != null && filePath.Length != 0 && fileEnabled && Application.isPlaying)
|
|
{
|
|
if (!ReadFile())
|
|
{
|
|
Debug.LogError("Failed to read file, attempting to regenerate audio geometry");
|
|
UploadGeometry();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UploadGeometry();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!(geometryHandle == IntPtr.Zero))
|
|
{
|
|
Matrix4x4 localToWorldMatrix = base.transform.localToWorldMatrix;
|
|
float[] matrix4x = new float[16]
|
|
{
|
|
localToWorldMatrix[0, 0],
|
|
localToWorldMatrix[1, 0],
|
|
0f - localToWorldMatrix[2, 0],
|
|
localToWorldMatrix[3, 0],
|
|
localToWorldMatrix[0, 1],
|
|
localToWorldMatrix[1, 1],
|
|
0f - localToWorldMatrix[2, 1],
|
|
localToWorldMatrix[3, 1],
|
|
localToWorldMatrix[0, 2],
|
|
localToWorldMatrix[1, 2],
|
|
0f - localToWorldMatrix[2, 2],
|
|
localToWorldMatrix[3, 2],
|
|
localToWorldMatrix[0, 3],
|
|
localToWorldMatrix[1, 3],
|
|
0f - localToWorldMatrix[2, 3],
|
|
localToWorldMatrix[3, 3]
|
|
};
|
|
ONSPPropagation.Interface.AudioGeometrySetTransform(geometryHandle, matrix4x);
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (geometryHandle != IntPtr.Zero && ONSPPropagation.Interface.DestroyAudioGeometry(geometryHandle) != OSPSuccess)
|
|
{
|
|
throw new Exception("Unable to destroy geometry");
|
|
}
|
|
geometryHandle = IntPtr.Zero;
|
|
}
|
|
|
|
private static void traverseMeshHierarchy(GameObject obj, ONSPPropagationMaterial[] currentMaterials, bool includeChildren, List<MeshMaterial> meshMaterials, List<TerrainMaterial> terrainMaterials, bool ignoreStatic)
|
|
{
|
|
if (!obj.activeInHierarchy)
|
|
{
|
|
return;
|
|
}
|
|
MeshFilter[] components = obj.GetComponents<MeshFilter>();
|
|
Terrain[] components2 = obj.GetComponents<Terrain>();
|
|
ONSPPropagationMaterial[] components3 = obj.GetComponents<ONSPPropagationMaterial>();
|
|
if (components3 != null && components3.Length > 0)
|
|
{
|
|
int num = components3.Length;
|
|
if (currentMaterials != null)
|
|
{
|
|
num = Math.Max(num, currentMaterials.Length);
|
|
}
|
|
ONSPPropagationMaterial[] array = new ONSPPropagationMaterial[num];
|
|
if (currentMaterials != null)
|
|
{
|
|
for (int i = components3.Length; i < num; i++)
|
|
{
|
|
array[i] = currentMaterials[i];
|
|
}
|
|
}
|
|
currentMaterials = array;
|
|
for (int j = 0; j < components3.Length; j++)
|
|
{
|
|
currentMaterials[j] = components3[j];
|
|
}
|
|
}
|
|
MeshFilter[] array2 = components;
|
|
foreach (MeshFilter meshFilter in array2)
|
|
{
|
|
Mesh sharedMesh = meshFilter.sharedMesh;
|
|
if (!(sharedMesh == null))
|
|
{
|
|
if (ignoreStatic && !sharedMesh.isReadable)
|
|
{
|
|
Debug.Log("Mesh: " + meshFilter.gameObject.name + " not readable, cannot be static.");
|
|
continue;
|
|
}
|
|
meshMaterials.Add(new MeshMaterial
|
|
{
|
|
meshFilter = meshFilter,
|
|
materials = currentMaterials
|
|
});
|
|
}
|
|
}
|
|
Terrain[] array3 = components2;
|
|
foreach (Terrain terrain in array3)
|
|
{
|
|
terrainMaterials.Add(new TerrainMaterial
|
|
{
|
|
terrain = terrain,
|
|
materials = currentMaterials
|
|
});
|
|
}
|
|
if (!includeChildren)
|
|
{
|
|
return;
|
|
}
|
|
foreach (Transform item in obj.transform)
|
|
{
|
|
if (item.GetComponent<ONSPPropagationGeometry>() == null)
|
|
{
|
|
traverseMeshHierarchy(item.gameObject, currentMaterials, includeChildren, meshMaterials, terrainMaterials, ignoreStatic);
|
|
}
|
|
}
|
|
}
|
|
|
|
private int uploadMesh(IntPtr geometryHandle, GameObject meshObject, Matrix4x4 worldToLocal, bool ignoreStatic)
|
|
{
|
|
List<MeshMaterial> list = new List<MeshMaterial>();
|
|
List<TerrainMaterial> list2 = new List<TerrainMaterial>();
|
|
traverseMeshHierarchy(meshObject, null, includeChildMeshes, list, list2, ignoreStatic);
|
|
int num = 0;
|
|
uint num2 = 0u;
|
|
int num3 = 0;
|
|
int num4 = 0;
|
|
foreach (MeshMaterial item in list)
|
|
{
|
|
Mesh sharedMesh = item.meshFilter.sharedMesh;
|
|
num4 += sharedMesh.subMeshCount;
|
|
num += sharedMesh.vertexCount;
|
|
for (int i = 0; i < sharedMesh.subMeshCount; i++)
|
|
{
|
|
MeshTopology topology = sharedMesh.GetTopology(i);
|
|
if (topology == MeshTopology.Triangles || topology == MeshTopology.Quads)
|
|
{
|
|
uint indexCount = sharedMesh.GetIndexCount(i);
|
|
num2 += indexCount;
|
|
switch (topology)
|
|
{
|
|
case MeshTopology.Triangles:
|
|
num3 += (int)indexCount / 3;
|
|
break;
|
|
case MeshTopology.Quads:
|
|
num3 += (int)indexCount / 4;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foreach (TerrainMaterial item2 in list2)
|
|
{
|
|
TerrainData terrainData = item2.terrain.terrainData;
|
|
int heightmapWidth = terrainData.heightmapWidth;
|
|
int heightmapHeight = terrainData.heightmapHeight;
|
|
int num5 = (heightmapWidth - 1) / terrainDecimation + 1;
|
|
int num6 = (heightmapHeight - 1) / terrainDecimation + 1;
|
|
int num7 = num5 * num6;
|
|
int num8 = (num5 - 1) * (num6 - 1) * 6;
|
|
num4++;
|
|
num += num7;
|
|
num2 += (uint)num8;
|
|
num3 += num8 / 3;
|
|
}
|
|
List<Vector3> list3 = new List<Vector3>();
|
|
List<int> list4 = new List<int>();
|
|
MeshGroup[] array = new MeshGroup[num4];
|
|
float[] array2 = new float[num * 3];
|
|
int[] array3 = new int[num2];
|
|
int num9 = 0;
|
|
int num10 = 0;
|
|
int num11 = 0;
|
|
foreach (MeshMaterial item3 in list)
|
|
{
|
|
MeshFilter meshFilter = item3.meshFilter;
|
|
Mesh sharedMesh2 = meshFilter.sharedMesh;
|
|
Matrix4x4 matrix4x = worldToLocal * meshFilter.gameObject.transform.localToWorldMatrix;
|
|
list3.Clear();
|
|
sharedMesh2.GetVertices(list3);
|
|
int count = list3.Count;
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
Vector3 vector = matrix4x.MultiplyPoint3x4(list3[j]);
|
|
int num12 = (num9 + j) * 3;
|
|
array2[num12] = vector.x;
|
|
array2[num12 + 1] = vector.y;
|
|
array2[num12 + 2] = vector.z;
|
|
}
|
|
for (int k = 0; k < sharedMesh2.subMeshCount; k++)
|
|
{
|
|
MeshTopology topology2 = sharedMesh2.GetTopology(k);
|
|
if (topology2 != MeshTopology.Triangles && topology2 != MeshTopology.Quads)
|
|
{
|
|
continue;
|
|
}
|
|
list4.Clear();
|
|
sharedMesh2.GetIndices(list4, k);
|
|
int count2 = list4.Count;
|
|
for (int l = 0; l < count2; l++)
|
|
{
|
|
array3[num10 + l] = list4[l] + num9;
|
|
}
|
|
switch (topology2)
|
|
{
|
|
case MeshTopology.Triangles:
|
|
array[num11 + k].faceType = FaceType.TRIANGLES;
|
|
array[num11 + k].faceCount = (UIntPtr)(ulong)(count2 / 3);
|
|
break;
|
|
case MeshTopology.Quads:
|
|
array[num11 + k].faceType = FaceType.QUADS;
|
|
array[num11 + k].faceCount = (UIntPtr)(ulong)(count2 / 4);
|
|
break;
|
|
}
|
|
array[num11 + k].indexOffset = (UIntPtr)(ulong)num10;
|
|
if (item3.materials != null && item3.materials.Length != 0)
|
|
{
|
|
int num13 = k;
|
|
if (num13 >= item3.materials.Length)
|
|
{
|
|
num13 = item3.materials.Length - 1;
|
|
}
|
|
item3.materials[num13].StartInternal();
|
|
array[num11 + k].material = item3.materials[num13].materialHandle;
|
|
}
|
|
else
|
|
{
|
|
array[num11 + k].material = IntPtr.Zero;
|
|
}
|
|
num10 += count2;
|
|
}
|
|
num9 += count;
|
|
num11 += sharedMesh2.subMeshCount;
|
|
}
|
|
foreach (TerrainMaterial item4 in list2)
|
|
{
|
|
TerrainData terrainData2 = item4.terrain.terrainData;
|
|
Matrix4x4 matrix4x2 = worldToLocal * item4.terrain.gameObject.transform.localToWorldMatrix;
|
|
int heightmapWidth2 = terrainData2.heightmapWidth;
|
|
int heightmapHeight2 = terrainData2.heightmapHeight;
|
|
float[,] heights = terrainData2.GetHeights(0, 0, heightmapWidth2, heightmapHeight2);
|
|
Vector3 size = terrainData2.size;
|
|
size = new Vector3(size.x / (float)(heightmapWidth2 - 1) * (float)terrainDecimation, size.y, size.z / (float)(heightmapHeight2 - 1) * (float)terrainDecimation);
|
|
int num14 = (heightmapWidth2 - 1) / terrainDecimation + 1;
|
|
int num15 = (heightmapHeight2 - 1) / terrainDecimation + 1;
|
|
int num16 = num14 * num15;
|
|
int num17 = (num14 - 1) * (num15 - 1) * 2;
|
|
array[num11].faceType = FaceType.TRIANGLES;
|
|
array[num11].faceCount = (UIntPtr)(ulong)num17;
|
|
array[num11].indexOffset = (UIntPtr)(ulong)num10;
|
|
if (item4.materials != null && 0 < item4.materials.Length)
|
|
{
|
|
item4.materials[0].StartInternal();
|
|
array[num11].material = item4.materials[0].materialHandle;
|
|
}
|
|
else
|
|
{
|
|
array[num11].material = IntPtr.Zero;
|
|
}
|
|
for (int m = 0; m < num15; m++)
|
|
{
|
|
for (int n = 0; n < num14; n++)
|
|
{
|
|
int num18 = (num9 + m * num14 + n) * 3;
|
|
Vector3 vector2 = matrix4x2.MultiplyPoint3x4(Vector3.Scale(size, new Vector3(m, heights[n * terrainDecimation, m * terrainDecimation], n)));
|
|
array2[num18] = vector2.x;
|
|
array2[num18 + 1] = vector2.y;
|
|
array2[num18 + 2] = vector2.z;
|
|
}
|
|
}
|
|
for (int num19 = 0; num19 < num15 - 1; num19++)
|
|
{
|
|
for (int num20 = 0; num20 < num14 - 1; num20++)
|
|
{
|
|
array3[num10] = num9 + num19 * num14 + num20;
|
|
array3[num10 + 1] = num9 + (num19 + 1) * num14 + num20;
|
|
array3[num10 + 2] = num9 + num19 * num14 + num20 + 1;
|
|
array3[num10 + 3] = num9 + (num19 + 1) * num14 + num20;
|
|
array3[num10 + 4] = num9 + (num19 + 1) * num14 + num20 + 1;
|
|
array3[num10 + 5] = num9 + num19 * num14 + num20 + 1;
|
|
num10 += 6;
|
|
}
|
|
}
|
|
num9 += num16;
|
|
num11++;
|
|
}
|
|
return ONSPPropagation.Interface.AudioGeometryUploadMeshArrays(geometryHandle, array2, num, array3, array3.Length, array, array.Length);
|
|
}
|
|
|
|
public void UploadGeometry()
|
|
{
|
|
if (uploadMesh(geometryHandle, base.gameObject, base.gameObject.transform.worldToLocalMatrix, true) != OSPSuccess)
|
|
{
|
|
throw new Exception("Unable to upload audio mesh geometry");
|
|
}
|
|
}
|
|
|
|
public bool ReadFile()
|
|
{
|
|
if (filePath == null || filePath.Length == 0)
|
|
{
|
|
Debug.LogError("Invalid mesh file path");
|
|
return false;
|
|
}
|
|
if (ONSPPropagation.Interface.AudioGeometryReadMeshFile(geometryHandle, filePath) != OSPSuccess)
|
|
{
|
|
Debug.LogError("Error reading mesh file " + filePath);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|