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.

238 lines
9.4 KiB
C#

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
██████╗░██╗░░░░░███████╗██╗░░██╗██╗░░░██╗░██████╗
██╔══██╗██║░░░░░██╔════╝╚██╗██╔╝██║░░░██║██╔════╝
██████╔╝██║░░░░░█████╗░░░╚███╔╝░██║░░░██║╚█████╗░
██╔═══╝░██║░░░░░██╔══╝░░░██╔██╗░██║░░░██║░╚═══██╗
██║░░░░░███████╗███████╗██╔╝╚██╗╚██████╔╝██████╔╝
╚═╝░░░░░╚══════╝╚══════╝╚═╝░░╚═╝░╚═════╝░╚═════╝░
█▀▀▄ █──█   ▀▀█▀▀ █──█ █▀▀   ░█▀▀▄ █▀▀ ▀█─█▀ █▀▀ █── █▀▀█ █▀▀█ █▀▀ █▀▀█
█▀▀▄ █▄▄█   ─░█── █▀▀█ █▀▀   ░█─░█ █▀▀ ─█▄█─ █▀▀ █── █──█ █──█ █▀▀ █▄▄▀
▀▀▀─ ▄▄▄█   ─░█── ▀──▀ ▀▀▀   ░█▄▄▀ ▀▀▀ ──▀── ▀▀▀ ▀▀▀ ▀▀▀▀ █▀▀▀ ▀▀▀ ▀─▀▀
____________________________________________________________________________________________________________________________________________
▄▀█ █▀ █▀ █▀▀ ▀█▀ ▀   █░█ █░░ ▀█▀ █ █▀▄▀█ ▄▀█ ▀█▀ █▀▀   ▄█ █▀█ ▄█▄   █▀ █░█ ▄▀█ █▀▄ █▀▀ █▀█ █▀
█▀█ ▄█ ▄█ ██▄ ░█░ ▄   █▄█ █▄▄ ░█░ █ █░▀░█ █▀█ ░█░ ██▄   ░█ █▄█ ░▀░   ▄█ █▀█ █▀█ █▄▀ ██▄ █▀▄ ▄█
____________________________________________________________________________________________________________________________________________
License:
The license is ATTRIBUTION 3.0
More license info here:
https://creativecommons.org/licenses/by/3.0/
____________________________________________________________________________________________________________________________________________
This shader has NOT been tested on any other PC configuration except the following:
CPU: Intel Core i5-6400
GPU: NVidia GTX 750Ti
RAM: 16GB
Windows: 10 x64
DirectX: 11
____________________________________________________________________________________________________________________________________________
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//[ExecuteAlways]
public class Plexus : MonoBehaviour
{
public ComputeShader plexus;
public int amountOfPoints = 100;
public int PPPS = 2; // Processed Points Per Second
public float lineWidth = 0.02f;
public Material lineMaterial;
public Vector3 box = new Vector3(4, 4, 4);
public float particleSpeed = 1.0f;
public float maxConnDistance = 3.0f; // The maximum distance for two points to connect
private float maxConnDistanceSqr;
private Vector3[] defaultPositions;
private Vector3[] velocities;
private Vector3[] positions;
private Mesh lineMesh;
private void Start()
{
lineMaterial.SetVector("_BoxDims", new Vector4(box.x, box.y, box.z, 1));
positions = new Vector3[amountOfPoints];
defaultPositions = new Vector3[amountOfPoints];
for (int i = 0; i < amountOfPoints; ++i)
{
positions[i] = new Vector3(
Random.Range(-box.x, box.x),
Random.Range(-box.y, box.y),
Random.Range(-box.z, box.z));
defaultPositions[i] = positions[i];
}
lineMesh = new Mesh();
int[] trigs = new int[6];
trigs[0] = 0;
trigs[1] = 1;
trigs[2] = 2;
trigs[3] = 3;
trigs[4] = 2;
trigs[5] = 1;
lineMesh.vertices = verts;
lineMesh.triangles = trigs;
velocities = new Vector3[amountOfPoints];
StartCoroutine(ConnectDots());
}
private void Update()
{
MovePoints();
RenderLines();
}
private void MovePoints()
{
int kernelIndex = plexus.FindKernel("MoveParticels");
// sizeof(float3) == 12
ComputeBuffer positionsBuffer = new ComputeBuffer(positions.Length, 12);
positionsBuffer.SetData(positions);
plexus.SetBuffer(kernelIndex, "positions", positionsBuffer);
// sizeof(float3) == 12
ComputeBuffer defaultPositionsBuffer = new ComputeBuffer(defaultPositions.Length, 12);
defaultPositionsBuffer.SetData(defaultPositions);
plexus.SetBuffer(kernelIndex, "defaultPositions", defaultPositionsBuffer);
// sizeof(float3) == 12
ComputeBuffer velocitiesBuffer = new ComputeBuffer(velocities.Length, 12);
velocitiesBuffer.SetData(velocities);
plexus.SetBuffer(kernelIndex, "velocities", velocitiesBuffer);
plexus.SetFloat("deltaTime", Time.deltaTime);
plexus.SetFloat("elapsedTime", Time.time);
plexus.SetFloat("particleSpeed", particleSpeed);
plexus.Dispatch(kernelIndex, positions.Length, 1, 1);
positionsBuffer.GetData(positions);
positionsBuffer.Release();
defaultPositionsBuffer.Release();
velocitiesBuffer.Release();
}
private static float DistanceSqr(Vector3 p1, Vector3 p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) + (p1.z - p2.z) * (p1.z - p2.z);
}
Vector3 normal, side, p1, p2;
int startingVerticesIndex = 0;
List<int> lineTrigs = new List<int>();
List<Vector3> lineVerts = new List<Vector3>();
Vector3[] verts = new Vector3[4];
int[] trigs = new int[6];
private void RenderLines()
{
lineMesh = new Mesh();
for (int i = 0; i < connected.Count; ++i)
{
// DrawLine(positions[connected[i].Key], positions[connected[i].Value]);
//transform.position - positions[connected[i].Key], // local to world space
//transform.position - positions[connected[i].Value]); // local to world space
p1 = positions[connected[i].Key];
p2 = positions[connected[i].Value];
normal = Vector3.Cross(p1, p2);
side = Vector3.Cross(normal, p2 - p1);
side.Normalize();
startingVerticesIndex = lineVerts.Count;
verts[0] = p1 + side * (lineWidth / 2);
verts[1] = p1 + side * (lineWidth / -2);
verts[2] = p2 + side * (lineWidth / 2);
verts[3] = p2 + side * (lineWidth / -2);
trigs[0] = startingVerticesIndex;
trigs[1] = trigs[5] = startingVerticesIndex + 1;
trigs[2] = trigs[4] = startingVerticesIndex + 2;
trigs[3] = startingVerticesIndex + 3;
lineVerts.AddRange(verts);
lineTrigs.AddRange(trigs);
}
lineMesh.vertices = lineVerts.ToArray();
lineMesh.triangles = lineTrigs.ToArray();
// Drawing the mesh
lineMesh.RecalculateBounds();
Graphics.DrawMesh(lineMesh, transform.localToWorldMatrix, lineMaterial, 0);
// Emptying the memory
lineTrigs.Clear();
lineVerts.Clear();
}
[HideInInspector]
public bool isEnabled = false;
List<KeyValuePair<int, int>> connected = new List<KeyValuePair<int, int>>();
HashSet<KeyValuePair<int, int>> connectedHashSet = new HashSet<KeyValuePair<int, int>>();
private IEnumerator ConnectDots()
{
// the idea behind this code is to extend the connection of dots in time
// not to do it each frame for all points but instead of doing it each frame for
// N points
WaitForEndOfFrame wfeof = new WaitForEndOfFrame();
int indx = 0, i = 0, j = 0;
Vector3 currentPos;
maxConnDistanceSqr = maxConnDistance * maxConnDistance;
do
{
yield return wfeof;
for (j = 0; j < PPPS; ++j)
{
currentPos = positions[indx];
connected.RemoveAll(x => x.Key == indx || x.Value == indx);
connectedHashSet.RemoveWhere(x => x.Key == indx || x.Value == indx);
for (i = 0; i < amountOfPoints; ++i)
{
if (i == indx)
continue;
if (DistanceSqr(currentPos, positions[i]) < maxConnDistanceSqr)
{
KeyValuePair<int, int> k = new KeyValuePair<int, int>(indx, i);
if(connectedHashSet.Add(k))
connected.Add(new KeyValuePair<int, int>(indx, i));
}
}
++indx;
if (indx >= amountOfPoints)
indx = 0;
}
} while (!isEnabled);
}
}