using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Cinemachine; using UniRx; using UnityEngine; using static Unity.Mathematics.math; using Unity.Mathematics; using Random = UnityEngine.Random; public class SectorRenderer : MonoBehaviour { public Transform FogCameraParent; public GameSettings Settings; public Transform SectorRoot; public Transform SectorBrushes; public MeshRenderer SectorBoundaryBrush; public MeshRenderer MinimapGravityQuad; public CinemachineVirtualCamera[] SceneCameras; public Camera[] FogCameras; public Camera[] MinimapCameras; public Material FogMaterial; public float FogFarFadeFraction = .125f; public float FarPlaneDistanceMultiplier = 2; public InstancedMesh[] AsteroidMeshes; // public Mesh[] AsteroidMeshes; // public Material AsteroidMaterial; [Header("Prefabs")] public PlanetObject Planet; public GasGiantObject GasGiant; public SunObject Sun; [Header("Icons")] public Texture2D PlanetoidIcon; public Texture2D PlanetIcon; private Dictionary _planets = new Dictionary(); private Dictionary _beltMeshes = new Dictionary(); private Zone _zone; private float _viewDistance; private float _maxDepth; public float Time { get; set; } public float ViewDistance { set { _viewDistance = value; foreach (var camera in FogCameras) camera.orthographicSize = value; foreach(var camera in SceneCameras) camera.m_Lens.FarClipPlane = value * FarPlaneDistanceMultiplier; FogMaterial.SetFloat("_DepthCeiling", value); FogMaterial.SetFloat("_DepthBlend", FogFarFadeFraction * value); } } public float MinimapDistance { set { foreach(var camera in MinimapCameras) camera.orthographicSize = value; MinimapGravityQuad.transform.localScale = value * 2 * Vector3.one; foreach (var planet in _planets.Values) planet.Icon.transform.localScale = Settings.IconSize / 256 * value * Vector3.one; } } void Start() { ViewDistance = Settings.DefaultViewDistance; MinimapDistance = Settings.MinimapZoomLevels[Settings.DefaultMinimapZoom]; } public void LoadZone(Zone zone) { _maxDepth = 0; _zone = zone; SectorBrushes.localScale = zone.Data.Radius * 2 * Vector3.one; ClearZone(); foreach(var p in zone.Planets.Values) LoadPlanet(p); } public void ClearZone() { if (_planets.Count > 0) { foreach (var planet in _planets.Values) { DestroyImmediate(planet.gameObject); } _planets.Clear(); _beltMeshes.Clear(); } } void LoadPlanet(BodyData planetData) { if (planetData is AsteroidBeltData beltData) { var meshes = AsteroidMeshes.ToList(); while(meshes.Count > Settings.AsteroidMeshCount) meshes.RemoveAt(Random.Range(0,meshes.Count)); _beltMeshes[planetData.ID] = meshes.ToArray(); } else { PlanetObject planet; if (planetData is GasGiantData gasGiantData) { if (planetData is SunData sunData) { planet = Instantiate(Sun, SectorRoot); var sun = (SunObject) planet; sunData.LightColor.Subscribe(c => sun.Light.color = c); sunData.Mass.Subscribe(m => sun.Light.range = Settings.PlanetSettings.LightRadius.Evaluate(m)); sunData.FogTintColor.Subscribe(c => sun.FogTint.material.SetColor("_Color", c)); sunData.Mass.Subscribe(m => sun.FogTint.transform.localScale = Settings.PlanetSettings.FogTintRadius.Evaluate(m) * Vector3.one); } else planet = Instantiate(GasGiant, SectorRoot); var gas = (GasGiantObject) planet; var gasGiant = _zone.PlanetInstances[planetData.ID] as GasGiant; gasGiantData.Colors.Subscribe(c => gas.Body.material.SetTexture("_ColorRamp", c.ToGradient(!(planetData is SunData)).ToTexture())); gasGiantData.AlbedoRotationSpeed.Subscribe(f => gas.SunMaterial.AlbedoRotationSpeed = f); gasGiantData.FirstOffsetRotationSpeed.Subscribe(f => gas.SunMaterial.FirstOffsetRotationSpeed = f); gasGiantData.SecondOffsetRotationSpeed.Subscribe(f => gas.SunMaterial.SecondOffsetRotationSpeed = f); gasGiantData.FirstOffsetDomainRotationSpeed.Subscribe(f => gas.SunMaterial.FirstOffsetDomainRotationSpeed = f); gasGiantData.SecondOffsetDomainRotationSpeed.Subscribe(f => gas.SunMaterial.SecondOffsetDomainRotationSpeed = f); gasGiant.GravityWavesRadius.Subscribe(f => gas.GravityWaves.transform.localScale = f * Vector3.one); gasGiant.GravityWavesDepth.Subscribe(f => gas.GravityWaves.material.SetFloat("_Depth", f)); planetData.Mass.Subscribe(f => gas.GravityWaves.material.SetFloat("_Frequency", Settings.PlanetSettings.WaveFrequency.Evaluate(f))); //gas.WaveScroll.Speed = Properties.GravitySettings.WaveSpeed.Evaluate(f); } else { planet = Instantiate(Planet, SectorRoot); //planet.Icon.material.mainTexture = planetData.Mass > Context.GlobalData.PlanetMass ? PlanetIcon : PlanetoidIcon; } var planetInstance = _zone.PlanetInstances[planetData.ID]; planetInstance.BodyRadius.Subscribe(f => planet.Body.transform.localScale = f * Vector3.one); planetInstance.GravityWellRadius.Subscribe(f => planet.GravityWell.transform.localScale = f * Vector3.one); planetInstance.GravityWellDepth.Subscribe(f => { if (f > _maxDepth) _maxDepth = f; planet.GravityWell.material.SetFloat("_Depth", f); }); _planets.Add(planetData.ID, planet); } } void LateUpdate() { foreach(var belt in _zone.AsteroidBelts) { var meshes = _beltMeshes[belt.Key]; for (int i = 0; i < meshes.Length; i++) { var matrices = belt.Value.Transforms .Skip((int) (((float)i / meshes.Length) * belt.Value.Transforms.Length)) .Take((int) (1f / meshes.Length * belt.Value.Transforms.Length)) .Select((v, x) => Matrix4x4.TRS( new Vector3(v.x, _zone.GetHeight(v.xy), v.y), Quaternion.Euler(cos(v.z + (float) i / meshes.Length) * 100, sin(v.z + (float) i / meshes.Length) * 100, (float)x/belt.Value.Transforms.Length * 360), Vector3.one * v.w)) .ToArray(); Graphics.DrawMeshInstanced(meshes[i].Mesh, 0, meshes[i].Material, matrices); } } foreach (var planet in _planets) { var planetInstance = _zone.PlanetInstances[planet.Key]; var p = _zone.GetOrbitPosition(planetInstance.BodyData.Orbit); planet.Value.transform.position = new Vector3(p.x, _zone.GetHeight(p) + planetInstance.BodyRadius.Value * 2, p.y); if(planet.Value is GasGiantObject gasGiantObject) { gasGiantObject.GravityWaves.material.SetFloat("_Phase", Time * Settings.PlanetSettings.WaveSpeed.Evaluate(planetInstance.BodyData.Mass.Value)); if(!(planet.Value is SunObject)) { var toParent = normalize(_zone.GetOrbitPosition(_zone.Orbits[planetInstance.BodyData.Orbit].Data.Parent) - p); gasGiantObject.SunMaterial.LightingDirection = new Vector3(toParent.x, 0, toParent.y); } } } var fogPos = FogCameraParent.position; SectorBoundaryBrush.material.SetFloat("_Power", Settings.PlanetSettings.ZoneDepthExponent); SectorBoundaryBrush.material.SetFloat("_Depth", Settings.PlanetSettings.ZoneDepth + Settings.PlanetSettings.ZoneBoundaryFog); var startDepth = Zone.PowerPulse(Settings.MinimapZoneGravityRange, Settings.PlanetSettings.ZoneDepthExponent) * Settings.PlanetSettings.ZoneDepth; var depthRange = Settings.PlanetSettings.ZoneDepth - startDepth + _maxDepth; MinimapGravityQuad.material.SetFloat("_StartDepth", startDepth); MinimapGravityQuad.material.SetFloat("_DepthRange", depthRange); FogMaterial.SetFloat("_GridOffset", Settings.PlanetSettings.ZoneBoundaryFog); FogMaterial.SetVector("_GridTransform", new Vector4(fogPos.x,fogPos.z,_viewDistance*2)); var gravPos = MinimapGravityQuad.transform.position; gravPos.y = -Settings.PlanetSettings.ZoneDepth - _maxDepth; MinimapGravityQuad.transform.position = gravPos; } } [Serializable] public class InstancedMesh { public Mesh Mesh; public Material Material; }