You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
11 KiB
C#
377 lines
11 KiB
C#
/******************************************************************************/
|
|
/*
|
|
Project - MudBun
|
|
Publisher - Long Bunny Labs
|
|
http://LongBunnyLabs.com
|
|
Author - Ming-Lun "Allen" Chou
|
|
http://AllenChou.net
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using Unity.Collections;
|
|
using UnityEngine;
|
|
|
|
#if MUDBUN_BURST
|
|
using Unity.Burst;
|
|
using Unity.Mathematics;
|
|
using AOT;
|
|
#endif
|
|
|
|
namespace MudBun
|
|
{
|
|
#if MUDBUN_BURST
|
|
[BurstCompile]
|
|
#endif
|
|
[ExecuteInEditMode]
|
|
public class MudCurveFull : MudSolid
|
|
{
|
|
/*
|
|
[Header("Noise")]
|
|
|
|
[SerializeField] private bool m_enableNoise = false;
|
|
[SerializeField] private float m_noiseOffset = 0.0f;
|
|
[SerializeField] private Vector2 m_noiseBaseOctaveSize = 0.5f * Vector2.one;
|
|
[SerializeField] [Range(0.0f, 1.0f)] private float m_noiseThreshold = 0.5f;
|
|
[SerializeField] [Range(1, 3)] private int m_noiseNumOctaves = 2;
|
|
[SerializeField] private float m_noiseOctaveOffsetFactor = 0.5f;
|
|
public bool EnableNoise { get => m_enableNoise; set { m_enableNoise = value; MarkDirty(); } }
|
|
public float NoiseOffset { get => m_noiseOffset; set { m_noiseOffset = value; MarkDirty(); } }
|
|
public Vector2 NoiseBaseOctaveSize { get => m_noiseBaseOctaveSize; set { m_noiseBaseOctaveSize = value; MarkDirty(); } }
|
|
public float NoiseThreshold { get => m_noiseThreshold; set { m_noiseThreshold = value; MarkDirty(); } }
|
|
public int NoiseNumOctaves { get => m_noiseNumOctaves; set { m_noiseNumOctaves = value; MarkDirty(); } }
|
|
public float NoiseOctaveOffsetFactor { get => m_noiseOctaveOffsetFactor; set { m_noiseOctaveOffsetFactor = value; MarkDirty(); } }
|
|
*/
|
|
|
|
[Serializable]
|
|
public class Point
|
|
{
|
|
public Transform Transform;
|
|
public float Radius;
|
|
|
|
public Point(Transform transform = null, float radius = 0.2f)
|
|
{
|
|
Transform = transform;
|
|
Radius = radius;
|
|
}
|
|
|
|
public Point(GameObject go, float radius = 0.2f)
|
|
{
|
|
Transform = go?.transform;
|
|
Radius = radius;
|
|
}
|
|
}
|
|
|
|
[Header("Shape")]
|
|
|
|
[SerializeField] [Range(1, 16)] private int m_precision = 8;
|
|
public int Precision { get => m_precision; set { m_precision = value; MarkDirty(); } }
|
|
|
|
public Transform HeadControlPoint;
|
|
public Transform TailControlPoint;
|
|
[SerializeField] private List<Point> m_points = new List<Point>();
|
|
public IList<Point> Points
|
|
{
|
|
get => m_points;
|
|
set
|
|
{
|
|
m_points.Clear();
|
|
foreach (var p in value)
|
|
m_points.Add(p);
|
|
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
public MudCurveFull()
|
|
{
|
|
m_points.Add(new Point());
|
|
}
|
|
|
|
public override Aabb RawBoundsRs
|
|
{
|
|
get
|
|
{
|
|
Aabb bounds = Aabb.Empty;
|
|
|
|
foreach (var p in m_points)
|
|
{
|
|
if (p == null || p.Transform == null)
|
|
continue;
|
|
|
|
Vector3 posRs = PointRs(p.Transform.position);
|
|
Vector3 r = 1.5f * p.Radius * Vector3.one;
|
|
bounds.Include(new Aabb(posRs - r, posRs + r));
|
|
}
|
|
|
|
return bounds;
|
|
}
|
|
}
|
|
|
|
public override void SanitizeParameters()
|
|
{
|
|
base.SanitizeParameters();
|
|
|
|
//Validate.NonNegative(ref m_noiseBaseOctaveSize);
|
|
|
|
if (m_points != null)
|
|
{
|
|
foreach(var p in m_points)
|
|
{
|
|
if (p == null || p.Transform == null)
|
|
continue;
|
|
|
|
Validate.NonNegative(ref p.Radius);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
foreach (var p in m_points)
|
|
{
|
|
if (p == null || p.Transform == null)
|
|
continue;
|
|
|
|
if (!p.Transform.hasChanged)
|
|
continue;
|
|
|
|
MarkDirty();
|
|
p.Transform.hasChanged = false;
|
|
}
|
|
|
|
if (HeadControlPoint != null && HeadControlPoint.hasChanged)
|
|
{
|
|
MarkDirty();
|
|
HeadControlPoint.hasChanged = false;
|
|
}
|
|
|
|
if (TailControlPoint != null && TailControlPoint.hasChanged)
|
|
{
|
|
MarkDirty();
|
|
TailControlPoint.hasChanged = false;
|
|
}
|
|
}
|
|
|
|
public override int FillComputeData(NativeArray<SdfBrush> aBrush, int iStart, List<Transform> aBone)
|
|
{
|
|
if (m_points == null || m_points.Count == 0)
|
|
return 0;
|
|
|
|
if (m_points.Any(p => p == null || p.Transform == null))
|
|
return 0;
|
|
|
|
SdfBrush brush = SdfBrush.New();
|
|
brush.Type = (int) SdfBrush.TypeEnum.CurveFull;
|
|
|
|
if (m_points.Count == 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int iBrush = iStart;
|
|
|
|
brush.Data0.x = m_points.Count + 2;
|
|
brush.Data0.y = Precision;
|
|
brush.Data0.z = 0.0f;//m_enableNoise ? 1.0f : 0.0f;
|
|
|
|
if (aBone != null)
|
|
{
|
|
brush.BoneIndex = aBone.Count;
|
|
foreach (var p in m_points)
|
|
aBone.Add(p.Transform);
|
|
}
|
|
|
|
aBrush[iBrush++] = brush;
|
|
brush.Type = (int) SdfBrush.TypeEnum.Nop;
|
|
|
|
/*
|
|
if (m_enableNoise)
|
|
{
|
|
brush.Data0 = new Vector4(m_noiseBaseOctaveSize.x, m_noiseBaseOctaveSize.y, m_noiseBaseOctaveSize.y, m_noiseThreshold);
|
|
brush.Data1 = new Vector4(m_noiseOffset, 0.0f, 0.0f, m_noiseNumOctaves);
|
|
brush.Data2 = new Vector4(m_noiseOctaveOffsetFactor, 0.0f, 0.0f, 0.0f);
|
|
aBrush[iBrush++] = brush;
|
|
}
|
|
*/
|
|
|
|
int iPreHead = iBrush;
|
|
var head = m_points[0];
|
|
var postHead = m_points[1];
|
|
Vector3 preHeadPosRs =
|
|
HeadControlPoint == null
|
|
? 2.0f * head.Transform.position - postHead.Transform.position
|
|
: HeadControlPoint.position;
|
|
preHeadPosRs = PointRs(preHeadPosRs);
|
|
brush.Data0 = new Vector4(preHeadPosRs.x, preHeadPosRs.y, preHeadPosRs.z, head.Radius);
|
|
aBrush[iBrush++] = brush;
|
|
|
|
for (int i = 0; i < m_points.Count; ++i)
|
|
{
|
|
var p = m_points[i];
|
|
Vector3 pointPosRs = PointRs(p.Transform.position);
|
|
brush.Data0 = new Vector4(pointPosRs.x, pointPosRs.y, pointPosRs.z, p.Radius);
|
|
aBrush[iBrush++] = brush;
|
|
}
|
|
|
|
int iPostTail = iBrush;
|
|
var tail = m_points[m_points.Count - 1];
|
|
var preTail = m_points[m_points.Count - 2];
|
|
Vector3 postTailPosRs =
|
|
TailControlPoint == null
|
|
? 2.0f * tail.Transform.position - preTail.Transform.position
|
|
: TailControlPoint.position;
|
|
postTailPosRs = PointRs(postTailPosRs);
|
|
brush.Data0 = new Vector4(postTailPosRs.x, postTailPosRs.y, postTailPosRs.z, tail.Radius);
|
|
aBrush[iBrush++] = brush;
|
|
|
|
if (HeadControlPoint == null)
|
|
{
|
|
Vector3 headPosRs = PointRs(head.Transform.position);
|
|
Vector3 postHeadPosRs = PointRs(postHead.Transform.position);
|
|
Vector3 headControlPosRs =
|
|
2.0f * headPosRs
|
|
- VectorUtil.CatmullRom
|
|
(
|
|
preHeadPosRs,
|
|
headPosRs,
|
|
postHeadPosRs,
|
|
aBrush[iPreHead + 3].Data0,
|
|
0.75f
|
|
);
|
|
var b = aBrush[iPreHead];
|
|
b.Data0 = new Vector4(headControlPosRs.x, headControlPosRs.y, headControlPosRs.z, head.Radius);
|
|
aBrush[iPreHead] = b;
|
|
}
|
|
|
|
if (TailControlPoint == null)
|
|
{
|
|
Vector3 tailPosRs = PointRs(tail.Transform.position);
|
|
Vector3 preTailPosRs = PointRs(preTail.Transform.position);
|
|
Vector3 tailControlPosRs =
|
|
2.0f * tailPosRs
|
|
- VectorUtil.CatmullRom
|
|
(
|
|
postTailPosRs,
|
|
tailPosRs,
|
|
preTailPosRs,
|
|
aBrush[iPostTail - 3].Data0,
|
|
0.75f
|
|
);
|
|
var b = aBrush[iPostTail];
|
|
b.Data0 = new Vector4(tailControlPosRs.x, tailControlPosRs.y, tailControlPosRs.z, tail.Radius);
|
|
aBrush[iPostTail] = b;
|
|
}
|
|
|
|
return iBrush - iStart;
|
|
}
|
|
|
|
#if MUDBUN_BURST
|
|
[BurstCompile]
|
|
[MonoPInvokeCallback(typeof(Sdf.SdfBrushEvalFunc))]
|
|
[RegisterSdfBrushEvalFunc(SdfBrush.TypeEnum.CurveFull)]
|
|
public static unsafe float EvaluateSdf(float resDummy, ref float3 p, in float3 pRel, SdfBrush* aBrush, int iBrush)
|
|
{
|
|
float res = float.MaxValue;
|
|
var b = aBrush[iBrush];
|
|
|
|
int numPoints = (int) b.Data0.x;
|
|
if (numPoints > 1)
|
|
{
|
|
int precision = (int) b.Data0.y;
|
|
float dt = 1.0f / precision;
|
|
|
|
bool useNoise = false;//(b.Data0.z > 0.0f);
|
|
|
|
int iA = iBrush + (useNoise ? 2 : 1);
|
|
float globalLen = 0.0f;
|
|
int iClosest = -1;
|
|
float tClosest = 0.0f;
|
|
float segResClosest = 0.0f;
|
|
float rClosest = 0.0f;
|
|
float3 pClosest = 0.0f;
|
|
float closestLen = 0.0f;
|
|
for (int i = 1, n = numPoints - 2; i < n; ++i, ++iA)
|
|
{
|
|
float3 pA = new float4(aBrush[iA + 0].Data0).xyz;
|
|
float3 pB = new float4(aBrush[iA + 1].Data0).xyz;
|
|
float3 pC = new float4(aBrush[iA + 2].Data0).xyz;
|
|
float3 pD = new float4(aBrush[iA + 3].Data0).xyz;
|
|
float3 prevPos = pB;
|
|
float r = aBrush[iA + 1].Data0.w;
|
|
float dr = (aBrush[iA + 2].Data0.w - r) * dt;
|
|
float localLen = 0.0f;
|
|
for (float t = dt; t < 1.0001f; t += dt)
|
|
{
|
|
float3 currPos;
|
|
MathUtil.CatmullRom(pA, pB, pC, pD, math.min(1.0f, t), out currPos);
|
|
float segLen = math.length(currPos - prevPos);
|
|
float d = Sdf.RoundCone(p, prevPos, currPos, r, r + dr);
|
|
if (d < res)
|
|
{
|
|
float2 segRes;
|
|
Sdf.Segment(p, prevPos, currPos, out segRes);
|
|
res = d;
|
|
iClosest = i;
|
|
tClosest = t;
|
|
rClosest = r + dr * segRes.y;
|
|
pClosest = math.lerp(prevPos, currPos, segRes.y);
|
|
closestLen = globalLen + localLen + segLen * segRes.y;
|
|
segResClosest = segRes.y;
|
|
}
|
|
prevPos = currPos;
|
|
r += dr;
|
|
localLen += segLen;
|
|
}
|
|
globalLen += localLen;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
public override void DrawSelectionGizmosRs()
|
|
{
|
|
base.DrawSelectionGizmosRs();
|
|
|
|
if (m_points == null)
|
|
return;
|
|
|
|
if (m_points.Any(p => p == null || p.Transform == null))
|
|
return;
|
|
|
|
GizmosUtil.DrawInvisibleCatmullRom
|
|
(
|
|
m_points.Select(p => PointRs(p.Transform.position)).ToArray(),
|
|
m_points.Select(p => p.Radius).ToArray(),
|
|
HeadControlPoint != null ? PointRs(HeadControlPoint.position) : VectorUtil.Invalid,
|
|
TailControlPoint != null ? PointRs(TailControlPoint.position) : VectorUtil.Invalid
|
|
);
|
|
}
|
|
|
|
public override void DrawOutlineGizmosRs()
|
|
{
|
|
base.DrawOutlineGizmosRs();
|
|
|
|
if (m_points == null)
|
|
return;
|
|
|
|
if (m_points.Any(p => p == null || p.Transform == null))
|
|
return;
|
|
|
|
GizmosUtil.DrawWireCatmullRom
|
|
(
|
|
m_points.Select(p => PointRs(p.Transform.position)).ToArray(),
|
|
m_points.Select(p => p.Radius).ToArray(),
|
|
HeadControlPoint != null ? PointRs(HeadControlPoint.position) : VectorUtil.Invalid,
|
|
TailControlPoint != null ? PointRs(TailControlPoint.position) : VectorUtil.Invalid
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|