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.
222 lines
7.5 KiB
C#
222 lines
7.5 KiB
C#
|
3 years ago
|
using UnityEngine;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
namespace UnityEngine.Polybrush
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Contains the brush target values
|
||
|
|
/// </summary>
|
||
|
|
internal class SplatWeight
|
||
|
|
{
|
||
|
|
private Dictionary<MeshChannel, int> map;
|
||
|
|
float[] values;
|
||
|
|
|
||
|
|
internal Vector4 this[MeshChannel channel]
|
||
|
|
{
|
||
|
|
get { return GetVec4(map[channel]); }
|
||
|
|
set { SetVec4(map[channel], value); }
|
||
|
|
}
|
||
|
|
|
||
|
|
internal float this[AttributeLayout attribute]
|
||
|
|
{
|
||
|
|
get { return GetAttributeValue(attribute); }
|
||
|
|
set { SetAttributeValue(attribute, value); }
|
||
|
|
}
|
||
|
|
|
||
|
|
internal float this[int valueIndex]
|
||
|
|
{
|
||
|
|
get { return values[valueIndex]; }
|
||
|
|
set { values[valueIndex] = value; }
|
||
|
|
}
|
||
|
|
|
||
|
|
internal SplatWeight(Dictionary<MeshChannel, int> map)
|
||
|
|
{
|
||
|
|
this.map = new Dictionary<MeshChannel, int>();
|
||
|
|
foreach(var v in map)
|
||
|
|
this.map.Add(v.Key, v.Value);
|
||
|
|
this.values = new float[map.Count * 4];
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Deep copy constructor.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="rhs">The SplatWeight we copy from</param>
|
||
|
|
internal SplatWeight(SplatWeight rhs)
|
||
|
|
{
|
||
|
|
this.map = new Dictionary<MeshChannel, int>();
|
||
|
|
|
||
|
|
foreach(var kvp in rhs.map)
|
||
|
|
this.map.Add(kvp.Key, kvp.Value);
|
||
|
|
|
||
|
|
int len = rhs.values.Length;
|
||
|
|
this.values = new float[len];
|
||
|
|
System.Array.Copy(rhs.values, this.values, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Return a Dictionnary that maps MeshChannels with their indexes
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="attributes"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
internal static Dictionary<MeshChannel, int> GetChannelMap(AttributeLayout[] attributes)
|
||
|
|
{
|
||
|
|
int index = 0;
|
||
|
|
|
||
|
|
Dictionary<MeshChannel, int> channelMap = new Dictionary<MeshChannel, int>();
|
||
|
|
|
||
|
|
foreach(MeshChannel ch in attributes.Select(x => x.channel).Distinct())
|
||
|
|
channelMap.Add(ch, index++);
|
||
|
|
|
||
|
|
return channelMap;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Does this have the same attributes as "attributes" ?
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="attributes"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
internal bool MatchesAttributes(AttributeLayout[] attributes)
|
||
|
|
{
|
||
|
|
for(int i = 0; i < attributes.Length; i++)
|
||
|
|
if(!map.ContainsKey(attributes[i].channel))
|
||
|
|
return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private Vector4 GetVec4(int index)
|
||
|
|
{
|
||
|
|
return new Vector4(
|
||
|
|
values[index * 4 ],
|
||
|
|
values[index * 4 + 1],
|
||
|
|
values[index * 4 + 2],
|
||
|
|
values[index * 4 + 3]);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetVec4(int index, Vector4 value)
|
||
|
|
{
|
||
|
|
values[index * 4 ] = value.x;
|
||
|
|
values[index * 4 + 1] = value.y;
|
||
|
|
values[index * 4 + 2] = value.z;
|
||
|
|
values[index * 4 + 3] = value.w;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal float GetAttributeValue(AttributeLayout attrib)
|
||
|
|
{
|
||
|
|
return values[GetAttributeIndex(attrib)];
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void SetAttributeValue(AttributeLayout attrib, float value)
|
||
|
|
{
|
||
|
|
values[GetAttributeIndex(attrib)] = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal int GetAttributeIndex(AttributeLayout attrib)
|
||
|
|
{
|
||
|
|
return map[attrib.channel] * 4 + (int)attrib.index;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Copy values array to another splatweight. This function doesn't check
|
||
|
|
/// that attribute layouts are matching; must do this yourself.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="other"></param>
|
||
|
|
internal void CopyTo(SplatWeight other)
|
||
|
|
{
|
||
|
|
for(int i = 0; i < values.Length; i++)
|
||
|
|
other.values[i] = this.values[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void Lerp(SplatWeight lhs, SplatWeight rhs, float alpha)
|
||
|
|
{
|
||
|
|
int len = values.Length;
|
||
|
|
|
||
|
|
if(len == 4)
|
||
|
|
{
|
||
|
|
values[0] = Mathf.LerpUnclamped(lhs.values[0], rhs.values[0], alpha);
|
||
|
|
values[1] = Mathf.LerpUnclamped(lhs.values[1], rhs.values[1], alpha);
|
||
|
|
values[2] = Mathf.LerpUnclamped(lhs.values[2], rhs.values[2], alpha);
|
||
|
|
values[3] = Mathf.LerpUnclamped(lhs.values[3], rhs.values[3], alpha);
|
||
|
|
}
|
||
|
|
else if(len == 8)
|
||
|
|
{
|
||
|
|
values[0] = Mathf.LerpUnclamped(lhs.values[0], rhs.values[0], alpha);
|
||
|
|
values[1] = Mathf.LerpUnclamped(lhs.values[1], rhs.values[1], alpha);
|
||
|
|
values[2] = Mathf.LerpUnclamped(lhs.values[2], rhs.values[2], alpha);
|
||
|
|
values[3] = Mathf.LerpUnclamped(lhs.values[3], rhs.values[3], alpha);
|
||
|
|
values[4] = Mathf.LerpUnclamped(lhs.values[4], rhs.values[4], alpha);
|
||
|
|
values[5] = Mathf.LerpUnclamped(lhs.values[5], rhs.values[5], alpha);
|
||
|
|
values[6] = Mathf.LerpUnclamped(lhs.values[6], rhs.values[6], alpha);
|
||
|
|
values[7] = Mathf.LerpUnclamped(lhs.values[7], rhs.values[7], alpha);
|
||
|
|
}
|
||
|
|
else if(len == 16)
|
||
|
|
{
|
||
|
|
values[0] = Mathf.LerpUnclamped(lhs.values[0], rhs.values[0], alpha);
|
||
|
|
values[1] = Mathf.LerpUnclamped(lhs.values[1], rhs.values[1], alpha);
|
||
|
|
values[2] = Mathf.LerpUnclamped(lhs.values[2], rhs.values[2], alpha);
|
||
|
|
values[3] = Mathf.LerpUnclamped(lhs.values[3], rhs.values[3], alpha);
|
||
|
|
values[4] = Mathf.LerpUnclamped(lhs.values[4], rhs.values[4], alpha);
|
||
|
|
values[5] = Mathf.LerpUnclamped(lhs.values[5], rhs.values[5], alpha);
|
||
|
|
values[6] = Mathf.LerpUnclamped(lhs.values[6], rhs.values[6], alpha);
|
||
|
|
values[7] = Mathf.LerpUnclamped(lhs.values[7], rhs.values[7], alpha);
|
||
|
|
values[8] = Mathf.LerpUnclamped(lhs.values[8], rhs.values[8], alpha);
|
||
|
|
values[9] = Mathf.LerpUnclamped(lhs.values[9], rhs.values[9], alpha);
|
||
|
|
values[10] = Mathf.LerpUnclamped(lhs.values[10], rhs.values[10], alpha);
|
||
|
|
values[11] = Mathf.LerpUnclamped(lhs.values[11], rhs.values[11], alpha);
|
||
|
|
values[12] = Mathf.LerpUnclamped(lhs.values[12], rhs.values[12], alpha);
|
||
|
|
values[13] = Mathf.LerpUnclamped(lhs.values[13], rhs.values[13], alpha);
|
||
|
|
values[14] = Mathf.LerpUnclamped(lhs.values[14], rhs.values[14], alpha);
|
||
|
|
values[15] = Mathf.LerpUnclamped(lhs.values[15], rhs.values[15], alpha);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for(int i = 0; i < lhs.values.Length; i++)
|
||
|
|
values[i] = Mathf.LerpUnclamped(lhs.values[i], rhs.values[i], alpha);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void Lerp(SplatWeight lhs, SplatWeight rhs, float alpha, List<int> mask)
|
||
|
|
{
|
||
|
|
// optimize for some common values
|
||
|
|
// unrolling the loop in these smaller cases can improve performances by ~33%
|
||
|
|
if(mask.Count == 4)
|
||
|
|
{
|
||
|
|
values[mask[0]] = Mathf.LerpUnclamped(lhs.values[mask[0]], rhs.values[mask[0]], alpha);
|
||
|
|
values[mask[1]] = Mathf.LerpUnclamped(lhs.values[mask[1]], rhs.values[mask[1]], alpha);
|
||
|
|
values[mask[2]] = Mathf.LerpUnclamped(lhs.values[mask[2]], rhs.values[mask[2]], alpha);
|
||
|
|
values[mask[3]] = Mathf.LerpUnclamped(lhs.values[mask[3]], rhs.values[mask[3]], alpha);
|
||
|
|
}
|
||
|
|
else if(mask.Count == 8)
|
||
|
|
{
|
||
|
|
values[mask[0]] = Mathf.LerpUnclamped(lhs.values[mask[0]], rhs.values[mask[0]], alpha);
|
||
|
|
values[mask[1]] = Mathf.LerpUnclamped(lhs.values[mask[1]], rhs.values[mask[1]], alpha);
|
||
|
|
values[mask[2]] = Mathf.LerpUnclamped(lhs.values[mask[2]], rhs.values[mask[2]], alpha);
|
||
|
|
values[mask[3]] = Mathf.LerpUnclamped(lhs.values[mask[3]], rhs.values[mask[3]], alpha);
|
||
|
|
values[mask[4]] = Mathf.LerpUnclamped(lhs.values[mask[4]], rhs.values[mask[4]], alpha);
|
||
|
|
values[mask[5]] = Mathf.LerpUnclamped(lhs.values[mask[5]], rhs.values[mask[5]], alpha);
|
||
|
|
values[mask[6]] = Mathf.LerpUnclamped(lhs.values[mask[6]], rhs.values[mask[6]], alpha);
|
||
|
|
values[mask[7]] = Mathf.LerpUnclamped(lhs.values[mask[7]], rhs.values[mask[7]], alpha);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for(int i = 0; i < mask.Count; i++)
|
||
|
|
values[mask[i]] = Mathf.LerpUnclamped(lhs.values[mask[i]], rhs.values[mask[i]], alpha);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override string ToString()
|
||
|
|
{
|
||
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||
|
|
|
||
|
|
foreach(var v in map)
|
||
|
|
{
|
||
|
|
sb.Append(v.Key.ToString());
|
||
|
|
sb.Append(": ");
|
||
|
|
sb.AppendLine(GetVec4(v.Value).ToString("F2"));
|
||
|
|
}
|
||
|
|
|
||
|
|
return sb.ToString();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|