mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Triplanar Heightmap (#577)
## Major features - Heightmap overhaul!!!! - normal maps (bump maps) - smoothness (gloss) and metallic maps - tiling versions of texture/normal/smoothness/metallic maps for finer up-close detail - texture painting - use the red, green, blue, and alpha channels of a blend texture to determine where each set of tile textures goes. - you can also use black spots on the blend map to include a fifth "base" set of tile textures for where there's a lack of red/blue/blue/alpha. ## Minor features - ## Improvements - ## Bug fixes -
This commit is contained in:
commit
551b4a8ac1
Binary file not shown.
@ -1,9 +1,9 @@
|
||||
ManifestFileVersion: 0
|
||||
CRC: 1013046168
|
||||
CRC: 1613957014
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: 0123e044c220152b98ceaf0975b8cadd
|
||||
Hash: 9b2f376d4639a3fa789eadaf132f9889
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: 10a6a558690295dadb3dd990eda0821a
|
||||
@ -17,7 +17,7 @@ SerializeReferenceClassIdentifiers: []
|
||||
Assets:
|
||||
- Assets/Shaders/SphereTextureWrapper.shader
|
||||
- Assets/Shaders/Ring.shader
|
||||
- Assets/Shaders/SphereTextureWrapperNormal.shader
|
||||
- Assets/Shaders/SphereTextureWrapperTriplanar.shader
|
||||
- Assets/Shaders/UnlitRing1Pixel.shader
|
||||
- Assets/Shaders/UnlitTransparent.shader
|
||||
- Assets/Resources/TransparentCloud.mat
|
||||
|
||||
@ -124,8 +124,7 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
v.y = v2.y * Mathf.Sqrt(1f - x2 / 2f - z2 / 2f + x2 * z2 / 3f);
|
||||
v.z = v2.z * Mathf.Sqrt(1f - x2 / 2f - y2 / 2f + x2 * y2 / 3f);
|
||||
|
||||
// The shader uses real coords
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(v, false);
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(v, true);
|
||||
float longitude = sphericals.x;
|
||||
float latitude = sphericals.y;
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using NewHorizons.Builder.Body.Geometry;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.Files;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
@ -13,66 +12,42 @@ namespace NewHorizons.Builder.Body
|
||||
public static class HeightMapBuilder
|
||||
{
|
||||
public static Shader PlanetShader;
|
||||
private static readonly int EmissionMap = Shader.PropertyToID("_EmissionMap");
|
||||
private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");
|
||||
|
||||
// I hate nested functions okay
|
||||
private static IModBehaviour _currentMod;
|
||||
private static string _currentPlanetName;
|
||||
|
||||
public static GameObject Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution, bool useLOD = false)
|
||||
{
|
||||
var deleteHeightmapFlag = false;
|
||||
bool deleteHeightmapFlag;
|
||||
|
||||
Texture2D heightMap, textureMap, smoothnessMap, normalMap, emissionMap, tileBlendMap;
|
||||
|
||||
Tile baseTile, redTile, greenTile, blueTile, alphaTile;
|
||||
|
||||
_currentMod = mod;
|
||||
_currentPlanetName = planetGO.name;
|
||||
|
||||
Texture2D heightMap, textureMap, emissionMap;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(module.heightMap) && !File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, module.heightMap)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {planetGO.name} heightMap: {module.heightMap} couldn't be found.");
|
||||
module.heightMap = null;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(module.textureMap) && !File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, module.textureMap)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {planetGO.name} textureMap: {module.textureMap} couldn't be found.");
|
||||
module.textureMap = null;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(module.emissionMap) && !File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, module.emissionMap)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {planetGO.name} emissionMap: {module.emissionMap} couldn't be found.");
|
||||
module.emissionMap = null;
|
||||
}
|
||||
// tiles sample from this so we must wrap
|
||||
textureMap = Load(module.textureMap, "textureMap", true, false) ?? Texture2D.whiteTexture;
|
||||
smoothnessMap = Load(module.smoothnessMap, "smoothnessMap", false, false);
|
||||
normalMap = Load(module.normalMap, "normalMap", false, true);
|
||||
emissionMap = Load(module.emissionMap, "emissionMap", false, false);
|
||||
|
||||
if (string.IsNullOrEmpty(module.heightMap))
|
||||
{
|
||||
heightMap = Texture2D.whiteTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO we gotta get this working better
|
||||
// If we've loaded a new heightmap we'll delete the texture after
|
||||
// Only delete it if it wasnt loaded before (something else is using it)
|
||||
deleteHeightmapFlag = !ImageUtilities.IsTextureLoaded(mod, module.heightMap);
|
||||
heightMap = ImageUtilities.GetTexture(mod, module.heightMap);
|
||||
}
|
||||
tileBlendMap = useLOD ? Load(module.tileBlendMap, "tileBlendMap", false, false) : null;
|
||||
|
||||
if (string.IsNullOrEmpty(module.textureMap))
|
||||
{
|
||||
textureMap = Texture2D.whiteTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
textureMap = ImageUtilities.GetTexture(mod, module.textureMap);
|
||||
}
|
||||
baseTile = new Tile(useLOD ? module.baseTile : null, "BASE_TILE", "_BaseTile");
|
||||
redTile = new Tile(useLOD ? module.redTile : null, "RED_TILE", "_RedTile");
|
||||
greenTile = new Tile(useLOD ? module.greenTile : null, "GREEN_TILE", "_GreenTile");
|
||||
blueTile = new Tile(useLOD ? module.blueTile : null, "BLUE_TILE", "_BlueTile");
|
||||
alphaTile = new Tile(useLOD ? module.alphaTile : null, "ALPHA_TILE", "_AlphaTile");
|
||||
|
||||
if (string.IsNullOrEmpty(module.emissionMap))
|
||||
{
|
||||
emissionMap = Texture2D.blackTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
emissionMap = ImageUtilities.GetTexture(mod, module.emissionMap);
|
||||
}
|
||||
// Only delete heightmap if it hasn't been loaded yet
|
||||
deleteHeightmapFlag = !string.IsNullOrEmpty(module.heightMap) && !ImageUtilities.IsTextureLoaded(mod, module.heightMap);
|
||||
|
||||
// If the texturemap is the same as the heightmap don't delete it #176
|
||||
// Do the same with emissionmap
|
||||
if (textureMap == heightMap || emissionMap == heightMap) deleteHeightmapFlag = false;
|
||||
heightMap = Load(module.heightMap, "heightMap", false, false) ?? Texture2D.whiteTexture;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -80,18 +55,20 @@ namespace NewHorizons.Builder.Body
|
||||
return null;
|
||||
}
|
||||
|
||||
_currentMod = null;
|
||||
_currentPlanetName = null;
|
||||
|
||||
var cubeSphere = new GameObject("CubeSphere");
|
||||
cubeSphere.SetActive(false);
|
||||
cubeSphere.transform.parent = sector?.transform ?? planetGO.transform;
|
||||
cubeSphere.transform.SetParent(sector?.transform ?? planetGO.transform, false);
|
||||
|
||||
if (PlanetShader == null) PlanetShader = Main.NHAssetBundle.LoadAsset<Shader>("Assets/Shaders/SphereTextureWrapper.shader");
|
||||
if (PlanetShader == null) PlanetShader = Main.NHAssetBundle.LoadAsset<Shader>("Assets/Shaders/SphereTextureWrapperTriplanar.shader");
|
||||
|
||||
var stretch = module.stretch != null ? (Vector3)module.stretch : Vector3.one;
|
||||
|
||||
var emissionColor = module.emissionColor != null ? module.emissionColor.ToColor() : Color.white;
|
||||
var emissionColor = module.emissionColor?.ToColor() ?? Color.white;
|
||||
|
||||
var level1 = MakeLODTerrain(cubeSphere, heightMap, textureMap, module.minHeight, module.maxHeight, resolution, stretch,
|
||||
emissionMap, emissionColor);
|
||||
var level1 = MakeLODTerrain(resolution, useLOD);
|
||||
|
||||
var cubeSphereMC = cubeSphere.AddComponent<MeshCollider>();
|
||||
cubeSphereMC.sharedMesh = level1.gameObject.GetComponent<MeshFilter>().mesh;
|
||||
@ -99,8 +76,7 @@ namespace NewHorizons.Builder.Body
|
||||
if (useLOD)
|
||||
{
|
||||
var level2Res = (int)Mathf.Clamp(resolution / 2f, 1 /*cube moment*/, 100);
|
||||
var level2 = MakeLODTerrain(cubeSphere, heightMap, textureMap, module.minHeight, module.maxHeight, level2Res, stretch,
|
||||
emissionMap, emissionColor);
|
||||
var level2 = MakeLODTerrain(level2Res, false);
|
||||
|
||||
var LODGroup = cubeSphere.AddComponent<LODGroup>();
|
||||
LODGroup.size = module.maxHeight;
|
||||
@ -118,42 +94,107 @@ namespace NewHorizons.Builder.Body
|
||||
}
|
||||
|
||||
var cubeSphereSC = cubeSphere.AddComponent<SphereCollider>();
|
||||
cubeSphereSC.radius = Mathf.Min(module.minHeight, module.maxHeight);
|
||||
cubeSphereSC.radius = Mathf.Min(module.minHeight, module.maxHeight) * Mathf.Min(stretch.x, stretch.y, stretch.z);
|
||||
|
||||
var superGroup = planetGO.GetComponent<ProxyShadowCasterSuperGroup>();
|
||||
if (superGroup != null) cubeSphere.AddComponent<ProxyShadowCaster>()._superGroup = superGroup;
|
||||
|
||||
// Fix rotation in the end
|
||||
// 90 degree rotation around x is because cube sphere uses Z as up, Unity uses Y
|
||||
cubeSphere.transform.rotation = planetGO.transform.TransformRotation(Quaternion.Euler(90, 0, 0));
|
||||
cubeSphere.transform.position = planetGO.transform.position;
|
||||
|
||||
cubeSphere.SetActive(true);
|
||||
|
||||
// Now that we've made the mesh we can delete the heightmap texture
|
||||
if (deleteHeightmapFlag) ImageUtilities.DeleteTexture(mod, module.heightMap, heightMap);
|
||||
|
||||
return cubeSphere;
|
||||
|
||||
MeshRenderer MakeLODTerrain(int resolution, bool useTriplanar)
|
||||
{
|
||||
var LODCubeSphere = new GameObject("LODCubeSphere");
|
||||
LODCubeSphere.transform.SetParent(cubeSphere.transform, false);
|
||||
|
||||
LODCubeSphere.AddComponent<MeshFilter>().mesh = CubeSphere.Build(resolution, heightMap, module.minHeight, module.maxHeight, stretch);
|
||||
|
||||
var cubeSphereMR = LODCubeSphere.AddComponent<MeshRenderer>();
|
||||
var material = new Material(PlanetShader);
|
||||
cubeSphereMR.material = material;
|
||||
material.name = textureMap.name;
|
||||
|
||||
material.mainTexture = textureMap;
|
||||
material.SetFloat("_Smoothness", module.smoothness);
|
||||
material.SetFloat("_Metallic", module.metallic);
|
||||
material.SetTexture("_SmoothnessMap", smoothnessMap);
|
||||
material.SetFloat("_BumpStrength", module.normalStrength);
|
||||
material.SetTexture("_BumpMap", normalMap);
|
||||
material.SetColor("_EmissionColor", emissionColor);
|
||||
material.SetTexture("_EmissionMap", emissionMap);
|
||||
|
||||
if (useTriplanar)
|
||||
{
|
||||
material.SetTexture("_BlendMap", tileBlendMap);
|
||||
|
||||
baseTile.TryApplyTile(material);
|
||||
redTile.TryApplyTile(material);
|
||||
greenTile.TryApplyTile(material);
|
||||
blueTile.TryApplyTile(material);
|
||||
alphaTile.TryApplyTile(material);
|
||||
}
|
||||
|
||||
return cubeSphereMR;
|
||||
}
|
||||
}
|
||||
|
||||
private static MeshRenderer MakeLODTerrain(GameObject root, Texture2D heightMap, Texture2D textureMap, float minHeight, float maxHeight, int resolution, Vector3 stretch, Texture2D emissionMap, Color emissionColor)
|
||||
private static Texture2D Load(string path, string name, bool wrap, bool linear)
|
||||
{
|
||||
var LODCubeSphere = new GameObject("LODCubeSphere");
|
||||
if (string.IsNullOrEmpty(path)) return null;
|
||||
|
||||
LODCubeSphere.AddComponent<MeshFilter>().mesh = CubeSphere.Build(resolution, heightMap, minHeight, maxHeight, stretch);
|
||||
if (!File.Exists(Path.Combine(_currentMod.ModHelper.Manifest.ModFolderPath, path)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {_currentPlanetName} {name}: {path} couldn't be found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var cubeSphereMR = LODCubeSphere.AddComponent<MeshRenderer>();
|
||||
var material = new Material(PlanetShader);
|
||||
cubeSphereMR.material = material;
|
||||
material.name = textureMap.name;
|
||||
material.mainTexture = textureMap;
|
||||
material.SetTexture(EmissionMap, emissionMap);
|
||||
material.SetColor(EmissionColor, emissionColor);
|
||||
return ImageUtilities.GetTexture(_currentMod, path, wrap: wrap, linear: linear);
|
||||
}
|
||||
|
||||
LODCubeSphere.transform.parent = root.transform;
|
||||
LODCubeSphere.transform.localPosition = Vector3.zero;
|
||||
private readonly struct Tile
|
||||
{
|
||||
private readonly HeightMapModule.HeightMapTileInfo _info;
|
||||
private readonly string _keyword, _prefix;
|
||||
private readonly Texture2D _texture, _smoothness, _normal;
|
||||
|
||||
return cubeSphereMR;
|
||||
public Tile(HeightMapModule.HeightMapTileInfo info, string keyword, string prefix)
|
||||
{
|
||||
_info = info;
|
||||
|
||||
_keyword = keyword;
|
||||
_prefix = prefix;
|
||||
|
||||
if (_info != null)
|
||||
{
|
||||
_texture = Load(info.textureTile, $"{_prefix}TextureTile", true, false);
|
||||
_smoothness = Load(info.smoothnessTile, $"{_prefix}SmoothnessTile", true, false);
|
||||
_normal = Load(info.normalTile, $"{_prefix}NormalTile", true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Visual studio won't compile if you don't do this idk
|
||||
_texture = _smoothness = _normal = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void TryApplyTile(Material material)
|
||||
{
|
||||
if (_info != null)
|
||||
{
|
||||
material.SetFloat(_prefix, 1);
|
||||
material.EnableKeyword(_keyword);
|
||||
|
||||
material.SetFloat($"{_prefix}Scale", 1 / _info.size);
|
||||
material.SetTexture($"{_prefix}Albedo", _texture);
|
||||
material.SetTexture($"{_prefix}SmoothnessMap", _smoothness);
|
||||
material.SetFloat($"{_prefix}BumpStrength", _info.normalStrength);
|
||||
material.SetTexture($"{_prefix}BumpMap", _normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ using NewHorizons.External.Modules.Props;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.Files;
|
||||
using NewHorizons.Utility.Geometry;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -11,6 +10,7 @@ using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace NewHorizons.Builder.Props
|
||||
{
|
||||
public static class ScatterBuilder
|
||||
@ -23,6 +23,7 @@ namespace NewHorizons.Builder.Props
|
||||
private static void MakeScatter(GameObject go, ScatterInfo[] scatterInfo, float radius, Sector sector, IModBehaviour mod, PlanetConfig config)
|
||||
{
|
||||
var heightMap = config.HeightMap;
|
||||
var deleteHeightmapFlag = false;
|
||||
|
||||
var makeFibonacciSphere = scatterInfo.Any(x => x.preventOverlap);
|
||||
|
||||
@ -46,10 +47,8 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
if (!string.IsNullOrEmpty(heightMap.heightMap))
|
||||
{
|
||||
// TODO copy what heightmap builder does eventually
|
||||
deleteHeightmapFlag = !ImageUtilities.IsTextureLoaded(mod, heightMap.heightMap);
|
||||
heightMapTexture = ImageUtilities.GetTexture(mod, heightMap.heightMap);
|
||||
// defer remove texture to next frame
|
||||
Delay.FireOnNextUpdate(() => Object.Destroy(heightMapTexture));
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
@ -63,7 +62,7 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
Random.InitState(propInfo.seed);
|
||||
|
||||
// By default don't put underwater more than a mater
|
||||
// By default don't put underwater more than a meter
|
||||
// this is a backward compat thing lol
|
||||
if (config.Water != null && propInfo.minHeight == null) propInfo.minHeight = config.Water.size - 1f;
|
||||
|
||||
@ -98,7 +97,7 @@ namespace NewHorizons.Builder.Props
|
||||
var height = radius;
|
||||
if (heightMapTexture != null)
|
||||
{
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(point, false);
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(point, true);
|
||||
float longitude = sphericals.x;
|
||||
float latitude = sphericals.y;
|
||||
|
||||
@ -119,9 +118,6 @@ namespace NewHorizons.Builder.Props
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Because heightmaps are dumb gotta rotate it 90 degrees around the x axis bc UHHHHHHHHHHHHH
|
||||
point = Quaternion.Euler(90, 0, 0) * point;
|
||||
}
|
||||
|
||||
var prop = scatterPrefab.InstantiateInactive();
|
||||
@ -140,6 +136,11 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
|
||||
Object.Destroy(scatterPrefab);
|
||||
|
||||
if (deleteHeightmapFlag && heightMapTexture != null)
|
||||
{
|
||||
ImageUtilities.DeleteTexture(mod, heightMap.heightMap, heightMapTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,8 +39,10 @@ namespace NewHorizons.Components.SizeControllers
|
||||
|
||||
private void UpdateTargetPositions()
|
||||
{
|
||||
var toPrimary = (_body.transform.position - _dustTargetBody.transform.position).normalized;
|
||||
var velocityDirection = (_primaryBody?.GetVelocity() ?? Vector3.zero) -_body.GetVelocity(); // Accept that this is flipped ok
|
||||
// body is null for proxies
|
||||
// TODO: this will make proxy tails face the real body rather than proxy body (ie wrong). fix properly in a different PR
|
||||
var toPrimary = ((_body ? _body.transform : transform).position - _dustTargetBody.transform.position).normalized;
|
||||
var velocityDirection = (_primaryBody?.GetVelocity() ?? Vector3.zero) - (_body ? _body.GetVelocity() : Vector3.zero); // Accept that this is flipped ok
|
||||
|
||||
var tangentVel = Vector3.ProjectOnPlane(velocityDirection, toPrimary) / velocityDirection.magnitude;
|
||||
|
||||
|
||||
117
NewHorizons/External/Modules/HeightMapModule.cs
vendored
117
NewHorizons/External/Modules/HeightMapModule.cs
vendored
@ -28,11 +28,6 @@ namespace NewHorizons.External.Modules
|
||||
/// </summary>
|
||||
public MVector3 stretch;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the terrain.
|
||||
/// </summary>
|
||||
public string textureMap;
|
||||
|
||||
/// <summary>
|
||||
/// Resolution of the heightmap.
|
||||
/// Higher values means more detail but also more memory/cpu/gpu usage.
|
||||
@ -42,6 +37,44 @@ namespace NewHorizons.External.Modules
|
||||
[DefaultValue(51 * 4)]
|
||||
public int resolution = 51 * 4;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the terrain colors.
|
||||
/// </summary>
|
||||
public string textureMap;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the terrain's smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.
|
||||
/// Typically black with variable transparency, when metallic isn't wanted.
|
||||
/// </summary>
|
||||
public string smoothnessMap;
|
||||
|
||||
/// <summary>
|
||||
/// How "glossy" the surface is, where 0 is diffuse, and 1 is like a mirror.
|
||||
/// Multiplies with the alpha of the smoothness map if using one.
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
[DefaultValue(0f)]
|
||||
public float smoothness = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// How metallic the surface is, from 0 to 1.
|
||||
/// Multiplies with the red of the smoothness map if using one.
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
[DefaultValue(0f)]
|
||||
public float metallic = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the normal (aka bump) map. Optional.
|
||||
/// </summary>
|
||||
public string normalMap;
|
||||
|
||||
/// <summary>
|
||||
/// Strength of the normal map. Usually 0-1, but can go above, or negative to invert the map.
|
||||
/// </summary>
|
||||
[DefaultValue(1f)]
|
||||
public float normalStrength = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for emission. Optional.
|
||||
/// </summary>
|
||||
@ -51,5 +84,79 @@ namespace NewHorizons.External.Modules
|
||||
/// Color multiplier of the emission texture. Defaults to white.
|
||||
/// </summary>
|
||||
public MColor emissionColor;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for blending up to 5 tiles together, using the red, green, blue, and alpha channels, plus a lack of all 4 for a fifth "base" tile.
|
||||
/// Optional, even if using tiles (defaults to white, therefore either base or all other channels will be active).
|
||||
/// </summary>
|
||||
public string tileBlendMap;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. This tile will appear when all other tile channels are absent in the blend map, or when no other tiles are defined.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main textures control the general appearance, and make the tiles handle up close details.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo baseTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by red channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo redTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by green channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo greenTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by blue channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo blueTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by alpha channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo alphaTile;
|
||||
|
||||
[JsonObject]
|
||||
public class HeightMapTileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The size, in meters, of each tile.
|
||||
/// </summary>
|
||||
[Range(0f, double.MaxValue)]
|
||||
[DefaultValue(1f)]
|
||||
public float size = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to a color texture. Optional.
|
||||
/// Note that this tile texture will be multiplied with the main texture map. This means that white will multiply by 2, black by 0, and grey by 1.
|
||||
/// Thus, a texture that stays near (128, 128, 128) will blend nicely with the main texture map below.
|
||||
/// Colors other than greyscale can be used, but they might multiply strangely.
|
||||
/// </summary>
|
||||
public string textureTile;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to a texture for smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.
|
||||
/// Note that this tile texture will be multiplied with the main smoothness map and/or values. This means that black/red will multiply by 2, transparent by 0, and half transparent by 1.
|
||||
/// Thus, a texture that stays near half alpha/red will blend nicely with the main smoothness map below.
|
||||
/// </summary>
|
||||
public string smoothnessTile;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to a normal (aka bump) texture. Optional.
|
||||
/// Blends additively with the main normal map.
|
||||
/// </summary>
|
||||
public string normalTile;
|
||||
|
||||
/// <summary>
|
||||
/// Strength of the tile normal. Usually 0-1, but can go above, or negative to invert the map.
|
||||
/// </summary>
|
||||
[DefaultValue(1f)]
|
||||
public float normalStrength = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,8 +196,19 @@ namespace NewHorizons
|
||||
GlobalMessenger<DeathType>.AddListener("PlayerDeath", OnDeath);
|
||||
|
||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||
|
||||
NHAssetBundle = ModHelper.Assets.LoadBundle("Assets/newhorizons_public");
|
||||
if (NHAssetBundle == null)
|
||||
{
|
||||
NHLogger.LogError("Couldn't find NHAssetBundle: The mod will likely not work.");
|
||||
}
|
||||
|
||||
NHPrivateAssetBundle = ModHelper.Assets.LoadBundle("Assets/newhorizons_private");
|
||||
if (NHPrivateAssetBundle == null)
|
||||
{
|
||||
NHLogger.LogError("Couldn't find NHPrivateAssetBundle: The mod will likely not work.");
|
||||
}
|
||||
|
||||
VesselWarpHandler.Initialize();
|
||||
|
||||
ResetConfigs(resetTranslation: false);
|
||||
@ -353,7 +364,14 @@ namespace NewHorizons
|
||||
|
||||
if (isTitleScreen && _useCustomTitleScreen)
|
||||
{
|
||||
TitleSceneHandler.DisplayBodyOnTitleScreen(BodyDict.Values.ToList().SelectMany(x => x).ToList());
|
||||
try
|
||||
{
|
||||
TitleSceneHandler.DisplayBodyOnTitleScreen(BodyDict.Values.ToList().SelectMany(x => x).ToList());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NHLogger.LogError($"Failed to make title screen bodies: {e}");
|
||||
}
|
||||
TitleSceneHandler.InitSubtitles();
|
||||
}
|
||||
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NewHorizons.Patches.ToolPatches
|
||||
{
|
||||
[HarmonyPatch(typeof(SurveyorProbe))]
|
||||
public static class SurveyorProbePatches
|
||||
{
|
||||
// This is to stop the game throwing too many errors if the probe is destroyed by a blackhole
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(SurveyorProbe.IsLaunched))]
|
||||
public static bool SurveyorProbe_IsLaunched(SurveyorProbe __instance, out bool __result)
|
||||
{
|
||||
__result = __instance?.gameObject?.activeSelf ?? false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -841,10 +841,6 @@
|
||||
"description": "The scale of the terrain.",
|
||||
"$ref": "#/definitions/MVector3"
|
||||
},
|
||||
"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.",
|
||||
@ -853,6 +849,40 @@
|
||||
"maximum": 2000.0,
|
||||
"minimum": 4.0
|
||||
},
|
||||
"textureMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the terrain colors."
|
||||
},
|
||||
"smoothnessMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the terrain's smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.\nTypically black with variable transparency, when metallic isn't wanted."
|
||||
},
|
||||
"smoothness": {
|
||||
"type": "number",
|
||||
"description": "How \"glossy\" the surface is, where 0 is diffuse, and 1 is like a mirror.\nMultiplies with the alpha of the smoothness map if using one.",
|
||||
"format": "float",
|
||||
"default": 0.0,
|
||||
"maximum": 1.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"metallic": {
|
||||
"type": "number",
|
||||
"description": "How metallic the surface is, from 0 to 1.\nMultiplies with the red of the smoothness map if using one.",
|
||||
"format": "float",
|
||||
"default": 0.0,
|
||||
"maximum": 1.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"normalMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the normal (aka bump) map. Optional."
|
||||
},
|
||||
"normalStrength": {
|
||||
"type": "number",
|
||||
"description": "Strength of the normal map. Usually 0-1, but can go above, or negative to invert the map.",
|
||||
"format": "float",
|
||||
"default": 1.0
|
||||
},
|
||||
"emissionMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for emission. Optional."
|
||||
@ -860,6 +890,61 @@
|
||||
"emissionColor": {
|
||||
"description": "Color multiplier of the emission texture. Defaults to white.",
|
||||
"$ref": "#/definitions/MColor"
|
||||
},
|
||||
"tileBlendMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for blending up to 5 tiles together, using the red, green, blue, and alpha channels, plus a lack of all 4 for a fifth \"base\" tile.\nOptional, even if using tiles (defaults to white, therefore either base or all other channels will be active)."
|
||||
},
|
||||
"baseTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. This tile will appear when all other tile channels are absent in the blend map, or when no other tiles are defined.\nNote that tiles will not be active from afar, so it is recommended to make the main textures control the general appearance, and make the tiles handle up close details.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"redTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by red channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"greenTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by green channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"blueTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by blue channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"alphaTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by alpha channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HeightMapTileInfo": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"size": {
|
||||
"type": "number",
|
||||
"description": "The size, in meters, of each tile.",
|
||||
"format": "float",
|
||||
"default": 1.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"textureTile": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to a color texture. Optional.\nNote that this tile texture will be multiplied with the main texture map. This means that white will multiply by 2, black by 0, and grey by 1.\nThus, a texture that stays near (128, 128, 128) will blend nicely with the main texture map below.\nColors other than greyscale can be used, but they might multiply strangely."
|
||||
},
|
||||
"smoothnessTile": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to a texture for smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.\nNote that this tile texture will be multiplied with the main smoothness map and/or values. This means that black/red will multiply by 2, transparent by 0, and half transparent by 1.\nThus, a texture that stays near half alpha/red will blend nicely with the main smoothness map below."
|
||||
},
|
||||
"normalTile": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to a normal (aka bump) texture. Optional.\nBlends additively with the main normal map."
|
||||
},
|
||||
"normalStrength": {
|
||||
"type": "number",
|
||||
"description": "Strength of the tile normal. Usually 0-1, but can go above, or negative to invert the map.",
|
||||
"format": "float",
|
||||
"default": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -28,7 +28,8 @@ namespace NewHorizons.Utility.Files
|
||||
return _loadedTextures.ContainsKey(path);
|
||||
}
|
||||
|
||||
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps = true, bool wrap = false)
|
||||
// bug: cache only considers file path, not wrap/mips/linear. oh well
|
||||
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps = true, bool wrap = false, bool linear = false)
|
||||
{
|
||||
// Copied from OWML but without the print statement lol
|
||||
var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename);
|
||||
@ -42,7 +43,7 @@ namespace NewHorizons.Utility.Files
|
||||
try
|
||||
{
|
||||
var data = File.ReadAllBytes(path);
|
||||
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, useMipmaps);
|
||||
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, useMipmaps, linear);
|
||||
texture.name = Path.GetFileNameWithoutExtension(path);
|
||||
texture.wrapMode = wrap ? TextureWrapMode.Repeat : TextureWrapMode.Clamp;
|
||||
texture.LoadImage(data);
|
||||
|
||||
@ -5,22 +5,23 @@ namespace NewHorizons.Utility.Geometry
|
||||
{
|
||||
// Longitude and latitude are in degrees
|
||||
// Using the phi and theta convention used on https://mathworld.wolfram.com/SphericalCoordinates.html (Mathematics not physics convention)
|
||||
public static Vector3 CartesianToSpherical(Vector3 v, bool useUnityCoords = true)
|
||||
public static Vector3 CartesianToSpherical(Vector3 v, bool useShaderCoords = false)
|
||||
{
|
||||
float x, y, z;
|
||||
if (useUnityCoords)
|
||||
if (useShaderCoords)
|
||||
{
|
||||
// Y is DOWN in the shader
|
||||
x = v.x;
|
||||
y = v.z;
|
||||
z = -v.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Y is up in unity
|
||||
x = v.x;
|
||||
y = v.z;
|
||||
z = v.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
float dist = Mathf.Sqrt(x * x + y * y + z * z);
|
||||
|
||||
@ -33,7 +34,7 @@ namespace NewHorizons.Utility.Geometry
|
||||
return new Vector3(longitude, latitude, dist);
|
||||
}
|
||||
|
||||
public static Vector3 SphericalToCartesian(Vector3 v, bool useUnityCoords = true)
|
||||
public static Vector3 SphericalToCartesian(Vector3 v)
|
||||
{
|
||||
var longitude = v.x;
|
||||
var latitude = v.y;
|
||||
@ -44,18 +45,9 @@ namespace NewHorizons.Utility.Geometry
|
||||
|
||||
float x, y, z;
|
||||
|
||||
if (useUnityCoords)
|
||||
{
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Cos(phi);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Cos(phi);
|
||||
}
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Cos(phi);
|
||||
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book",
|
||||
"name": "New Horizons",
|
||||
"uniqueName": "xen.NewHorizons",
|
||||
"version": "1.10.2",
|
||||
"version": "1.11.0",
|
||||
"owmlVersion": "2.9.0",
|
||||
"dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ],
|
||||
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user