Files
2026-02-28 12:43:44 +08:00

838 lines
31 KiB
C#

//Copyright(c)2020 Procedural Worlds Pty Limited
using System;
using System.Collections.Generic;
using UnityEngine;
namespace GeNa.Core
{
/// <summary>
/// Spline Extension for creating Rivers along a Spline
/// </summary>
[Serializable]
[CreateAssetMenu(fileName = "Rivers", menuName = "Procedural Worlds/GeNa/Extensions/Rivers", order = 4)]
public class GeNaRiverExtension : GeNaSplineExtension
{
const string GENA_USER_DATA_PATH = "GeNa User Data/";
const string BAKED_UNSPLIT_RIVER_PARENT_NAME = "BakedUnsplit_RiverMeshes";
const string RIVER_MESHES_PARENT_NAME = "RiverMeshes";
[SerializeField] protected GeNaRiverProfile m_riverProfile;
[SerializeField] protected Material m_currentMaterial;
[SerializeField] protected float m_seaLevel = 25f;
[SerializeField] protected bool m_useGaiaSeaLevel = true;
[SerializeField] protected float m_startFlow = 0.2f;
[SerializeField] protected float m_vertexDistance = 3.0f;
[SerializeField] protected float m_bankOverstep = 1.0f;
[SerializeField] protected float m_splineSmoothing = 0.82f;
[SerializeField] protected float m_riverWidth = 20f;
[SerializeField] protected float m_capDistance = 15f;
[SerializeField] protected float m_endCapDistance = 0.0f;
[SerializeField] protected bool m_addCollider = false;
[SerializeField] protected bool m_shadowsCast = false;
[SerializeField] protected bool m_shadowsReceive = false;
[SerializeField] protected bool m_raycastTerrainOnly = true;
[SerializeField] protected bool m_useWorldspaceTextureWidth = false;
[SerializeField] protected float m_worldspaceWidth = 15.0f;
[SerializeField] protected string m_tag = "Untagged";
[SerializeField] protected int m_layer = -1;
[SerializeField] protected bool m_splitAtTerrains = true;
[SerializeField] protected bool m_autoUpdateOnTerrainChange = false;
[SerializeField] protected MeshRenderer m_meshRenderer;
[NonSerialized] protected RenderTexture m_currentRenderTexture = null;
[NonSerialized] protected GameObject m_riverMeshParent = null;
[NonSerialized] protected bool m_postProcess = true;
[SerializeField] protected List<GameObject> m_bakedMeshes = new List<GameObject>();
public GeNaRiverProfile RiverProfile
{
get => m_riverProfile;
set => m_riverProfile = value;
}
public bool UseGaiaSeaLevel
{
get => m_useGaiaSeaLevel;
set => m_useGaiaSeaLevel = value;
}
public float SeaLevel
{
get => m_seaLevel;
set => m_seaLevel = value;
}
public bool SyncToWeather
{
get => m_riverProfile.RiverParameters.m_syncToWeather;
set => m_riverProfile.RiverParameters.m_syncToWeather = value;
}
public float StartFlow
{
get => m_startFlow;
set => m_startFlow = Mathf.Clamp(value, 0.05f, Mathf.Infinity);
}
public float VertexDistance
{
get => m_vertexDistance;
set => m_vertexDistance = value;
}
public float BankOverstep
{
get => m_bankOverstep;
set => m_bankOverstep = Mathf.Clamp(value, 0.5f, 5.0f);
}
public float RiverWidth
{
get => m_riverWidth;
set => m_riverWidth = Mathf.Max(value, 0.5f);
}
public float CapDistance
{
get => m_capDistance;
set => m_capDistance = Mathf.Clamp(value, 0.1f, Mathf.Infinity);
}
public float EndCapDistance
{
get => m_endCapDistance;
set => m_endCapDistance = Mathf.Clamp(value, 0.0f, 5000.0f);
}
public bool AddCollider
{
get => m_addCollider;
set => m_addCollider = value;
}
public bool RaycastTerrainOnly
{
get => m_raycastTerrainOnly;
set => m_raycastTerrainOnly = value;
}
public bool ReceiveShadows
{
get => m_shadowsReceive;
set => m_shadowsReceive = value;
}
public bool CastShadows
{
get => m_shadowsCast;
set => m_shadowsCast = value;
}
private void OnEnable()
{
if (m_autoUpdateOnTerrainChange)
{
GeNaEvents.onTerrainChanged -= TerrainChanged;
GeNaEvents.onTerrainChanged += TerrainChanged;
}
}
public bool UpdateOnTerrainChange
{
get => m_autoUpdateOnTerrainChange;
set
{
if (m_autoUpdateOnTerrainChange != value)
{
if (value)
{
GeNaEvents.onTerrainChanged -= TerrainChanged;
GeNaEvents.onTerrainChanged += TerrainChanged;
}
else
{
GeNaEvents.onTerrainChanged -= TerrainChanged;
}
}
m_autoUpdateOnTerrainChange = value;
}
}
public string Tag
{
get => m_tag;
set => m_tag = value;
}
public int Layer
{
get => m_layer;
set => m_layer = value;
}
public bool SplitAtTerrains
{
get => m_splitAtTerrains;
set => m_splitAtTerrains = value;
}
public bool UseWorldspaceTextureWidth
{
get => m_useWorldspaceTextureWidth;
set => m_useWorldspaceTextureWidth = value;
}
public float WorldspaceWidthRepeat
{
get => m_worldspaceWidth;
set => m_worldspaceWidth = value;
}
public MeshRenderer MeshRenderer
{
get => m_meshRenderer;
set => m_meshRenderer = value;
}
public GameObject Parent
{
get => m_riverMeshParent;
set => m_riverMeshParent = value;
}
/// <summary>
/// GeNa Extension Methods
/// </summary>
#region GeNaSpline Extension Methods
protected override void OnAttach(GeNaSpline spline)
{
if (RiverProfile == null)
{
RiverProfile = GeNaUtility.LoadNewRiverProfile();
if (m_layer < 0)
{
m_layer = LayerMask.NameToLayer("PW_Object_Large");
if (m_layer < 0)
m_layer = 0;
}
}
if (m_autoUpdateOnTerrainChange)
{
GeNaEvents.onTerrainChanged -= TerrainChanged;
GeNaEvents.onTerrainChanged += TerrainChanged;
}
CreateRivers();
GameObjectEntity gameObjectEntity = ScriptableObject.CreateInstance<GameObjectEntity>();
gameObjectEntity.m_gameObject = m_riverMeshParent;
GeNaUndoRedo.RecordUndo(gameObjectEntity);
}
List<Transform> affectedTerrains = new List<Transform>();
private void TerrainChanged(Terrain terrain, TerrainChangedFlags flags)
{
if ((flags & TerrainChangedFlags.Heightmap) == TerrainChangedFlags.Heightmap || (flags & TerrainChangedFlags.FlushEverythingImmediately) == TerrainChangedFlags.FlushEverythingImmediately)
{
bool affected = false;
Transform terrainTransform = terrain.transform;
for (int i = 0; i < affectedTerrains.Count; i++)
{
if (affectedTerrains[i] == terrainTransform)
affected = true;
}
if (!affected)
return;
//Debug.Log($"Affected Terrain Changed ({Spline.Nodes.Count}).");
PreExecute();
Execute();
}
}
public void Bake(bool postProcess)
{
m_postProcess = postProcess;
Bake();
}
protected override GameObject OnBake(GeNaSpline spline)
{
if (m_postProcess)
{
PreExecute();
Execute();
}
else
{
CreateCurrentRenderTexture();
}
FindMeshesParent();
if (m_autoUpdateOnTerrainChange)
GeNaEvents.onTerrainChanged -= TerrainChanged;
if (m_bakedMeshes == null)
m_bakedMeshes = new List<GameObject>();
if (m_bakedMeshes.Count > 0)
{
for (int i = 0; i < m_bakedMeshes.Count; i++)
{
if (m_bakedMeshes[i] != null)
GeNaEvents.Destroy(m_bakedMeshes[i]);
}
}
m_bakedMeshes.Clear();
spline.IsDirty = true;
GameObject riverMeshes = GeNaEvents.BakeSpline(m_riverMeshParent, spline);
if (riverMeshes == null)
return null;
Dictionary<Transform, List<Transform>> meshParentDict = null;
if (m_postProcess && m_splitAtTerrains)
{
// PostProcess will split the meshes up into new meshes per terrain.
List<Transform> meshTransforms = GeNaRiverMesh.PostProcess(riverMeshes, BakedGroupName());
meshParentDict = ProcessRenderTargets(meshTransforms);
if (!GeNaEvents.HasTerrainsAsScenes())
{
foreach (Transform parentTransform in meshParentDict.Keys)
{
m_bakedMeshes.Add(parentTransform.gameObject);
}
}
}
else
{
GameObject bakedRivers = GameObject.Find(BAKED_UNSPLIT_RIVER_PARENT_NAME);
if (bakedRivers == null)
{
bakedRivers = new GameObject(BAKED_UNSPLIT_RIVER_PARENT_NAME);
}
riverMeshes.transform.parent = bakedRivers.transform;
riverMeshes.name = BakedGroupName();
List<Transform> meshTransforms = new List<Transform>();
Renderer[] renderers = riverMeshes.GetComponentsInChildren<Renderer>();
for (int i = 0; i < renderers.Length; i++)
meshTransforms.Add(renderers[i].transform);
meshParentDict = ProcessRenderTargets(meshTransforms);
if (m_postProcess)
{
foreach (Transform parentTransform in meshParentDict.Keys)
{
m_bakedMeshes.Add(parentTransform.gameObject);
}
}
}
return riverMeshes;
}
void FindMeshesParent()
{
if (m_riverMeshParent != null && m_riverMeshParent.transform.parent != Spline.transform)
m_riverMeshParent = null;
if (m_riverMeshParent == null)
{
Transform parent = Spline.gameObject.transform.Find(RIVER_MESHES_PARENT_NAME);
if (parent != null)
m_riverMeshParent = parent.gameObject;
}
}
Dictionary<Transform, List<Transform>> ProcessRenderTargets(List<Transform> meshTransforms)
{
Dictionary<Transform, List<Transform>> meshParentDict = new Dictionary<Transform, List<Transform>>();
if (meshTransforms.Count < 1)
return meshParentDict;
foreach (Transform meshXform in meshTransforms)
{
if (!meshParentDict.ContainsKey(meshXform.parent))
meshParentDict.Add(meshXform.parent, new List<Transform>());
meshParentDict[meshXform.parent].Add(meshXform);
}
// Get the Flow Render Target and Create a Texture2D from it,
// to be assigned to the River Material.
if (RiverProfile.RiverParameters.m_renderMode == Constants.ProfileRenderMode.RiverFlow)
{
Material material = meshTransforms[0].GetComponent<Renderer>().sharedMaterial;
if (m_currentMaterial != null)
material = m_currentMaterial;
// Create a Texture2D to replace the RenderTexture created in CaptureRiverFlow.
Texture tex = material.GetTexture("_FlowMap");
RenderTexture rtFlow = tex as RenderTexture;
if (rtFlow != null)
{
RenderTexture.active = rtFlow;
int size = rtFlow.width;
Texture2D tFlow = new Texture2D(size, size, TextureFormat.RGBA32, false, true);
tFlow.anisoLevel = 0;
tFlow.ReadPixels(new Rect(0, 0, size, size), 0, 0, false);
tFlow.Apply();
RenderTexture.active = null;
material.SetTexture("_FlowMap", tFlow);
foreach (List<Transform> meshes in meshParentDict.Values)
{
Material newMat = new Material(material);
newMat.SetTexture("_FlowMap", tFlow);
foreach (Transform transform in meshes)
{
transform.GetComponent<Renderer>().sharedMaterial = newMat;
}
}
}
}
return meshParentDict;
}
/// <summary>
/// Returns a dictionary of mesh transforms key'ed by their parent transform.
/// </summary>
/// <typeparam name="Transform"></typeparam>
/// <typeparam name="List"></typeparam>
/// <param name=""></param>
/// <param name=""></param>
/// <param name=""></param>
Dictionary<Transform, List<Transform>> ProcessRenderTargetsPerTerrain(List<Transform> meshTransforms)
{
Dictionary<Transform, List<Transform>> meshParentDict = new Dictionary<Transform, List<Transform>>();
foreach (Transform meshXform in meshTransforms)
{
if (!meshParentDict.ContainsKey(meshXform.parent))
meshParentDict.Add(meshXform.parent, new List<Transform>());
meshParentDict[meshXform.parent].Add(meshXform);
}
// If the current River Profile uses the RiverFlow shader, then
// we need to capture the flow texture for all of the meshes
// that are parented to the same terrain, with the same resolution
// texture for each.
if (RiverProfile.RiverParameters.m_renderMode == Constants.ProfileRenderMode.RiverFlow)
{
//Debug.Log($"Creating a Texture2D for each RenderTexture for {terrainMeshDict.Count} terrain rivers.");
GameObject oceanGO = GameObject.Find("Water Surface");
Transform oceanMeshTransform = null;
if (oceanGO != null)
oceanMeshTransform = oceanGO.transform;
foreach (List<Transform> meshXForms in meshParentDict.Values)
{
// Let's get the "Baked River Meshes" transform so that we capture the flow of all river meshes.
if (meshXForms[0].parent == null || meshXForms[0].parent.parent == null)
{
Debug.LogError("Missing River Mesh parent and/or grandparent.");
return meshParentDict;
}
Transform bakedRiverMeshes = meshXForms[0].parent.parent;
Terrain terrain = null;
if (bakedRiverMeshes != null && bakedRiverMeshes.parent != null)
terrain = bakedRiverMeshes.parent.GetComponent<Terrain>();
Material material = RiverProfile.ApplyProfile(SeaLevel, true, meshXForms[0].GetComponent<Renderer>().sharedMaterial);
foreach (Transform meshXForm in meshXForms)
{
meshXForm.GetComponent<Renderer>().sharedMaterial = material;
}
CaptureFlow captureFlow = new CaptureFlow();
CaptureFlow.RiverFlowResults results;
if (bakedRiverMeshes != null)
results = captureFlow.CaptureRiverFlow(bakedRiverMeshes, null, 4096, material, oceanMeshTransform, terrain);
else
results = captureFlow.CaptureRiverFlow(meshXForms, null, 4096, material, oceanMeshTransform, terrain);
material.SetVector("_BoundsMinimum", results.boundsCenter - results.boundsExtent);
material.SetVector("_BoundsMaximum", results.boundsCenter + results.boundsExtent);
material.SetVector("_Center", results.boundsCenter);
material.SetVector("_Extent", results.boundsExtent);
// Create a Texture2D to replace the RenderTexture created in CaptureRiverFlow.
RenderTexture.active = results.rtFlow;
int size = results.rtFlow.width;
Texture2D tFlow = new Texture2D(size, size, TextureFormat.RGBA32, false, true);
tFlow.anisoLevel = 0;
tFlow.ReadPixels(new Rect(0, 0, size, size), 0, 0, false);
tFlow.Apply();
RenderTexture.active = null;
// Now, set all material properties of the river meshes that depend on the new Flow Texture.
// NOTE: for now, these operations will be done over and over, for each River Spline on a terrain.
if (bakedRiverMeshes != null)
{
Renderer[] allRenderers = bakedRiverMeshes.GetComponentsInChildren<Renderer>(false);
foreach (Renderer renderer in allRenderers)
{
Material thisMaterial = renderer.sharedMaterial;
if (thisMaterial.shader == material.shader)
{
thisMaterial.SetVector("_BoundsMinimum", results.boundsCenter - results.boundsExtent);
thisMaterial.SetVector("_BoundsMaximum", results.boundsCenter + results.boundsExtent);
thisMaterial.SetVector("_Center", results.boundsCenter);
thisMaterial.SetVector("_Extent", results.boundsExtent);
thisMaterial.SetTexture("_FlowMap", tFlow);
}
}
}
}
}
return meshParentDict;
}
public override void Execute()
{
if (IsActive && Spline.Nodes.Count > 1)
{
ProcessSpline(Spline);
}
}
public override void PreExecute()
{
//DeleteRiverMeshGameobjects(Spline);
}
protected override void OnActivate()
{
if (Spline.Nodes.Count > 1)
ProcessSpline(Spline);
if (m_autoUpdateOnTerrainChange)
{
GeNaEvents.onTerrainChanged -= TerrainChanged;
GeNaEvents.onTerrainChanged += TerrainChanged;
}
}
protected override void OnDeactivate()
{
DeleteRiverMeshGameobjects(Spline);
if (m_autoUpdateOnTerrainChange)
GeNaEvents.onTerrainChanged -= TerrainChanged;
}
protected override void OnDelete()
{
DeleteRiverMeshGameobjects(Spline);
if (m_autoUpdateOnTerrainChange)
GeNaEvents.onTerrainChanged -= TerrainChanged;
if (m_riverMeshParent != null)
{
GeNaEvents.Destroy(m_riverMeshParent);
m_riverMeshParent = null;
}
}
protected override void OnDrawGizmosSelected()
{
if (Spline.Settings.Advanced.DebuggingEnabled == false)
return;
foreach (GeNaCurve curve in Spline.Curves)
{
DrawCurveInfo(curve);
}
}
private void DrawCurveInfo(GeNaCurve geNaCurve)
{
// Draw arrows showing which direction a curve is facing (from StartNode to EndNode).
Gizmos.color = Color.red;
GeNaSample geNaSample = geNaCurve.GetSample(0.45f);
DrawArrow(geNaSample.Location, geNaSample.Forward);
geNaSample = geNaCurve.GetSample(0.5f);
DrawArrow(geNaSample.Location, geNaSample.Forward);
geNaSample = geNaCurve.GetSample(0.55f);
DrawArrow(geNaSample.Location, geNaSample.Forward);
}
private void DrawArrow(Vector3 position, Vector3 direction)
{
direction.Normalize();
Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;
Ray ray = new Ray(position, (-direction + right) * 0.5f);
Gizmos.DrawRay(ray);
ray.direction = (-direction - right) * 0.5f;
Gizmos.DrawRay(ray);
}
#endregion End GeNa Extension Methods
private void DeleteRiverMeshGameobjects(GeNaSpline spline)
{
// Check to make sure they haven't move the road meshes in the hierarchy
if (m_riverMeshParent != null && m_riverMeshParent.transform.parent != Spline.transform)
m_riverMeshParent = null;
if (m_riverMeshParent == null)
{
Transform splineTransform = Spline.gameObject.transform;
// see if we can find it
Transform riverMeshesTransform = splineTransform.Find(RIVER_MESHES_PARENT_NAME);
if (riverMeshesTransform != null)
m_riverMeshParent = riverMeshesTransform.gameObject;
}
if (m_riverMeshParent != null)
{
List<Transform> children = new List<Transform>();
foreach (Transform transform in m_riverMeshParent.transform)
{
children.Add(transform);
}
for (int i = 0; i < children.Count; i++)
{
GeNaEvents.Destroy(children[i].gameObject);
}
}
}
private void ProcessSpline(GeNaSpline spline)
{
CreateRivers();
}
public void UpdateMaterial()
{
if (RiverProfile == null)
{
return;
}
// recompute the river meshes and assign new material.
ProcessSpline(this.Spline);
}
private string BakedGroupName()
{
return $"River Meshes ({this.Spline.GetInstanceID() % 9997})";
}
public bool HasBakedRivers()
{
return m_bakedMeshes != null && m_bakedMeshes.Count > 0;
/*
string groupName = BakedGroupName();
GameObject go = GameObject.Find(groupName);
if (go != null)
return true;
return false;
*/
}
public void DeleteBakedRiver(bool reenableSpline = false)
{
//string groupName = BakedGroupName();
//GameObject go = GameObject.Find(groupName);
if (m_bakedMeshes == null || m_bakedMeshes.Count < 1)
return;
int count = 0;
//while (go != null)
foreach (GameObject go in m_bakedMeshes)
{
if (go != null)
{
Transform parent = go.transform.parent;
GeNaEvents.Destroy(go);
count++;
if (parent != null && parent.childCount == 0 && (parent.name == "Baked_RiverMeshes" || parent.name == BAKED_UNSPLIT_RIVER_PARENT_NAME))
{
GeNaEvents.Destroy(parent.gameObject);
}
}
//go = GameObject.Find(groupName);
}
if (reenableSpline)
Spline.gameObject.SetActive(true);
m_bakedMeshes.Clear();
Spline.IsDirty = true;
if (count > 0)
Debug.Log($"{count} baked river mesh group(s) deleted.");
}
public void SetSplineToDownhill()
{
if (Spline == null)
return;
_SetSplineToDownhill();
}
private void _SetSplineToDownhill()
{
Dictionary<int, List<GeNaCurve>> trees = Spline.GetTrees();
foreach (List<GeNaCurve> curCurves in trees.Values)
{
(float min, float max) minMax = _GetCurvesMinMax(curCurves);
List<GeNaCurve> curves = new List<GeNaCurve>(curCurves);
if (minMax.min > minMax.max)
{
curves.Reverse();
(minMax.min, minMax.max) = (minMax.max, minMax.min);
}
float curHeight = minMax.max;
for (int i = 0; i < curves.Count; i++)
{
if (curves[i].EndNode.Position.y >= curHeight)
{
Vector3 pos = curves[i].EndNode.Position;
pos = new Vector3(pos.x, curHeight - 0.001f, pos.z);
curves[i].EndNode.Position = pos;
}
curHeight = curves[i].EndNode.Position.y;
}
}
Spline.Smooth();
}
private (float min, float max) _GetCurvesMinMax(List<GeNaCurve> curves)
{
return (curves[curves.Count - 1].P3.y, curves[0].P0.y);
}
private void CreateRivers()
{
if (Spline == null || Spline.Nodes.Count < 2)
return;
// See if we already have a material
Material material = null;
if (m_riverMeshParent != null)
{
Renderer child = m_riverMeshParent.GetComponentInChildren<Renderer>();
if (child != null)
{
material = child.sharedMaterial;
if (!material.HasProperty("_FlowMap"))
{
material = m_currentMaterial;
}
}
}
DeleteRiverMeshGameobjects(Spline);
if (m_riverMeshParent == null)
{
Transform splineTransform = Spline.gameObject.transform;
// see if we can find it
Transform riverMeshesTransform = splineTransform.Find(RIVER_MESHES_PARENT_NAME);
if (riverMeshesTransform != null)
m_riverMeshParent = riverMeshesTransform.gameObject;
if (m_riverMeshParent == null)
{
m_riverMeshParent = new GameObject(RIVER_MESHES_PARENT_NAME);
m_riverMeshParent.transform.position = Vector3.zero;
m_riverMeshParent.transform.parent = splineTransform;
}
}
if (RiverProfile != null)
{
if (GeNaUtility.Gaia2Present)
{
if (UseGaiaSeaLevel)
{
SeaLevel = GeNaEvents.GetSeaLevel(SeaLevel);
}
}
m_currentMaterial = RiverProfile.ApplyProfile(SeaLevel, true, material);
GeNaRiverMesh geNaRiverMesh = new GeNaRiverMesh(Spline, m_startFlow, m_vertexDistance, m_bankOverstep, m_currentMaterial, m_riverWidth, SyncToWeather, RiverProfile, m_shadowsCast, m_shadowsReceive);
if (m_autoUpdateOnTerrainChange)
geNaRiverMesh.m_affectedTerrains = affectedTerrains;
else
geNaRiverMesh.m_affectedTerrains = null;
geNaRiverMesh.CreateMeshes(m_riverMeshParent.transform, m_addCollider, m_raycastTerrainOnly, m_tag, m_layer, SeaLevel, CapDistance, UseWorldspaceTextureWidth, WorldspaceWidthRepeat, EndCapDistance);
RenderTexture newRTex = CaptureRiverFlowTexture();
if (m_currentRenderTexture != null && m_currentRenderTexture != newRTex)
{
GeNaEvents.Destroy(m_currentRenderTexture);
//Debug.Log("Render Texture for River Material destroyed.");
}
m_currentRenderTexture = newRTex;
}
}
void CreateCurrentRenderTexture()
{
FindMeshesParent();
RenderTexture newRTex = CaptureRiverFlowTexture();
if (m_currentRenderTexture != null && m_currentRenderTexture != newRTex)
{
GeNaEvents.Destroy(m_currentRenderTexture);
//Debug.Log("Render Texture for River Material destroyed.");
}
m_currentRenderTexture = newRTex;
}
public RenderTexture CaptureRiverFlowTexture(bool saveFlowTexture = false)
{
if (m_riverMeshParent == null)
return m_currentRenderTexture;
// Do we need to create a river flow texture?
GeNaRiverParameters riverParameters = RiverProfile.RiverParameters;
if (riverParameters != null)
{
if (riverParameters.m_renderMode == Constants.ProfileRenderMode.RiverFlow)
{
GameObject oceanGO = GameObject.Find("Water Surface");
Transform oceanMeshTransform = null;
if (oceanGO != null)
oceanMeshTransform = oceanGO.transform;
int textureSize = 1024;
string filename = string.Empty;
if (saveFlowTexture)
{
filename = System.IO.Path.Combine(Application.dataPath, GENA_USER_DATA_PATH, $"FlowMap_{Spline.GetInstanceID()}.png");
Debug.Log($"Flow Map filename = {filename}");
}
else
{
textureSize = 2048;
}
CaptureFlow captureFlow = new CaptureFlow();
CaptureFlow.RiverFlowResults results = captureFlow.CaptureRiverFlow(m_riverMeshParent.transform, filename, textureSize, m_currentMaterial, oceanMeshTransform);
m_currentMaterial.SetVector("_BoundsMinimum", results.boundsCenter - results.boundsExtent);
m_currentMaterial.SetVector("_BoundsMaximum", results.boundsCenter + results.boundsExtent);
m_currentMaterial.SetVector("_Center", results.boundsCenter);
m_currentMaterial.SetVector("_Extent", results.boundsExtent);
return results.rtFlow;
}
}
return null;
}
}
}