_xiaofang/xiaofang/Assets/Obi/Scripts/Common/Collisions/ObiHeightFieldContainer.cs
杨号敬 bcc74f0465 add
2024-12-18 02:18:45 +08:00

115 lines
3.7 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace Obi
{
public class ObiHeightFieldHandle : ObiResourceHandle<TerrainData>
{
public ObiHeightFieldHandle(TerrainData data, int index = -1) : base(index) { owner = data; }
}
public struct HeightFieldHeader //we need to use the header in the backend, so it must be a struct.
{
public int firstSample;
public int sampleCount;
public HeightFieldHeader(int firstSample, int sampleCount)
{
this.firstSample = firstSample;
this.sampleCount = sampleCount;
}
}
public class ObiHeightFieldContainer
{
public Dictionary<TerrainData, ObiHeightFieldHandle> handles; /**< dictionary indexed by asset, so that we don't generate data for the same distance field multiple times.*/
public ObiNativeHeightFieldHeaderList headers; /**< One header per distance field.*/
public ObiNativeFloatList samples;
public ObiHeightFieldContainer()
{
handles = new Dictionary<TerrainData, ObiHeightFieldHandle>();
headers = new ObiNativeHeightFieldHeaderList();
samples = new ObiNativeFloatList();
}
public ObiHeightFieldHandle GetOrCreateHeightField(TerrainData source)
{
ObiHeightFieldHandle handle;
if (!handles.TryGetValue(source, out handle))
{
// Get the heighfield into a 1d array:
int width = source.heightmapResolution;
int height = source.heightmapResolution;
float[,] heights = source.GetHeights(0, 0, width, height);
bool[,] holes = source.GetHoles(0, 0, width-1, height-1);
float[] buffer = new float[width * height];
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
buffer[y * width + x] = heights[y, x] * (holes[Mathf.Min(y,height - 2), Mathf.Min(x, width - 2)] ? 1:-1);
handle = new ObiHeightFieldHandle(source, headers.count);
handles.Add(source, handle);
headers.Add(new HeightFieldHeader(samples.count, buffer.Length));
samples.AddRange(buffer);
}
return handle;
}
public void DestroyHeightField(ObiHeightFieldHandle handle)
{
if (handle != null && handle.isValid && handle.index < handles.Count)
{
var header = headers[handle.index];
// Update headers:
for (int i = 0; i < headers.count; ++i)
{
var h = headers[i];
if (h.firstSample > header.firstSample)
{
h.firstSample -= header.sampleCount;
headers[i] = h;
}
}
// update handles:
foreach (var pair in handles)
{
if (pair.Value.index > handle.index)
pair.Value.index--;
}
// Remove nodes
samples.RemoveRange(header.firstSample, header.sampleCount);
// remove header:
headers.RemoveAt(handle.index);
// remove the heightfield from the dictionary:
handles.Remove(handle.owner);
// Invalidate our handle:
handle.Invalidate();
}
}
public void Dispose()
{
if (headers != null)
headers.Dispose();
if (samples != null)
samples.Dispose();
}
}
}