void PrepareScene(Transform locationRoot, Dictionary <string, string> savedStandardMeshes, Dictionary <string, string> savedObjectMeshes) { for (int i = 0; i < locationRoot.childCount; i++) { Transform loc = locationRoot.GetChild(i); WG_LocationController locController = loc.GetComponent <WG_LocationController>(); if (locController != null) { locController.PrepareLocation("Assets" + assetMeshPath, "Assets" + assetMaterialPath, "Assets" + assetTexturePath, "Assets" + assetMinimapPath, lightMapShader, minimapSize, minimapCamera, minimapCameraHeight, exportLightmapHDR, savedStandardMeshes, savedObjectMeshes); } } //prepare navmesh WG_TerrainBuilder builderComponent = builder.gameObject.GetComponent <WG_TerrainBuilder>(); NavMeshData data = builderComponent.GetNavmeshData(); if (data != null) { SaveNavmeshAsset(data); localNavMesh = data; } }
public void BuildNavmeshOnly() { WG_LocationController[] locations = GetComponentsInChildren <WG_LocationController>(); if (locations.Length > 0) { WG_LocationController loc = locations[0]; NavMeshSurface navSurface = loc.groundGO.GetComponent <NavMeshSurface>(); navSurface.BuildNavMesh(); SaveNavMeshData(navSurface.navMeshData); } }
WG_LocationController GetLocationByCoordinates(IntPair coords, List <WG_LocationController> locations) { for (int i = 0; i < locations.Count; i++) { WG_LocationController loc = locations[i]; if (loc.u == coords.u && loc.v == coords.v) { return(loc); } } return(null); }
void PrepareScene(Transform locationRoot, Dictionary <string, string> savedStandardMeshes, Dictionary <string, string> savedObjectMeshes) { for (int i = 0; i < locationRoot.childCount; i++) { Transform loc = locationRoot.GetChild(i); WG_LocationController locController = loc.GetComponent <WG_LocationController>(); if (locController != null) { locController.PrepareLocation("Assets" + assetMeshPath, "Assets" + assetMaterialPath, "Assets" + assetTexturePath, "Assets" + assetMinimapPath, lwrpShader, stdShaders, lmMode, minimapSize, minimapCamera, minimapCameraHeight, exportLightmapHDR, ldrAmbientCompensation, ldrLightmapMultiplier, savedStandardMeshes, savedObjectMeshes); } } PrepareNavmesh(); }
void ExportScene(Transform locationRoot) { for (int i = 0; i < locationRoot.childCount; i++) { Transform loc = locationRoot.GetChild(i); WG_LocationController locController = loc.GetComponent <WG_LocationController>(); if (locController != null) { locController.ExportLocation("Assets" + assetLocationPath, minimapSize, minimapCamera, minimapCameraHeight, "Assets" + assetMinimapPath); } } //export navmesh #if UNITY_EDITOR WG_TerrainBuilder builderComponent = builder.gameObject.GetComponent <WG_TerrainBuilder>(); NavMeshData data = builderComponent.GetNavmeshData(); string navmeshAssetPath = ""; if (data != null) { navmeshAssetPath = "navmeshes/" + data.name; AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(data)).SetAssetBundleNameAndVariant(navmeshAssetPath, ""); } else { if (localNavMesh == null) { Debug.Log("Navmesh data is null, can't export it."); } else { Debug.Log("Use local version of the navmesh data object."); data = localNavMesh; navmeshAssetPath = "navmeshes/" + localNavMesh.name; AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(localNavMesh)).SetAssetBundleNameAndVariant(navmeshAssetPath, ""); } } //create xml with navmeshlink and starting points GlobalLocation globalLocation = new GlobalLocation(); if (navmeshAssetPath.Length > 0 && data != null) { globalLocation.navmeshData = new NavmeshData() { link = navmeshAssetPath, name = data.name }; if (exportPlayerPositionsInLocations) { globalLocation.positions = new List <PositionData>(); WG_Position[] positions = FindObjectsOfType <WG_Position>(); for (int i = 0; i < positions.Length; i++) { Vector3 pos = positions[i].gameObject.transform.position; globalLocation.positions.Add(new PositionData() { positionX = pos.x, positionY = pos.y, positionZ = pos.z }); } if (globalLocation.positions.Count == 0) { Debug.Log("No start positions on the scene. Add default position (0, 0, 0)."); globalLocation.positions.Add(new PositionData() { positionX = 0.0f, positionY = 0.0f, positionZ = 0.0f }); } } globalLocation.bounds = new LocationsBounds() { minU = builderComponent.segmentsMinX, maxU = builderComponent.segmenstMaxX, minV = builderComponent.segmentsMinY, maxV = builderComponent.segmenstMaxY }; globalLocation.locationSize = new LocationSize() { value = builderComponent.segmentSize }; string globalLocationName = "global_location"; string globalLocationAssetPath = "Assets" + assetLocationPath + globalLocationName + ".xml"; globalLocation.Save(globalLocationAssetPath); AssetDatabase.ImportAsset(globalLocationAssetPath, ImportAssetOptions.ForceUpdate); AssetImporter.GetAtPath(globalLocationAssetPath).SetAssetBundleNameAndVariant("locations/" + globalLocationName, ""); //export server data SavePlayerPositions(); //SaveCollisionMap(data); SaveCollisionMap(serverPath); SaveTowerPositions(); } #endif }
WG_LocationController EmitSegment(int u, int v, float segmentSize, float meshSquareSize, Transform root, bool[,] map, Material floorMaterial, Material wallsMaterial, float height, float uvPadding) { //create game object GameObject location = new GameObject() { name = "location_" + u.ToString() + "_" + v.ToString() }; location.transform.SetParent(root); location.transform.position = new Vector3(u * segmentSize, 0.0f, v * segmentSize); WG_MarchingSquares marchingSquares = new WG_MarchingSquares(); MeshDataClass mountainsData = marchingSquares.GenerateMesh(map, false, -segmentSize / 2, segmentSize / 2, -segmentSize / 2, segmentSize / 2, meshSquareSize, height, false, false, 0f); MeshDataClass floorData = marchingSquares.GenerateMesh(map, true, -segmentSize / 2, segmentSize / 2, -segmentSize / 2, segmentSize / 2, meshSquareSize, 0, true, true, height); //get walls vertices and triangles from generaton of the floor MeshDataClass wallsData = marchingSquares.GetWallsData(); //union ground and mountains Vector3[] vertices = new Vector3[mountainsData.vertices.Count + floorData.vertices.Count]; int mountainsVerticesCount = mountainsData.vertices.Count; for (int i = 0; i < mountainsVerticesCount; i++) { vertices[i] = mountainsData.vertices[i]; } for (int i = 0; i < floorData.vertices.Count; i++) { vertices[mountainsVerticesCount + i] = floorData.vertices[i]; } //re-enumerate triangles int[] triangles = new int[mountainsData.triangles.Count + floorData.triangles.Count]; int mountainsTrianglesCount = mountainsData.triangles.Count; for (int i = 0; i < mountainsTrianglesCount; i++) { triangles[i] = mountainsData.triangles[i]; } for (int i = 0; i < floorData.triangles.Count; i++) { triangles[mountainsTrianglesCount + i] = floorData.triangles[i] + mountainsVerticesCount; } GameObject groundGO = new GameObject("Ground") { isStatic = true }; groundGO.transform.SetParent(location.transform, false); MeshRenderer groundRenderer = groundGO.AddComponent <MeshRenderer>(); groundRenderer.material = floorMaterial; Mesh groundMesh = new Mesh() { vertices = vertices, triangles = triangles }; groundMesh.Simplify(); groundMesh.RecalculateNormals(); //ground uv Vector2[] groundUV = new Vector2[groundMesh.vertexCount]; Vector2[] groundUV2 = new Vector2[groundMesh.vertexCount]; Vector3[] groundVertices = groundMesh.vertices; Vector2[] vertexNormals = marchingSquares.GetVertexNormals(groundMesh.vertices, groundMesh.triangles); for (int i = 0; i < groundVertices.Length; i++) { groundUV[i] = new Vector2(0.5f + groundVertices[i].x / segmentSize, 0.5f + groundVertices[i].z / segmentSize); groundUV2[i] = groundUV[i] - uvPadding * vertexNormals[i]; } groundMesh.uv = groundUV; groundMesh.uv2 = groundUV2; MeshFilter groundFilter = groundGO.AddComponent <MeshFilter>(); groundFilter.mesh = groundMesh; //next walls bool createWalls = false; GameObject wallsGO = new GameObject("Walls") { isStatic = true }; if (wallsData.vertices.Count > 0) { createWalls = true; wallsGO.transform.SetParent(location.transform, false); MeshRenderer wallsRenderer = wallsGO.AddComponent <MeshRenderer>(); wallsRenderer.material = wallsMaterial; Mesh wallsMesh = new Mesh() { vertices = wallsData.vertices.ToArray(), triangles = wallsData.triangles.ToArray() }; wallsMesh.RecalculateNormals(); //next we should calculate uv coordinates //all polygons are separate 4-sided polygons Vector2[] wallsUV = marchingSquares.GetWallsUV(); Vector2[] uv1 = new Vector2[wallsUV.Length]; Vector2[] uv2 = new Vector2[wallsUV.Length]; //uv2 should be fit to the square [0, 1]x[0, 1] //for uv1 rescale 1 to walls height float wallLength = marchingSquares.GetWallLength(); for (int i = 0; i < wallsUV.Length; i++) { Vector2 uv = wallsUV[i]; uv1[i] = new Vector2(uv.x / height, uv.y); uv2[i] = new Vector2(uv.x / wallLength, uv.y); } wallsMesh.uv = uv1; wallsMesh.uv2 = uv2; MeshFilter wallsFilter = wallsGO.AddComponent <MeshFilter>(); wallsFilter.mesh = wallsMesh; } WG_LocationController locationController = location.AddComponent <WG_LocationController>(); locationController.groundGO = groundGO; locationController.wallsGO = createWalls ? wallsGO : null; locationController.u = u; locationController.v = v; if (!createWalls) { UnityEngine.Object.DestroyImmediate(wallsGO); } return(locationController); }
public void BuildMesh() { #if UNITY_EDITOR //clear generated segments navmeshExist = false; //create helper object for all sub-generated objects GameObject store = new GameObject() { name = "Temp Store" }; Transform[] allTransforms = gameObject.GetComponentsInChildren <Transform>(); for (int trIndex = allTransforms.Length - 1; trIndex >= 0; trIndex--) { GameObject go = allTransforms[trIndex].gameObject; //try to get noise primitive component //if this component is null, then delete game object WG_Primitive_PerlinNoise noiseComponent = go.GetComponent <WG_Primitive_PerlinNoise>(); WG_Primitive_Paint paintComponent = go.GetComponent <WG_Primitive_Paint>(); WG_Painter painterComponent = go.GetComponent <WG_Painter>(); WG_VisualCenter visCenterComponent = go.GetComponent <WG_VisualCenter>(); if (go != gameObject && noiseComponent == null && paintComponent == null && painterComponent == null && visCenterComponent == null) { if (clearAll) { DestroyImmediate(go); } else { //check is this object contains location controller WG_LocationController locController = go.GetComponent <WG_LocationController>(); if (locController != null) {//this is location root object, destoy it DestroyImmediate(go); } else { //this is not location root, may be walls or ground object if (go.name == groundName || go.name == wallsName || go.name == meshRootName) { //this is generated ground or wall object, destoy it DestroyImmediate(go); } else {//this is sub-placed object, store it if (PrefabUtility.GetOutermostPrefabInstanceRoot(go) == null || PrefabUtility.GetOutermostPrefabInstanceRoot(go) == go) { go.transform.SetParent(store.transform, true); } } } } } } //fill map for all location segments bool[,] map = new bool[(segmenstMaxX - segmentsMinX + 1) * meshSquaresCount + 1, (segmenstMaxY - segmentsMinY + 1) * meshSquaresCount + 1]; WG_Primitive_BaseNoise[] noises = gameObject.GetComponentsInChildren <WG_Primitive_BaseNoise>(); float meshSquareSize = segmentSize / meshSquaresCount; Vector2 bottomLeftCorner = new Vector2((segmentsMinX - 0.5f) * segmentSize, (segmentsMinY - 0.5f) * segmentSize); for (int x = 0; x < map.GetLength(0); x++) { for (int y = 0; y < map.GetLength(1); y++) { Vector2 pos = new Vector2(x * meshSquareSize, y * meshSquareSize) + bottomLeftCorner; map[x, y] = IsPointMountains(pos, noises); } } //next create root for location segments GameObject locationsRoot = new GameObject { name = meshRootName }; locationsRoot.transform.SetParent(gameObject.transform); //create location generator WG_SegmentsGenerator generator = new WG_SegmentsGenerator(); List <WG_LocationController> locations = generator.GenerateLocationSegments(this, segmentSize, meshSquareSize, meshSquaresCount, segmentsMinX, segmenstMaxX, segmentsMinY, segmenstMaxY, locationsRoot, groundMaterial, mountainsMaterial, wallsMaterial, map, mountainsHeight, !(forceUpdate && buildMesh), navMeshCutVolume, uv2Padding); #endif #if UNITY_EDITOR //after generation we should place back all stored objects, we will place it inside location root object Transform[] storedObjects = store.GetComponentsInChildren <Transform>(); for (int tfmIndex = 0; tfmIndex < storedObjects.Length; tfmIndex++) { Transform tfm = storedObjects[tfmIndex]; if (tfm.gameObject != store) { Vector3 position = tfm.position; IntPair locCoords = WG_Helper.GetLocationCoordinates(position, segmentSize); WG_LocationController loc = GetLocationByCoordinates(locCoords, locations); if (loc != null) { //rever prefab properties (mesh and material) GameObject prefabMaster = PrefabUtility.GetOutermostPrefabInstanceRoot(tfm.gameObject); MeshFilter meshComponent = tfm.GetComponent <MeshFilter>(); if ((prefabMaster == null && meshComponent != null) || prefabMaster == tfm.gameObject) { Vector3 scale = tfm.localScale; GameObject source = PrefabUtility.GetCorrespondingObjectFromSource(tfm.gameObject); if (source != null) { PrefabUtility.RevertPrefabInstance(tfm.gameObject, InteractionMode.UserAction); } tfm.localScale = scale; //move object inside location tfm.SetParent(loc.gameObject.transform, true); tfm.position += loc.gameObject.transform.position; } } else { Debug.Log("There is no locations with coordinates " + locCoords.ToString() + ", so skip the object " + tfm.gameObject.name); } } } //delete temp store DestroyImmediate(store); #endif BuildNavmeshOnly(); }
void ExportScene(Transform locationRoot) { WG_Helper.ClearFolder(Application.dataPath + assetLocationSOPath); for (int i = 0; i < locationRoot.childCount; i++) { Transform loc = locationRoot.GetChild(i); WG_LocationController locController = loc.GetComponent <WG_LocationController>(); if (locController != null) { locController.ExportLocation("Assets" + assetLocationXMLPath, "Assets" + assetLocationSOPath, minimapSize, minimapCamera, minimapCameraHeight, "Assets" + assetMinimapPath); } } #if UNITY_EDITOR //export navmesh WG_TerrainBuilder builderComponent = builder.gameObject.GetComponent <WG_TerrainBuilder>(); NavMeshData data = builderComponent.GetNavmeshData(); string navmeshAssetPath = ""; if (data != null) { navmeshAssetPath = "navmeshes/" + data.name; AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(data)).SetAssetBundleNameAndVariant(navmeshAssetPath, ""); } else { if (localNavMesh == null) { Debug.Log("Navmesh data is null, can't export it."); } else { Debug.Log("Use local version of the navmesh data object."); data = localNavMesh; navmeshAssetPath = "navmeshes/" + localNavMesh.name; AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(localNavMesh)).SetAssetBundleNameAndVariant(navmeshAssetPath, ""); } } //create xml with navmeshlink and starting points GlobalLocation globalLocation = new GlobalLocation(); if (navmeshAssetPath.Length > 0 && data != null) { globalLocation.navmeshData = new NavmeshData() { link = navmeshAssetPath, name = data.name }; if (exportPlayerPositionsInLocations) { globalLocation.positions = new List <PositionData>(); WG_Position[] positions = WG_Helper.FindObjectsOfTypeAll <WG_Position>().ToArray();// FindObjectsOfType<WG_Position>(); for (int i = 0; i < positions.Length; i++) { Vector3 pos = positions[i].gameObject.transform.position; IntPair loc = WG_Helper.GetLocationCoordinates(pos, builderComponent.segmentSize); if (loc.u >= builderComponent.segmentsMinX && loc.u <= builderComponent.segmenstMaxX && loc.v >= builderComponent.segmentsMinY && loc.v <= builderComponent.segmenstMaxY) { globalLocation.positions.Add(new PositionData() { positionX = pos.x, positionY = pos.y, positionZ = pos.z }); } } if (globalLocation.positions.Count == 0) { Debug.Log("No start positions on the scene. Add default position (0, 0, 0)."); globalLocation.positions.Add(new PositionData() { positionX = 0.0f, positionY = 0.0f, positionZ = 0.0f }); } } globalLocation.bounds = new LocationsBounds() { minU = builderComponent.segmentsMinX, maxU = builderComponent.segmenstMaxX, minV = builderComponent.segmentsMinY, maxV = builderComponent.segmenstMaxY }; globalLocation.locationSize = new LocationSize() { value = builderComponent.segmentSize }; string globalLocationName = "global_location"; string globalLocationAssetPath = "Assets" + assetLocationXMLPath + globalLocationName + ".xml"; globalLocation.Save(globalLocationAssetPath); AssetDatabase.ImportAsset(globalLocationAssetPath, ImportAssetOptions.ForceUpdate); AssetImporter.GetAtPath(globalLocationAssetPath).SetAssetBundleNameAndVariant("locations/" + globalLocationName, ""); //export server data SavePlayerPositions(builderComponent); SaveCollisionMap(serverPath); SaveTowerPositions(builderComponent); //also export locations data to SO GlobalLocationDataSO globalSO = ScriptableObjectUtility.CreateAsset <GlobalLocationDataSO>("Assets" + assetLocationSOPath, globalLocationName); globalSO.minU = builderComponent.segmentsMinX; globalSO.maxU = builderComponent.segmenstMaxX; globalSO.minV = builderComponent.segmentsMinY; globalSO.maxV = builderComponent.segmenstMaxY; globalSO.size = builderComponent.segmentSize; globalSO.navmeshName = data.name; globalSO.navmeshLink = navmeshAssetPath; if (exportPlayerPositionsInLocations) { globalSO.startPositions = new List <Vector3>(); for (int pi = 0; pi < globalLocation.positions.Count; pi++) { globalSO.startPositions.Add(new Vector3(globalLocation.positions[pi].positionX, globalLocation.positions[pi].positionY, globalLocation.positions[pi].positionZ)); } } EditorUtility.SetDirty(globalSO); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); AssetImporter.GetAtPath("Assets" + assetLocationSOPath + globalLocationName + ".asset").SetAssetBundleNameAndVariant("locations_so/" + globalLocationName, ""); } #endif }
void CombineLocation(GameObject locationRoot) { #if UNITY_EDITOR //we should collect objects with the same material Dictionary <int, List <CombinerDataContainer> > materialMap = new Dictionary <int, List <CombinerDataContainer> >(); Dictionary <int, Material> materials = new Dictionary <int, Material>(); Transform[] allTransforms = locationRoot.transform.GetComponentsInChildren <Transform>(); for (int i = 0; i < allTransforms.Length; i++) { GameObject go = allTransforms[i].gameObject; WG_LocationController locController = go.GetComponent <WG_LocationController>(); if (locController == null) { //Debug.Log(allTransforms[i].gameObject.name); GameObject prefab = PrefabUtility.GetOutermostPrefabInstanceRoot(go); if (prefab != null && prefab == go) // ignore individual generated objects { //this object is prefab, so, dive to it subobjects //use this code only when we consider the root prefab object and ignore for all it subobjects GameObject source = PrefabUtility.GetCorrespondingObjectFromSource(prefab); Transform[] sourceSubtfms = source.transform.GetComponentsInChildren <Transform>(); Transform goTfm = go.transform; if (sourceSubtfms.Length == 1) { //prefab contains only one object (it builded by proBuilder) //use changed mesh filter of the original scene object MeshFilter mFilter = go.GetComponent <MeshFilter>(); MeshRenderer mRenderer = go.GetComponent <MeshRenderer>(); if (mFilter != null && mRenderer != null) { Material m = mRenderer.sharedMaterial; int mId = m.GetInstanceID(); if (materialMap.ContainsKey(mId)) { materialMap[mId].Add(new CombinerDataContainer() { go = go, worldMatrix = go.transform.localToWorldMatrix /*toCenterTfm = goTfm*/ }); } else { materialMap.Add(mId, new List <CombinerDataContainer>() { new CombinerDataContainer() { go = go, worldMatrix = go.transform.localToWorldMatrix /*toCenterTfm = goTfm */ } }); materials.Add(mId, m); } } } else {//for large prefab we use master prefab objects for (int j = 0; j < sourceSubtfms.Length; j++) { GameObject subObj = sourceSubtfms[j].gameObject; MeshFilter mFilter = subObj.GetComponent <MeshFilter>(); MeshRenderer mRenderer = subObj.GetComponent <MeshRenderer>(); if (mFilter != null && mRenderer != null && mFilter.sharedMesh != null) // ignore subobject, if the master prefab does not contains the mesh { //this object contains mesh Material m = mRenderer.sharedMaterial; int mId = m.GetInstanceID(); if (materialMap.ContainsKey(mId)) { materialMap[mId].Add(new CombinerDataContainer() { go = subObj, worldMatrix = go.transform.localToWorldMatrix * subObj.transform.localToWorldMatrix /*toCenterTfm = goTfm, localTfm = subObj.transform*/ }); } else { materialMap.Add(mId, new List <CombinerDataContainer>() { new CombinerDataContainer() { go = subObj, worldMatrix = go.transform.localToWorldMatrix * subObj.transform.localToWorldMatrix /*toCenterTfm = goTfm, localTfm = subObj.transform*/ } }); materials.Add(mId, m); } } } } //mark original objects and disable it go.AddComponent <WG_Tag_MasterPrefab>(); go.SetActive(false); } } } //builded material map Matrix4x4 rootMatrix = locationRoot.transform.worldToLocalMatrix; foreach (int mId in materialMap.Keys) { //Debug.Log(mId.ToString() + ": " + materials[mId].name); //we should create new mesh for all objects with this material List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); List <Vector2> uvs = new List <Vector2>(); List <Vector3> normals = new List <Vector3>(); List <Vector4> tangents = new List <Vector4>(); int indexShift = 0; for (int i = 0; i < materialMap[mId].Count; i++) { GameObject go = materialMap[mId][i].go; // here we should use transform relative to the master prefab (we should store it separatly) //Debug.Log("\tobject " + go.name); //Transform tfm = materialMap[mId][i].toCenterTfm; //Matrix4x4 globalMatrix = tfm.localToWorldMatrix; //Matrix4x4 = rootMatrix * globalMatrix; Matrix4x4 changeMatrix = rootMatrix * materialMap[mId][i].worldMatrix; //if(materialMap[mId][i].localTfm != null) //{ //changeMatrix = changeMatrix * materialMap[mId][i].localTfm.localToWorldMatrix; //} MeshFilter mFilter = go.GetComponent <MeshFilter>(); Mesh mesh = mFilter.sharedMesh; Vector3[] vs = mesh.vertices; for (int j = 0; j < vs.Length; j++) { vertices.Add(changeMatrix.MultiplyPoint(vs[j])); } //Debug.Log("\t\tvetices: " + vs.Length.ToString()); int[] trs = mesh.triangles; for (int j = 0; j < trs.Length; j++) { triangles.Add(trs[j] + indexShift); } Vector2[] mvs = mesh.uv; for (int j = 0; j < vs.Length; j++) { uvs.Add(mvs[j]); } Vector3[] nms = mesh.normals; for (int j = 0; j < nms.Length; j++) { normals.Add(changeMatrix.MultiplyVector(nms[j]).normalized); } Vector4[] tgs = mesh.tangents; for (int j = 0; j < tgs.Length; j++) { Vector4 t = changeMatrix.MultiplyVector(tgs[j]); t.w = tgs[j].w; tangents.Add(t); } //Debug.Log("\t\tnormals: " + nms.Length.ToString()); indexShift += vs.Length; } Mesh combinedMesh = new Mesh(); combinedMesh.vertices = vertices.ToArray(); combinedMesh.triangles = triangles.ToArray(); combinedMesh.uv = uvs.ToArray(); combinedMesh.normals = normals.ToArray(); combinedMesh.tangents = tangents.ToArray(); //Debug.Log("\tset vertices: " + vertices.Count.ToString() + ", normals: " + normals.Count.ToString()); Unwrapping.GenerateSecondaryUVSet(combinedMesh); //create game object GameObject combinedGO = new GameObject("combined_" + materials[mId].name) { isStatic = true }; MeshFilter cmf = combinedGO.AddComponent <MeshFilter>(); cmf.mesh = combinedMesh; combinedGO.transform.SetParent(locationRoot.transform, false); MeshRenderer cmr = combinedGO.AddComponent <MeshRenderer>(); cmr.material = materials[mId]; combinedGO.AddComponent <WG_Tag_CombineMesh>(); //StaticEditorFlags flags = StaticEditorFlags.NavigationStatic | StaticEditorFlags.ContributeGI; //GameObjectUtility.SetStaticEditorFlags(combinedGO, flags); } #endif }