Rasagar/Library/PackageCache/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/FitToWaterSurfaceBurst.cs
2024-08-26 23:07:20 +03:00

174 lines
5.7 KiB
C#

using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteInEditMode]
public class FitToWaterSurfaceBurst : MonoBehaviour
{
// Public parameters
public int count = 50;
public WaterSurface waterSurface = null;
public bool includeDeformation = true;
public bool excludeSimulation = false;
public float currentSpeedMultiplier = 1.0f;
public GameObject prefab;
// List
List<GameObject> prefabList;
BoxCollider boxCollider;
// Input job parameters
NativeArray<float3> targetPositionBuffer;
// Output job parameters
NativeArray<float> errorBuffer;
NativeArray<float3> candidatePositionBuffer;
NativeArray<float3> projectedPositionWSBuffer;
NativeArray<float3> normalWSBuffer;
NativeArray<float3> directionBuffer;
NativeArray<int> stepCountBuffer;
// Start is called before the first frame update
void Start()
{
boxCollider = this.GetComponent<BoxCollider>();
Reset();
}
void Reset()
{
//Dispose buffer if already created
OnDestroy();
// Allocate the buffers
targetPositionBuffer = new NativeArray<float3>(count, Allocator.Persistent);
errorBuffer = new NativeArray<float>(count, Allocator.Persistent);
candidatePositionBuffer = new NativeArray<float3>(count, Allocator.Persistent);
projectedPositionWSBuffer = new NativeArray<float3>(count, Allocator.Persistent);
normalWSBuffer = new NativeArray<float3>(count, Allocator.Persistent);
stepCountBuffer = new NativeArray<int>(count, Allocator.Persistent);
directionBuffer = new NativeArray<float3>(count, Allocator.Persistent);
prefabList = new List<GameObject>();
prefabList.Clear();
// Need to do it like this to be able to delete child in edit mode;
for (int i = this.transform.childCount; i > 0; --i)
SmartDestroy(this.transform.GetChild(0).gameObject);
for (int x = 0; x < count; ++x)
{
GameObject instance = GameObject.Instantiate(prefab);
instance.transform.parent = this.transform;
instance.transform.localPosition = RandomPointInBounds(GetComponent<Collider>().bounds) - this.transform.position;
instance.transform.localEulerAngles = new Vector3(-180, UnityEngine.Random.Range(0,360), 0);
prefabList.Add(instance);
}
}
// Update is called once per frame
void Update()
{
if (waterSurface == null)
return;
if (!targetPositionBuffer.IsCreated)
Reset();
// Try to get the simulation data if available
WaterSimSearchData simData = new WaterSimSearchData();
if (!waterSurface.FillWaterSearchData(ref simData))
return;
// Fill the input positions
for (int i = 0; i < prefabList.Count; ++i)
{
targetPositionBuffer[i] = prefabList[i].transform.position;
}
// Prepare the first band
WaterSimulationSearchJob searchJob = new WaterSimulationSearchJob();
// Assign the simulation data
searchJob.simSearchData = simData;
// Fill the input data
searchJob.targetPositionWSBuffer = targetPositionBuffer;
searchJob.startPositionWSBuffer = targetPositionBuffer;
searchJob.maxIterations = 8;
searchJob.error = 0.01f;
searchJob.includeDeformation = includeDeformation;
searchJob.excludeSimulation = excludeSimulation;
searchJob.projectedPositionWSBuffer = projectedPositionWSBuffer;
searchJob.normalWSBuffer = normalWSBuffer;
searchJob.errorBuffer = errorBuffer;
searchJob.candidateLocationWSBuffer = candidatePositionBuffer;
searchJob.directionBuffer = directionBuffer;
searchJob.stepCountBuffer = stepCountBuffer;
// Schedule the job with one Execute per index in the results array and only 1 item per processing batch
JobHandle handle = searchJob.Schedule(count, 1);
handle.Complete();
// Fill the input positions
for (int i = 0; i < prefabList.Count; ++i)
{
float3 projectedPosition = projectedPositionWSBuffer[i];
prefabList[i].transform.position = projectedPosition + Time.deltaTime * directionBuffer[i] * currentSpeedMultiplier;
}
}
private Vector3 RandomPointInBounds(Bounds bounds) {
return new Vector3(
UnityEngine.Random.Range(bounds.min.x, bounds.max.x),
UnityEngine.Random.Range(bounds.min.y, bounds.max.y),
UnityEngine.Random.Range(bounds.min.z, bounds.max.z)
);
}
void OnDestroy()
{
if(targetPositionBuffer.IsCreated) targetPositionBuffer.Dispose();
if(errorBuffer.IsCreated) errorBuffer.Dispose();
if(candidatePositionBuffer.IsCreated) candidatePositionBuffer.Dispose();
if(projectedPositionWSBuffer.IsCreated) projectedPositionWSBuffer.Dispose();
if(normalWSBuffer.IsCreated) normalWSBuffer.Dispose();
if(stepCountBuffer.IsCreated) stepCountBuffer.Dispose();
if(directionBuffer.IsCreated) directionBuffer.Dispose();
}
void OnDisable()
{
OnDestroy();
}
public static void SmartDestroy(UnityEngine.Object obj)
{
if (obj == null)
{
return;
}
#if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
Destroy(obj);
}
else
{
DestroyImmediate(obj);
}
#else
Destroy(obj);
#endif
}
}