You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
3.5 KiB

// DFVolume - Distance field volume generator for Unity
// https://github.com/keijiro/DFVolume
using UnityEngine;
namespace DFVolume
{
public class VolumeSampler : MonoBehaviour
{
#region Exposed attributes
[SerializeField] int _resolution = 50;
public int resolution {
get { return _resolution; }
}
[SerializeField] float _extent = 0.5f;
public float extent {
get { return _extent; }
}
#endregion
#if UNITY_EDITOR
#region Editor functions
void OnDrawGizmos()
{
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube(Vector3.zero, Vector3.one * _extent * 2);
}
public Color[] GenerateBitmap()
{
// Generate a distance field.
var df = new float[_resolution * _resolution * _resolution];
for (var xi = 0; xi < _resolution; xi++)
{
var x = 2.0f * xi / (_resolution - 1) - 1;
for (var yi = 0; yi < _resolution; yi++)
{
var y = 2.0f * yi / (_resolution - 1) - 1;
for (var zi = 0; zi < _resolution; zi++)
{
var z = 2.0f * zi / (_resolution - 1) - 1;
var pt = new Vector3(x, y, z) * _extent;
pt = transform.TransformPoint(pt);
var dist = SearchDistance(pt) * 0.5f / _extent;
df[GetIndex(xi, yi, zi)] = dist;
}
}
}
// Compute gradients and pack them into a bitmap.
var bmp = new Color[df.Length];
var dds2 = (_resolution - 1) / 2.0f;
for (var xi = 0; xi < _resolution; xi++)
{
for (var yi = 0; yi < _resolution; yi++)
{
for (var zi = 0; zi < _resolution; zi++)
{
var d = df[GetIndex(xi, yi, zi)];
var dx0 = df[GetIndex(xi - 1, yi, zi)];
var dx1 = df[GetIndex(xi + 1, yi, zi)];
var dy0 = df[GetIndex(xi, yi - 1, zi)];
var dy1 = df[GetIndex(xi, yi + 1, zi)];
var dz0 = df[GetIndex(xi, yi, zi - 1)];
var dz1 = df[GetIndex(xi, yi, zi + 1)];
bmp[GetIndex(xi, yi, zi)] = new Color(
(dx1 - dx0) * dds2,
(dy1 - dy0) * dds2,
(dz1 - dz0) * dds2,
d
);
}
}
}
return bmp;
}
#endregion
#region Private functions
int GetIndex(int xi, int yi, int zi)
{
xi = Mathf.Clamp(xi, 0, _resolution - 1);
yi = Mathf.Clamp(yi, 0, _resolution - 1);
zi = Mathf.Clamp(zi, 0, _resolution - 1);
return xi + _resolution * (yi + _resolution * zi);
}
float SearchDistance(Vector3 pt)
{
var r = _extent;
var s = _extent * 0.5f;
for (var i = 0; i < 10; i++)
{
r += (Physics.CheckSphere(pt, r) ? -1 : 1) * s;
s *= 0.5f;
}
return r;
}
#endregion
#endif
}
}