diff --git a/NewHorizons/Builder/Body/HeightMapBuilder.cs b/NewHorizons/Builder/Body/HeightMapBuilder.cs index 6c505c04..43f2d78b 100644 --- a/NewHorizons/Builder/Body/HeightMapBuilder.cs +++ b/NewHorizons/Builder/Body/HeightMapBuilder.cs @@ -1,5 +1,7 @@ using NewHorizons.Builder.Body.Geometry; +using NewHorizons.External.Configs; using NewHorizons.External.Modules; +using NewHorizons.Handlers; using NewHorizons.Utility; using OWML.Common; using System; @@ -11,7 +13,7 @@ namespace NewHorizons.Builder.Body { public static Shader PlanetShader; - public static void Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution) + public static void Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution, bool useLOD = false) { var deleteHeightmapFlag = false; @@ -51,24 +53,35 @@ namespace NewHorizons.Builder.Body GameObject cubeSphere = new GameObject("CubeSphere"); cubeSphere.SetActive(false); cubeSphere.transform.parent = sector?.transform ?? planetGO.transform; - cubeSphere.transform.rotation = Quaternion.Euler(90, 0, 0); - - Vector3 stretch = module.stretch != null ? (Vector3)module.stretch : Vector3.one; - Mesh mesh = CubeSphere.Build(resolution, heightMap, module.minHeight, module.maxHeight, stretch); - - cubeSphere.AddComponent(); - cubeSphere.GetComponent().mesh = mesh; if (PlanetShader == null) PlanetShader = Main.NHAssetBundle.LoadAsset("Assets/Shaders/SphereTextureWrapper.shader"); - var cubeSphereMR = cubeSphere.AddComponent(); - var material = new Material(PlanetShader); - cubeSphereMR.material = material; - material.name = textureMap.name; - material.mainTexture = textureMap; + Vector3 stretch = module.stretch != null ? (Vector3)module.stretch : Vector3.one; + + var level1 = MakeLODTerrain(cubeSphere, heightMap, textureMap, module.minHeight, module.maxHeight, resolution, stretch); var cubeSphereMC = cubeSphere.AddComponent(); - cubeSphereMC.sharedMesh = mesh; + cubeSphereMC.sharedMesh = level1.gameObject.GetComponent().mesh; + + if (useLOD) + { + var level2Res = (int)Mathf.Clamp(resolution / 2f, 35, 100); + var level2 = MakeLODTerrain(cubeSphere, heightMap, textureMap, module.minHeight, module.maxHeight, level2Res, stretch); + + var LODGroup = cubeSphere.AddComponent(); + LODGroup.size = module.maxHeight; + + LODGroup.SetLODs(new LOD[] + { + new LOD(1 / 3f, new Renderer[] { level1 }), + new LOD(0, new Renderer[] { level2 }) + }); + + level1.name += "0"; + level2.name += "1"; + + LODGroup.RecalculateBounds(); + } var cubeSphereSC = cubeSphere.AddComponent(); cubeSphereSC.radius = Mathf.Min(module.minHeight, module.maxHeight); @@ -86,5 +99,26 @@ namespace NewHorizons.Builder.Body // Now that we've made the mesh we can delete the heightmap texture if (deleteHeightmapFlag) ImageUtilities.DeleteTexture(mod, module.heightMap, heightMap); } + + public static MeshRenderer MakeLODTerrain(GameObject root, Texture2D heightMap, Texture2D textureMap, float minHeight, float maxHeight, int resolution, Vector3 stretch) + { + var LODCubeSphere = new GameObject("LODCubeSphere"); + + Mesh mesh = CubeSphere.Build(resolution, heightMap, minHeight, maxHeight, stretch); + + LODCubeSphere.AddComponent(); + LODCubeSphere.GetComponent().mesh = mesh; + + var cubeSphereMR = LODCubeSphere.AddComponent(); + var material = new Material(PlanetShader); + cubeSphereMR.material = material; + material.name = textureMap.name; + material.mainTexture = textureMap; + + LODCubeSphere.transform.parent = root.transform; + LODCubeSphere.transform.localPosition = Vector3.zero; + + return cubeSphereMR; + } } } diff --git a/NewHorizons/External/Modules/HeightMapModule.cs b/NewHorizons/External/Modules/HeightMapModule.cs index d2ef4371..945f65ed 100644 --- a/NewHorizons/External/Modules/HeightMapModule.cs +++ b/NewHorizons/External/Modules/HeightMapModule.cs @@ -33,7 +33,6 @@ namespace NewHorizons.External.Modules /// public string textureMap; - /* /// /// Resolution of the heightmap. /// Higher values means more detail but also more memory/cpu/gpu usage. @@ -42,6 +41,5 @@ namespace NewHorizons.External.Modules [Range(1 * 4, 500 * 4)] [DefaultValue(51 * 4)] public int resolution = 51 * 4; - */ } } \ No newline at end of file diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index 25e1e2e8..2bfb3532 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -466,13 +466,10 @@ namespace NewHorizons.Handlers if (body.Config.HeightMap != null) { - /* // resolution = tris on edge per face // divide by 4 to account for all the way around the equator var res = body.Config.HeightMap.resolution / 4; - HeightMapBuilder.Make(go, sector, body.Config.HeightMap, body.Mod, res); - */ - HeightMapBuilder.Make(go, sector, body.Config.HeightMap, body.Mod, 51); + HeightMapBuilder.Make(go, sector, body.Config.HeightMap, body.Mod, res, true); } if (body.Config.ProcGen != null) diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index f2b57706..b7e33836 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -710,6 +710,14 @@ "textureMap": { "type": "string", "description": "Relative filepath to the texture used for the terrain." + }, + "resolution": { + "type": "integer", + "description": "Resolution of the heightmap.\nHigher values means more detail but also more memory/cpu/gpu usage.\nThis value will be 1:1 with the heightmap texture width, but only at the equator.", + "format": "int32", + "default": 204, + "maximum": 2000.0, + "minimum": 4.0 } } }, diff --git a/NewHorizons/Utility/CoordinateUtilities.cs b/NewHorizons/Utility/CoordinateUtilities.cs index 6d5af6ca..530e9a83 100644 --- a/NewHorizons/Utility/CoordinateUtilities.cs +++ b/NewHorizons/Utility/CoordinateUtilities.cs @@ -25,9 +25,7 @@ namespace NewHorizons.Utility float dist = Mathf.Sqrt(x * x + y * y + z * z); // theta - float longitude = 180f; - if (x > 0) longitude = Mathf.Rad2Deg * Mathf.Atan(y / x); - if (x < 0) longitude = Mathf.Rad2Deg * (Mathf.Atan(y / x) + Mathf.PI); + var longitude = Mathf.Rad2Deg * Mathf.Atan2(y, x); // phi float latitude = (Mathf.Rad2Deg * Mathf.Acos(z / dist));