diff --git a/Assets/Swarm/CrawlerSwarm.cs b/Assets/Swarm/CrawlerSwarm.cs index f9ec656..12b960c 100644 --- a/Assets/Swarm/CrawlerSwarm.cs +++ b/Assets/Swarm/CrawlerSwarm.cs @@ -7,16 +7,85 @@ namespace Swarm { + // Distance-field constrained swarm public sealed class CrawlerSwarm : MonoBehaviour { - #region Editable properties + #region Basic settings [SerializeField] int _instanceCount = 1000; + + public int instanceCount { + get { return _instanceCount; } + } + + #endregion + + #region Renderer settings + [SerializeField] TubeTemplate _template; + + public TubeTemplate template { + get { return _template; } + } + + [SerializeField, Range(0, 0.1f)] float _radius = 0.01f; + + public float radius { + get { return _radius; } + set { _radius = value; } + } + [SerializeField] Material _material; + + public Material material { + get { return _material; } + } + [SerializeField] CosineGradient _gradient; + + public CosineGradient gradient { + get { return _gradient; } + set { _gradient = value; } + } + + #endregion + + #region Dynamics settings + + [SerializeField] float _speed = 0.5f; + + public float speed { + get { return _speed; } + set { _speed = value; } + } + [SerializeField] VolumeData _volume; + public VolumeData volume { + get { return _volume; } + } + + [SerializeField] float _constraint = 6; + + public float constraint { + get { return _constraint; } + set { _constraint = value; } + } + + [SerializeField] float _noiseFrequency = 2; + + public float noiseFrequency { + get { return _noiseFrequency; } + set { _noiseFrequency = value; } + } + + [SerializeField] float _noiseMotion = 0.1f; + + public float noiseMotion { + get { return _noiseMotion; } + set { _noiseMotion = value; } + } + #endregion #region Hidden attributes @@ -107,6 +176,9 @@ void OnDestroy() void Update() { + var time = Time.time; + var delta = Mathf.Min(Time.deltaTime, 1.0f / 15); + // Index offset on the position buffer. var offset0 = InstanceCount * ( _frameCount % HistoryLength); var offset1 = InstanceCount * ((_frameCount + 1) % HistoryLength); @@ -116,7 +188,11 @@ void Update() _compute.SetInt("IndexOffset0", offset0); _compute.SetInt("IndexOffset1", offset1); _compute.SetInt("IndexOffset2", offset2); - _compute.SetFloat("Time", Time.time); + _compute.SetFloat("Time", time); + _compute.SetFloat("Speed", _speed * delta); + _compute.SetFloat("Constraint", _constraint); + _compute.SetFloat("NoiseFrequency", _noiseFrequency); + _compute.SetFloat("NoiseOffset", time * _noiseMotion); // Update the position buffer. var kernel = _compute.FindKernel("CrawlerUpdate"); @@ -128,6 +204,7 @@ void Update() // Draw the meshes with instancing. _material.SetInt("_IndexOffset", _frameCount + 3); + _material.SetFloat("_Radius", _radius); _material.SetVector("_GradientA", _gradient.coeffsA); _material.SetVector("_GradientB", _gradient.coeffsB); _material.SetVector("_GradientC", _gradient.coeffsC2); diff --git a/Assets/Swarm/Editor/CrawlerSwarmEditor.cs b/Assets/Swarm/Editor/CrawlerSwarmEditor.cs new file mode 100644 index 0000000..605db45 --- /dev/null +++ b/Assets/Swarm/Editor/CrawlerSwarmEditor.cs @@ -0,0 +1,66 @@ +// Swarm - Special renderer that draws a swarm of wobbling/crawling tubes. +// https://github.com/keijiro/Swarm + +using UnityEngine; +using UnityEditor; + +namespace Swarm +{ + // Custom inspector for CrawlerSwarm + [CustomEditor(typeof(CrawlerSwarm)), CanEditMultipleObjects] + public class CrawlerSwarmEditor : Editor + { + SerializedProperty _instanceCount; + + SerializedProperty _template; + SerializedProperty _radius; + SerializedProperty _material; + SerializedProperty _gradient; + + SerializedProperty _speed; + SerializedProperty _volume; + SerializedProperty _constraint; + SerializedProperty _noiseFrequency; + SerializedProperty _noiseMotion; + + void OnEnable() + { + _instanceCount = serializedObject.FindProperty("_instanceCount"); + + _template = serializedObject.FindProperty("_template"); + _radius = serializedObject.FindProperty("_radius"); + _material = serializedObject.FindProperty("_material"); + _gradient = serializedObject.FindProperty("_gradient"); + + _speed = serializedObject.FindProperty("_speed"); + _volume = serializedObject.FindProperty("_volume"); + _constraint = serializedObject.FindProperty("_constraint"); + _noiseFrequency = serializedObject.FindProperty("_noiseFrequency"); + _noiseMotion = serializedObject.FindProperty("_noiseMotion"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(_instanceCount); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(_template); + EditorGUILayout.PropertyField(_radius); + EditorGUILayout.PropertyField(_material); + EditorGUILayout.PropertyField(_gradient); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(_speed); + EditorGUILayout.PropertyField(_volume); + EditorGUILayout.PropertyField(_constraint); + EditorGUILayout.PropertyField(_noiseFrequency); + EditorGUILayout.PropertyField(_noiseMotion); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Swarm/Editor/CrawlerSwarmEditor.cs.meta b/Assets/Swarm/Editor/CrawlerSwarmEditor.cs.meta new file mode 100644 index 0000000..e937952 --- /dev/null +++ b/Assets/Swarm/Editor/CrawlerSwarmEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1e0e86c7d739a604b95ed16b908733b6 +timeCreated: 1496157550 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Swarm/Editor/TubeTemplateEditor.cs b/Assets/Swarm/Editor/TubeTemplateEditor.cs index 5a0ddff..574ed4a 100644 --- a/Assets/Swarm/Editor/TubeTemplateEditor.cs +++ b/Assets/Swarm/Editor/TubeTemplateEditor.cs @@ -10,7 +10,7 @@ namespace Swarm { // Custom inspector for TubeTemplate. [CustomEditor(typeof(TubeTemplate)), CanEditMultipleObjects] - public class TubeTemplateEditor : Editor + public sealed class TubeTemplateEditor : Editor { #region Custom inspector diff --git a/Assets/Swarm/Shader/Crawler.compute b/Assets/Swarm/Shader/Crawler.compute index 8873066..cd14beb 100644 --- a/Assets/Swarm/Shader/Crawler.compute +++ b/Assets/Swarm/Shader/Crawler.compute @@ -24,6 +24,10 @@ CBUFFER_START(Params) uint IndexOffset1; uint IndexOffset2; float Time; + float Speed; + float Constraint; + float NoiseFrequency; + float NoiseOffset; CBUFFER_END float UVRandom(float u, float v) @@ -44,7 +48,7 @@ void CrawlerInit(uint id : SV_DispatchThreadID) float x = UVRandom(id * 0.01334, 0.3728); float y = UVRandom(0.8372, id * 0.01197); float z = UVRandom(4.438, id * 0.01938 - 4.378); - float4 p = float4(x, y, z, 0) * 0.8 - 0.4; + float4 p = float4(x, y, z, 0) * 0.5 - 0.25; float d = SampleVolume(p); // Swizzle and compre, choose one with closer distance. @@ -80,17 +84,17 @@ void CrawlerUpdate(uint id : SV_DispatchThreadID) float3 p = PositionBuffer[IndexOffset1 + id].xyz; // Distance field (gradient.x, y, z, distance). - float4 df = SampleVolume(p) * 6; + float4 df = SampleVolume(p) * Constraint; // Two independent noise fields (not completely independent though). - float4 sn1 = snoise(10.33 + p * 2 + Time * 0.1); - float4 sn2 = snoise(32.38 - p * 2 + Time * 0.1); + float4 sn1 = snoise(10.33 + p.xyz * NoiseFrequency + NoiseOffset); + float4 sn2 = snoise(32.38 - p.yzx * NoiseFrequency + NoiseOffset); // Apply the boundary condition to the first noise field. sn1.xyz = -sn1.xyz * df.w + df.xyz * sn1.w; // Apply the divergence free noise field to the position. - p += cross(sn1.xyz, sn2.xyz) * 0.005; + p += cross(sn1.xyz, sn2.xyz) * Speed; // Update the buffer. PositionBuffer[IndexOffset2 + id].xyz = p; diff --git a/Assets/Swarm/Shader/Tube.shader b/Assets/Swarm/Shader/Tube.shader index e96c682..4155e17 100644 --- a/Assets/Swarm/Shader/Tube.shader +++ b/Assets/Swarm/Shader/Tube.shader @@ -22,6 +22,8 @@ half _Smoothness; half _Metallic; + float _Radius; + half3 _GradientA; half3 _GradientB; half3 _GradientC; @@ -53,8 +55,6 @@ #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED - const float radius = 0.01; - float phi = v.vertex.x; // Angle in slice float cap = v.vertex.y; // -1:head, +1:tail float seg = v.vertex.z; // Segment index @@ -76,7 +76,7 @@ float3 normal = n * cos(phi) + b * sin(phi); // Surface normal // Feedback the results. - v.vertex = float4(p + normal * radius * (1 - abs(cap)), 1); + v.vertex = float4(p + normal * _Radius * (1 - abs(cap)), 1); v.normal = normal * (1 - abs(cap)) + n * cap; v.color = param; diff --git a/Assets/Test/Test.unity b/Assets/Test/Test.unity index b03d5fa..d12e63f 100644 --- a/Assets/Test/Test.unity +++ b/Assets/Test/Test.unity @@ -355,9 +355,14 @@ MonoBehaviour: m_EditorClassIdentifier: _instanceCount: 4000 _template: {fileID: 11400000, guid: 407b7afb8fbe855408cc9bf4dd39058a, type: 2} + _radius: 0.01 _material: {fileID: 2100000, guid: b3e3f432bd29ac1499686dbad7ae39ef, type: 2} _gradient: {fileID: 11400000, guid: 202a0875a5bc2554a932e60d8ed7e7ec, type: 2} + _speed: 0.5 _volume: {fileID: 11400000, guid: 33827603f26d861438dab734dfca23e1, type: 2} + _constraint: 6 + _noiseFrequency: 2 + _noiseMotion: 0.1 _compute: {fileID: 7200000, guid: e579db230e141ad4baa8636ac84ed1ef, type: 3} --- !u!4 &1452801457 Transform: