Skip to content

Instantly share code, notes, and snippets.

@morpheus-solutions
Last active January 9, 2024 05:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morpheus-solutions/d648edeeac43e8ab1e84d3fae425fecd to your computer and use it in GitHub Desktop.
Save morpheus-solutions/d648edeeac43e8ab1e84d3fae425fecd to your computer and use it in GitHub Desktop.
Cloudmap for use on Terrains and using the Expanse Creative sky. Assign script under your terrain, create your particle system and assign to the script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CloudMap : MonoBehaviour
{
private Terrain m_terrain;
[Tooltip("The Global particle System for rain/snow on the terrain according to the cloud map")]
public ParticleSystem m_globalParticles;
[Tooltip("Lower values will emit from denser clouds")]
[Range(0, 1)]
public float m_visibilityThreshold = 0.5f;
[Tooltip("The higher the resolution, the more samples taken so will have an impact on performance ")]
public CloudMapResolution m_cloudMapResolution = CloudMapResolution._256;
int m_cloudMapSize;
[Tooltip("Height of the global particle system relative to the highest point on the terrain")]
public float m_globalParticlesHeight = 1000f;
[Tooltip("Cloudmap update in seconds. 0 means only sample will be taken on start")]
public float m_cloudMapUpdate = 5;
private List<float> m_visibility = new List<float>();
private List<float> m_density = new List<float>();
private float max_height;
// Start is called before the first frame update
void Start()
{
m_terrain = gameObject.GetComponent<Terrain>();
max_height = m_terrain.terrainData.size.y;
switch (m_cloudMapResolution)
{
case CloudMapResolution._64:
m_cloudMapSize = 64;
break;
case CloudMapResolution._128:
m_cloudMapSize = 128;
break;
case CloudMapResolution._256:
m_cloudMapSize = 256;
break;
case CloudMapResolution._512:
m_cloudMapSize = 512;
break;
}
if (m_globalParticles != null)
{
var shape = m_globalParticles.shape;
shape.enabled = true;
shape.scale = new Vector3(m_terrain.terrainData.size.x, m_terrain.terrainData.size.z, 1);
m_globalParticles.gameObject.transform.localScale = m_terrain.gameObject.transform.localScale;
m_globalParticles.gameObject.transform.position = new Vector3(m_terrain.gameObject.transform.position.x + (m_terrain.terrainData.size.x / 2), m_globalParticlesHeight + max_height, m_terrain.gameObject.transform.position.z + (m_terrain.terrainData.size.z / 2));
}
if (m_cloudMapUpdate > 0) InvokeRepeating("CreateRTDensity", 0.5f, m_cloudMapUpdate);
else Invoke("CreateRTDensity", 0.5f); //if update == 0, the cloudmap will only be generated once on start
}
public enum CloudMapResolution
{
_64, _128, _256, _512
}
//Brads visibility Query
public void CreateRTDensity()
{
var height = gameObject.transform.position.y;
int r = (int)m_terrain.terrainData.size.x / m_cloudMapSize;
for (int y = 0; y < m_cloudMapSize; y++)
{
for (int x = 0; x < m_cloudMapSize; x++)
{
Expanse.GameplayQueries.QueryInfo q;
q.startWS = new Vector3(x * r, height, y * r); // Visibility start point is the probe's position.
q.endWS = new Vector3(x * r, height + 10000, y * r); // Visibility query end point is the target's position.
q.density = 0; // Initialize to null result, to be safe.
q.visibility = 1; // Initialize to null result, to be safe.
// Dispatch it using the static GameplayQueries class.
Expanse.GameplayQueries.Dispatch(q, OnQueryCompletion);
}
}
Invoke("CreateTex", 0.2f);
}
void OnQueryCompletion(Expanse.GameplayQueries.QueryInfo q)
{
m_visibility.Add(q.visibility);
m_density.Add(q.density);//not used but no further impact on performance
}
//Texture is created by sampling the terrain size and taking readings at intervals set by the reloution.
//The higher the resolution, the more samples taken so will have an impact on performance
void CreateTex()
{
print(m_visibility.Count);
var c = 0;
Texture2D tex = new Texture2D(m_cloudMapSize, m_cloudMapSize);
for (int y = 0; y < tex.height; y++)
{
for (int x = 0; x < tex.width; x++)
{
if (m_visibility[x + c] > m_visibilityThreshold)
tex.SetPixel(x, y, Color.black);
else
tex.SetPixel(x, y, Color.white);
}
c = y * m_cloudMapSize;
}
tex.Apply();
//add cloudmap to Global particle system
if (m_globalParticles != null)
{
var partShape = m_globalParticles.shape;
partShape.texture = tex;
partShape.textureClipChannel = ParticleSystemShapeTextureChannel.Red;
partShape.textureClipThreshold = 0.9f;
m_globalParticles.gameObject.SetActive(true);
}
m_visibility.Clear();
m_density.Clear();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment