private int uploadMesh()

in RealityMaterialExplorer/Assets/Oculus/Spatializer/scripts/ONSPPropagationGeometry.cs [230:460]


    private int uploadMesh(IntPtr geometryHandle, GameObject meshObject, Matrix4x4 worldToLocal, bool ignoreStatic, ref int ignoredMeshCount)
    {
        // Get the child mesh objects.
        List<MeshMaterial> meshes = new List<MeshMaterial>();
        List<TerrainMaterial> terrains = new List<TerrainMaterial>();
        traverseMeshHierarchy(meshObject, null, includeChildMeshes, meshes, terrains, ignoreStatic, ref ignoredMeshCount);

        //***********************************************************************
        // Count the number of vertices and indices.

        int totalVertexCount = 0;
        uint totalIndexCount = 0;
        int totalFaceCount = 0;
        int totalMaterialCount = 0;

        foreach (MeshMaterial m in meshes)
        {
            updateCountsForMesh(ref totalVertexCount, ref totalIndexCount, ref totalFaceCount, ref totalMaterialCount, m.meshFilter.sharedMesh);
        }

        // TODO: expose tree material
        ONSPPropagationMaterial[] treeMaterials = new ONSPPropagationMaterial[1];
        
        for (int i = 0; i < terrains.Count; ++i)
        {
            TerrainMaterial t = terrains[i];
            TerrainData terrain = t.terrain.terrainData;

#if UNITY_2019_3_OR_NEWER
            int w = terrain.heightmapResolution;
            int h = terrain.heightmapResolution;
#else
            int w = terrain.heightmapWidth;
            int h = terrain.heightmapHeight;
#endif
            int wRes = (w - 1) / terrainDecimation + 1;
            int hRes = (h - 1) / terrainDecimation + 1;
            int vertexCount = wRes * hRes;
            int indexCount = (wRes - 1) * (hRes - 1) * 6;

            totalMaterialCount++;
            totalVertexCount += vertexCount;
            totalIndexCount += (uint)indexCount;
            totalFaceCount += indexCount / 3;

#if INCLUDE_TERRAIN_TREES
            TreePrototype[] treePrototypes = terrain.treePrototypes;

            if (treePrototypes.Length != 0)
            {
                if (treeMaterials[0] == null)
                {
                    // Create the tree material
                    treeMaterials[0] = gameObject.AddComponent<ONSPPropagationMaterial>();
#if true
                    treeMaterials[0].SetPreset(ONSPPropagationMaterial.Preset.Foliage);
#else
                    // Custom material that is highly transmissive
                    treeMaterials[0].absorption.points = new List<ONSPPropagationMaterial.Point>{
			            new ONSPPropagationMaterial.Point(125f,  .03f), 
                        new ONSPPropagationMaterial.Point(250f,  .06f), 
                        new ONSPPropagationMaterial.Point(500f,  .11f), 
                        new ONSPPropagationMaterial.Point(1000f, .17f), 
                        new ONSPPropagationMaterial.Point(2000f, .27f), 
                        new ONSPPropagationMaterial.Point(4000f, .31f) };

                    treeMaterials[0].scattering.points = new List<ONSPPropagationMaterial.Point>{
			            new ONSPPropagationMaterial.Point(125f,  .20f), 
                        new ONSPPropagationMaterial.Point(250f,  .3f), 
                        new ONSPPropagationMaterial.Point(500f,  .4f), 
                        new ONSPPropagationMaterial.Point(1000f, .5f), 
                        new ONSPPropagationMaterial.Point(2000f, .7f), 
                        new ONSPPropagationMaterial.Point(4000f, .8f) };

                    treeMaterials[0].transmission.points = new List<ONSPPropagationMaterial.Point>(){
			            new ONSPPropagationMaterial.Point(125f,  .95f), 
                        new ONSPPropagationMaterial.Point(250f,  .92f), 
                        new ONSPPropagationMaterial.Point(500f,  .87f), 
                        new ONSPPropagationMaterial.Point(1000f, .81f), 
                        new ONSPPropagationMaterial.Point(2000f, .71f), 
                        new ONSPPropagationMaterial.Point(4000f, .67f) };
#endif
                }

                t.treePrototypeMeshes = new Mesh[treePrototypes.Length];

                // assume the sharedMesh with the lowest vertex is the lowest LOD
                for (int j = 0; j < treePrototypes.Length; ++j)
                {
                    GameObject prefab = treePrototypes[j].prefab;
                    MeshFilter[] meshFilters = prefab.GetComponentsInChildren<MeshFilter>();
                    int minVertexCount = int.MaxValue;
                    int index = -1;
                    for (int k = 0; k < meshFilters.Length; ++k)
                    {
                        int count = meshFilters[k].sharedMesh.vertexCount;
                        if (count < minVertexCount)
                        {
                            minVertexCount = count;
                            index = k;
                        }
                    }

                    t.treePrototypeMeshes[j] = meshFilters[index].sharedMesh;
                }

                TreeInstance[] trees = terrain.treeInstances;
                foreach (TreeInstance tree in trees)
                {
                    updateCountsForMesh(ref totalVertexCount, ref totalIndexCount, ref totalFaceCount,
                        ref totalMaterialCount, t.treePrototypeMeshes[tree.prototypeIndex]);
                }

                terrains[i] = t;
            }
#endif
        }

        //***********************************************************************
        // Copy the mesh data.

        List<Vector3> tempVertices = new List<Vector3>();
        List<int> tempIndices = new List<int>();

        MeshGroup[] groups = new MeshGroup[totalMaterialCount];
        float[] vertices = new float[totalVertexCount * 3];
        int[] indices = new int[totalIndexCount];

        int vertexOffset = 0;
        int indexOffset = 0;
        int groupOffset = 0;

        foreach (MeshMaterial m in meshes)
        {
            MeshFilter meshFilter = m.meshFilter;

            // Compute the combined transform to go from mesh-local to geometry-local space.
            Matrix4x4 matrix = worldToLocal * meshFilter.gameObject.transform.localToWorldMatrix;

            uploadMeshFilter(tempVertices, tempIndices, groups, vertices, indices, ref vertexOffset, ref indexOffset, ref groupOffset, meshFilter.sharedMesh, m.materials, matrix);
        }

        foreach (TerrainMaterial t in terrains)
        {
            TerrainData terrain = t.terrain.terrainData;

            // Compute the combined transform to go from mesh-local to geometry-local space.
            Matrix4x4 matrix = worldToLocal * t.terrain.gameObject.transform.localToWorldMatrix;

#if UNITY_2019_3_OR_NEWER
            int w = terrain.heightmapResolution;
            int h = terrain.heightmapResolution;
#else
            int w = terrain.heightmapWidth;
            int h = terrain.heightmapHeight;
#endif
            float[,] tData = terrain.GetHeights(0, 0, w, h);

            Vector3 meshScale = terrain.size;
            meshScale = new Vector3(meshScale.x / (w - 1) * terrainDecimation, meshScale.y, meshScale.z / (h - 1) * terrainDecimation);
            int wRes = (w - 1) / terrainDecimation + 1;
            int hRes = (h - 1) / terrainDecimation + 1;
            int vertexCount = wRes * hRes;
            int triangleCount = (wRes - 1) * (hRes - 1) * 2;

            // Initialize the group.
            groups[groupOffset].faceType = FaceType.TRIANGLES;
            groups[groupOffset].faceCount = (UIntPtr)triangleCount;
            groups[groupOffset].indexOffset = (UIntPtr)indexOffset;

            if (t.materials != null && 0 < t.materials.Length)
            {
                t.materials[0].StartInternal();
                groups[groupOffset].material = t.materials[0].materialHandle;
            }
            else
                groups[groupOffset].material = IntPtr.Zero;

            // Build vertices and UVs
            for (int y = 0; y < hRes; y++)
            {
                for (int x = 0; x < wRes; x++)
                {
                    int offset = (vertexOffset + y * wRes + x) * 3;
                    Vector3 v = matrix.MultiplyPoint3x4(Vector3.Scale(meshScale, new Vector3(y, tData[x * terrainDecimation, y * terrainDecimation], x)));
                    vertices[offset + 0] = v.x;
                    vertices[offset + 1] = v.y;
                    vertices[offset + 2] = v.z;
                }
            }

            // Build triangle indices: 3 indices into vertex array for each triangle
            for (int y = 0; y < hRes - 1; y++)
            {
                for (int x = 0; x < wRes - 1; x++)
                {
                    // For each grid cell output two triangles
                    indices[indexOffset + 0] = (vertexOffset + (y * wRes) + x);
                    indices[indexOffset + 1] = (vertexOffset + ((y + 1) * wRes) + x);
                    indices[indexOffset + 2] = (vertexOffset + (y * wRes) + x + 1);

                    indices[indexOffset + 3] = (vertexOffset + ((y + 1) * wRes) + x);
                    indices[indexOffset + 4] = (vertexOffset + ((y + 1) * wRes) + x + 1);
                    indices[indexOffset + 5] = (vertexOffset + (y * wRes) + x + 1);
                    indexOffset += 6;
                }
            }

            vertexOffset += vertexCount;
            groupOffset++;

#if INCLUDE_TERRAIN_TREES
            TreeInstance[] trees = terrain.treeInstances;
            foreach (TreeInstance tree in trees)
            {
                Vector3 pos = Vector3.Scale(tree.position, terrain.size);
                Matrix4x4 treeLocalToWorldMatrix = t.terrain.gameObject.transform.localToWorldMatrix;
                treeLocalToWorldMatrix.SetColumn(3, treeLocalToWorldMatrix.GetColumn(3) + new Vector4(pos.x, pos.y, pos.z, 0.0f));
                // TODO: tree rotation
                Matrix4x4 treeMatrix = worldToLocal * treeLocalToWorldMatrix;
                uploadMeshFilter(tempVertices, tempIndices, groups, vertices, indices, ref vertexOffset, ref indexOffset, ref groupOffset, t.treePrototypeMeshes[tree.prototypeIndex], treeMaterials, treeMatrix);
            }
#endif
        }

        // Upload mesh data
        return ONSPPropagation.Interface.AudioGeometryUploadMeshArrays(geometryHandle,
                                                       vertices, totalVertexCount,
                                                       indices, indices.Length,
                                                       groups, groups.Length);
    }