Skip to content

Instantly share code, notes, and snippets.

@nshelton
Last active April 30, 2018 03:38
Show Gist options
  • Save nshelton/f213d1086e631964865a2eec1d4523e5 to your computer and use it in GitHub Desktop.
Save nshelton/f213d1086e631964865a2eec1d4523e5 to your computer and use it in GitHub Desktop.
m_primitive should be a prefab with a small collider (scale like 0.005). Run the script and then put a small collider in the center to get things to start sticking to it. May take some time. Also set growthRoot to some gameobject, that's where the primitives will be instantiated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
public class DiffusionLimitedAggregation : MonoBehaviour
{
[SerializeField]
private int m_numPoints = 10000;
[SerializeField]
private float m_intersectRadius = 0.002f;
[SerializeField]
private float m_initialVelocity = 0.1f;
private Vector3[] m_points;
private Vector3[] m_velocity;
private List<Vector3> m_depositedPoints;
[SerializeField]
private GameObject m_primitive;
[SerializeField]
private GameObject m_growthRoot;
private Collider[] m_hitResults;
void Start()
{
m_hitResults = new Collider[1];
m_points = new Vector3[m_numPoints];
m_velocity = new Vector3[m_numPoints];
m_depositedPoints = new List<Vector3>();
for (int i = 0; i < m_numPoints; i++)
{
SpawnParticle(i);
}
}
void SpawnParticle(int index)
{
m_points[index] = new Vector3(
Random.value * transform.localScale.x,
Random.value * transform.localScale.y,
Random.value * transform.localScale.z);
m_velocity[index] = Random.onUnitSphere * m_initialVelocity;
}
void SpawnPrimitive(Vector3 p)
{
var prim = Instantiate(m_primitive, m_growthRoot.transform);
prim.transform.position = p;
m_depositedPoints.Add(p);
}
void AdvectPoints()
{
for (int i = 0; i < m_numPoints; i++)
{
m_points[i] += m_velocity[i] * Time.deltaTime;
if (m_points[i].x > transform.localScale.x ||
m_points[i].y > transform.localScale.y ||
m_points[i].z > transform.localScale.z ||
m_points[i].x < 0 ||
m_points[i].y < 0 ||
m_points[i].z < 0)
{
SpawnParticle(i);
}
if(Physics.OverlapSphereNonAlloc(m_points[i], m_intersectRadius, m_hitResults) > 0)
{
SpawnPrimitive(m_points[i]);
SpawnParticle(i);
}
}
}
public void SavePoints()
{
string outPath = "Assets/points.ply";
StreamWriter writer = new StreamWriter(outPath, true);
writer.WriteLine("ply");
writer.WriteLine("format ascii 1.0 ");
writer.WriteLine(string.Format("element vertex {0}", m_depositedPoints.Count));
writer.WriteLine("property float x");
writer.WriteLine("property float y");
writer.WriteLine("property float z");
writer.WriteLine("end_header");
for ( int i = 0; i < m_depositedPoints.Count; i++)
{
string outString = string.Format("{0} {1} {2}", m_depositedPoints[i].x, m_depositedPoints[i].y, m_depositedPoints[i].z);
writer.WriteLine(outString);
}
writer.Close();
}
void Update()
{
//5x faster!!!!!!
AdvectPoints();
AdvectPoints();
AdvectPoints();
AdvectPoints();
AdvectPoints();
}
void OnDrawGizmos()
{
if ( m_points != null)
for (int i = 0; i < m_points.Length; i++)
{
Gizmos.DrawWireSphere(m_points[i], m_intersectRadius);
}
Gizmos.DrawWireCube(Vector3.one * 0.5f, transform.localScale);
}
}
// this is just to export the point cloud if you want to look at it in another program
[CustomEditor(typeof(DiffusionLimitedAggregation))]
public class DiffusionLimitedAggregationEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
DiffusionLimitedAggregation myScript = (DiffusionLimitedAggregation)target;
if(GUILayout.Button("Save"))
{
myScript.SavePoints();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment