mirror of
https://github.com/celisej567/metaballs.git
synced 2025-12-31 09:49:26 +03:00
A lot of diffrerent things
Now containers will have different meshes. Added Bouncing Ball in context menu. Added Metaballs namespace. Added QuakeFastSqrt function instead default sqrt in .compute shader. Fixed some bugs. Bug: actuall you can't use more then one Conteiner, because for some reason only one work at one time. It will show, but not updates.
This commit is contained in:
@@ -1,66 +1,81 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
public class BouncingBall : MetaBall {
|
||||
public float speed;
|
||||
|
||||
private Container container;
|
||||
private Vector3 direction;
|
||||
|
||||
private Vector3 lastPos;
|
||||
|
||||
override public void OnDrawGizmos()
|
||||
namespace MetaBalls
|
||||
{
|
||||
public class BouncingBall : MetaBall
|
||||
{
|
||||
base.OnDrawGizmos();
|
||||
}
|
||||
public override void Start() {
|
||||
base.Start();
|
||||
this.direction = Random.onUnitSphere;
|
||||
this.container = this.GetComponentInParent<Container>();
|
||||
}
|
||||
public float speed;
|
||||
|
||||
override public void Update()
|
||||
{
|
||||
base.Update();
|
||||
if (Application.isPlaying)
|
||||
private Container container;
|
||||
private Vector3 direction;
|
||||
|
||||
private Vector3 lastPos;
|
||||
|
||||
override public void OnDrawGizmos()
|
||||
{
|
||||
if (transform.position != lastPos)
|
||||
base.OnDrawGizmos();
|
||||
}
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
this.direction = Random.onUnitSphere;
|
||||
this.container = this.GetComponentInParent<Container>();
|
||||
}
|
||||
|
||||
override public void Update()
|
||||
{
|
||||
base.Update();
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
lastPos = transform.position;
|
||||
this.updatePosition(Time.deltaTime);
|
||||
if (transform.position != lastPos && speed != 0)
|
||||
{
|
||||
lastPos = transform.position;
|
||||
this.updatePosition(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePosition(float dt)
|
||||
{
|
||||
float posX = this.transform.position.x, posY = this.transform.position.y, posZ = this.transform.position.z;
|
||||
Vector3 containerPosition = this.container.transform.position;
|
||||
Vector3 containerScale = this.container.transform.localScale;
|
||||
|
||||
if (posX + this.radius + this.container.safeZone > containerPosition.x + containerScale.x / 2)
|
||||
{
|
||||
posX -= 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.left);
|
||||
}
|
||||
else if (posX - this.radius - this.container.safeZone < containerPosition.x - containerScale.x / 2)
|
||||
{
|
||||
posX += 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.right);
|
||||
}
|
||||
|
||||
if (posY + this.radius + this.container.safeZone > containerPosition.y + containerScale.y / 2)
|
||||
{
|
||||
posY -= 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.down);
|
||||
}
|
||||
else if (posY - this.radius - this.container.safeZone < containerPosition.y - containerScale.y / 2)
|
||||
{
|
||||
posY += 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.up);
|
||||
}
|
||||
|
||||
if (posZ + this.radius + this.container.safeZone > containerPosition.z + containerScale.z / 2)
|
||||
{
|
||||
posZ -= 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.back);
|
||||
}
|
||||
else if (posZ - this.radius - this.container.safeZone < containerPosition.z - containerScale.z / 2)
|
||||
{
|
||||
posZ += 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.forward);
|
||||
}
|
||||
|
||||
this.transform.position = new Vector3(posX, posY, posZ) + this.direction * speed * dt;
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePosition(float dt) {
|
||||
float posX = this.transform.position.x, posY = this.transform.position.y, posZ = this.transform.position.z;
|
||||
Vector3 containerPosition = this.container.transform.position;
|
||||
Vector3 containerScale = this.container.transform.localScale;
|
||||
|
||||
if(posX + this.radius + this.container.safeZone > containerPosition.x + containerScale.x / 2) {
|
||||
posX -= 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.left);
|
||||
} else if(posX - this.radius - this.container.safeZone < containerPosition.x - containerScale.x / 2) {
|
||||
posX += 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.right);
|
||||
}
|
||||
|
||||
if(posY + this.radius + this.container.safeZone > containerPosition.y + containerScale.y / 2) {
|
||||
posY -= 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.down);
|
||||
} else if(posY - this.radius - this.container.safeZone < containerPosition.y - containerScale.y / 2) {
|
||||
posY += 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.up);
|
||||
}
|
||||
|
||||
if(posZ + this.radius + this.container.safeZone > containerPosition.z + containerScale.z / 2) {
|
||||
posZ -= 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.back);
|
||||
} else if(posZ - this.radius - this.container.safeZone < containerPosition.z - containerScale.z / 2) {
|
||||
posZ += 0.01f;
|
||||
this.direction = Vector3.Reflect(this.direction, Vector3.forward);
|
||||
}
|
||||
|
||||
this.transform.position = new Vector3(posX, posY, posZ) + this.direction * speed * dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +1,237 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class Container : MonoBehaviour {
|
||||
public float safeZone = 0.8f;
|
||||
public float resolution = 0.2f;
|
||||
public float threshold = 1;
|
||||
public float updateDelay = 0.03f;
|
||||
public ComputeShader computeShader;
|
||||
public bool calculateNormals = true;
|
||||
public Material material;
|
||||
namespace MetaBalls
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class Container : MonoBehaviour
|
||||
{
|
||||
|
||||
float lastsafeZone = 0.04f;
|
||||
float lastresolution = 0.15f;
|
||||
float lastthreshold = 1;
|
||||
float nextUpdate;
|
||||
Vector3 lastscale = new Vector3(1,1,1);
|
||||
[Header("Variables")]
|
||||
public float safeZone = 0.8f;
|
||||
public float threshold = 1;
|
||||
public float updateDelay = 0.03f;
|
||||
|
||||
MetaBall[] balls; //hehe
|
||||
Vector3[] lastBallsPos;
|
||||
bool update;
|
||||
List<Vector3> lastPosBalls = new List<Vector3>();
|
||||
public ComputeShader computeShader;
|
||||
public bool calculateNormals = true;
|
||||
public Material material;
|
||||
|
||||
private bool message = true;
|
||||
public float resolutionX = 0.2f;
|
||||
public float resolutionY = 0.2f;
|
||||
public float resolutionZ = 0.2f;
|
||||
|
||||
private CubeGrid grid;
|
||||
float lastsafeZone = 0.04f;
|
||||
float lastResolutionX = 0.2f;
|
||||
float lastResolutionY = 0.2f;
|
||||
float lastResolutionZ = 0.2f;
|
||||
float lastthreshold = 1;
|
||||
float nextUpdate;
|
||||
Vector3 lastscale = new Vector3(1, 1, 1);
|
||||
|
||||
public void Start() {
|
||||
balls = GetComponentsInChildren<MetaBall>();
|
||||
nextUpdate = Time.time;
|
||||
for (int i = 0; i<=balls.Length-1; i++)
|
||||
MetaBall[] balls; //hehe
|
||||
Vector3[] lastBallsPos;
|
||||
List<Vector3> lastPosBalls = new List<Vector3>();
|
||||
MeshFilter meshFilter;
|
||||
|
||||
private bool message = true;
|
||||
private CubeGrid grid;
|
||||
|
||||
Mesh mesh;
|
||||
Mesh mySharedMesh;
|
||||
Mesh myMesh;
|
||||
|
||||
bool CheckForChangedResolution()
|
||||
{
|
||||
lastPosBalls.Add(balls[i].transform.position);
|
||||
if ((resolutionX != lastResolutionX) || (resolutionY != lastResolutionY) || (resolutionZ != lastResolutionZ))
|
||||
{
|
||||
lastResolutionX = resolutionX;
|
||||
lastResolutionY = resolutionY;
|
||||
lastResolutionZ = resolutionZ;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.grid = new CubeGrid(this, this.computeShader);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireCube(gameObject.transform.position, gameObject.transform.localScale);
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Vector3 safeScale = new Vector3(gameObject.transform.localScale.x - safeZone, gameObject.transform.localScale.y - safeZone, gameObject.transform.localScale.z - safeZone);
|
||||
Gizmos.DrawWireCube(gameObject.transform.position, safeScale);
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawLine(transform.position, transform.position + (transform.forward * 2));
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position, transform.position + (transform.right * 2));
|
||||
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawLine(transform.position, transform.position + (transform.up * 2));
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
if (Time.time >= nextUpdate)
|
||||
bool CheckForBallsPos()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
for (int i = 0; i <= balls.Length - 1; i++)
|
||||
{
|
||||
for (int i = 0; i <= balls.Length - 1; i++)
|
||||
if (lastPosBalls[i] != balls[i].transform.position)
|
||||
{
|
||||
if (lastPosBalls[i] != balls[i].transform.position)
|
||||
{
|
||||
update = true;
|
||||
lastPosBalls[i] = balls[i].gameObject.transform.position;
|
||||
}
|
||||
lastPosBalls[i] = balls[i].gameObject.transform.position;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (update || (lastsafeZone != safeZone) || (lastresolution != resolution) || (lastthreshold != threshold) || (lastscale != transform.localScale))
|
||||
Vector3[] Smooth(Vector3[] verts, int[] triangles)
|
||||
{
|
||||
Vector3[] normals = new Vector3[verts.Length];
|
||||
List<Vector3>[] vertexNormals = new List<Vector3>[verts.Length];
|
||||
for (int i = 0; i < vertexNormals.Length; i++)
|
||||
{
|
||||
vertexNormals[i] = new List<Vector3>();
|
||||
}
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
Vector3 currNormal = Vector3.Cross(
|
||||
(verts[triangles[i + 1]] - verts[triangles[i]]).normalized,
|
||||
(verts[triangles[i + 2]] - verts[triangles[i]]).normalized);
|
||||
|
||||
vertexNormals[triangles[i]].Add(currNormal);
|
||||
vertexNormals[triangles[i + 1]].Add(currNormal);
|
||||
vertexNormals[triangles[i + 2]].Add(currNormal);
|
||||
}
|
||||
for (int i = 0; i < vertexNormals.Length; i++)
|
||||
{
|
||||
normals[i] = Vector3.zero;
|
||||
float numNormals = vertexNormals[i].Count;
|
||||
for (int j = 0; j < numNormals; j++)
|
||||
{
|
||||
if (grid == null || (lastscale != transform.localScale) || (resolution != lastresolution))
|
||||
normals[i] += vertexNormals[i][j];
|
||||
}
|
||||
normals[i] /= numNormals;
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
Vector3[] CalculateNormals(Mesh mesh)
|
||||
{
|
||||
|
||||
Vector3[] normals = mesh.normals;
|
||||
int[] trigs = mesh.triangles;
|
||||
|
||||
for (int i = 0; i < trigs.Length; i += 3)
|
||||
{
|
||||
|
||||
Vector3 avg = (normals[trigs[i]] + normals[trigs[i + 1]] + normals[trigs[i + 2]]) / 3;
|
||||
normals[trigs[i]] = avg;
|
||||
normals[trigs[i + 1]] = avg;
|
||||
normals[trigs[i + 2]] = avg;
|
||||
|
||||
}
|
||||
|
||||
return normals;
|
||||
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
balls = GetComponentsInChildren<MetaBall>();
|
||||
|
||||
meshFilter = GetComponent<MeshFilter>();
|
||||
|
||||
mesh = meshFilter.sharedMesh;
|
||||
|
||||
mesh = new Mesh();
|
||||
mesh.name = "MetaBalls " + Random.Range(int.MinValue, int.MaxValue);
|
||||
|
||||
this.GetComponent<MeshFilter>().sharedMesh = mesh;
|
||||
this.GetComponent<MeshFilter>().mesh = mesh;
|
||||
|
||||
nextUpdate = Time.time;
|
||||
for (int i = 0; i <= balls.Length - 1; i++)
|
||||
{
|
||||
lastPosBalls.Add(balls[i].transform.position);
|
||||
}
|
||||
|
||||
lastResolutionX = resolutionX;
|
||||
lastResolutionY = resolutionY;
|
||||
lastResolutionZ = resolutionZ;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
|
||||
Vector3 scale = new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z);
|
||||
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireCube(gameObject.transform.position, scale);
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Vector3 safeScale = new Vector3(scale.x - safeZone, scale.y - safeZone, scale.z - safeZone);
|
||||
Gizmos.DrawWireCube(gameObject.transform.position, safeScale);
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawLine(transform.position, transform.position + (transform.forward * 2));
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position, transform.position + (transform.right * 2));
|
||||
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawLine(transform.position, transform.position + (transform.up * 2));
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
if (Time.time >= nextUpdate)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
|
||||
if (CheckForBallsPos() || (lastsafeZone != safeZone) || (lastthreshold != threshold) || (lastscale != transform.localScale) || CheckForChangedResolution())
|
||||
{
|
||||
this.grid = new CubeGrid(this, this.computeShader);
|
||||
if (grid == null || (lastscale != transform.localScale))
|
||||
{
|
||||
this.grid = new CubeGrid(this, this.computeShader);
|
||||
}
|
||||
|
||||
|
||||
this.grid.evaluateAll(balls);
|
||||
|
||||
GetComponent<MeshRenderer>().material = material;
|
||||
|
||||
mesh.Clear();
|
||||
mesh.vertices = this.grid.vertices.ToArray();
|
||||
mesh.triangles = this.grid.getTriangles();
|
||||
meshFilter.mesh = mesh;
|
||||
|
||||
if (this.calculateNormals)
|
||||
{
|
||||
mesh.RecalculateNormals();
|
||||
}
|
||||
|
||||
lastsafeZone = safeZone;
|
||||
lastthreshold = threshold;
|
||||
lastscale = transform.localScale;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
balls = GetComponentsInChildren<MetaBall>();
|
||||
if (balls == null)
|
||||
return;
|
||||
|
||||
GetComponent<MeshRenderer>().sharedMaterial = material;
|
||||
|
||||
this.grid = new CubeGrid(this, this.computeShader);
|
||||
|
||||
this.grid.evaluateAll(balls);
|
||||
|
||||
Mesh mesh = this.GetComponent<MeshFilter>().mesh;
|
||||
mesh.Clear();
|
||||
mesh.vertices = this.grid.vertices.ToArray();
|
||||
mesh.triangles = this.grid.getTriangles();
|
||||
meshFilter.sharedMesh = mesh;
|
||||
|
||||
if (this.calculateNormals)
|
||||
{
|
||||
mesh.RecalculateNormals();
|
||||
}
|
||||
|
||||
lastsafeZone = safeZone;
|
||||
lastresolution = resolution;
|
||||
lastthreshold = threshold;
|
||||
lastscale = transform.localScale;
|
||||
update = false;
|
||||
|
||||
}
|
||||
|
||||
nextUpdate = Time.time + updateDelay;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
balls = GetComponentsInChildren<MetaBall>();
|
||||
if (balls == null)
|
||||
return;
|
||||
|
||||
if (GetComponent<MeshRenderer>().material != material)
|
||||
GetComponent<MeshRenderer>().material = material;
|
||||
|
||||
this.grid = new CubeGrid(this, this.computeShader);
|
||||
|
||||
this.grid.evaluateAll(balls);
|
||||
Mesh mesh;
|
||||
|
||||
mesh = this.GetComponent<MeshFilter>().mesh;
|
||||
if (!Application.isPlaying && message)
|
||||
{
|
||||
Debug.Log("If you got \"Please use MeshFilter.sharedMesh instead.\" warning - ignore it.");
|
||||
message = false;
|
||||
}
|
||||
|
||||
mesh.Clear();
|
||||
mesh.vertices = this.grid.vertices.ToArray();
|
||||
mesh.triangles = this.grid.getTriangles();
|
||||
|
||||
if (this.calculateNormals)
|
||||
{
|
||||
mesh.RecalculateNormals();
|
||||
}
|
||||
}
|
||||
|
||||
nextUpdate = Time.time + updateDelay;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,15 @@ using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using MetaBalls;
|
||||
|
||||
public class ContextItem
|
||||
{
|
||||
[MenuItem("GameObject/Metaballs/Volume")]
|
||||
public static void CreateMetaballVoid(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject newObject = ObjectFactory.CreateGameObject("Metaballs", typeof(Container)); // spawn
|
||||
newObject.AddComponent<MeshRenderer>(); newObject.AddComponent<MeshFilter>(); newObject.GetComponent<MeshRenderer>().material = null; //Adding things for render
|
||||
GameObject newObject = ObjectFactory.CreateGameObject("Metaballs", typeof(MeshRenderer)); // spawn
|
||||
newObject.AddComponent<MeshFilter>(); newObject.GetComponent<MeshRenderer>().material = null; newObject.AddComponent<Container>(); //Adding things for render
|
||||
newObject.transform.localScale = new Vector3(5, 5, 5);
|
||||
|
||||
SceneView lastView = SceneView.lastActiveSceneView;
|
||||
@@ -19,12 +20,13 @@ public class ContextItem
|
||||
StageUtility.PlaceGameObjectInCurrentStage(newObject);
|
||||
GameObjectUtility.EnsureUniqueNameForSibling(newObject);
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
if(!Application.isPlaying)
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Metaballs/Ball")]
|
||||
public static void CreateBallVoid(MenuCommand menuCommand)
|
||||
public static void CreateBall(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject newObject = ObjectFactory.CreateGameObject("Ball", typeof(MetaBall)); // spawn
|
||||
|
||||
@@ -35,7 +37,24 @@ public class ContextItem
|
||||
GameObjectUtility.EnsureUniqueNameForSibling(newObject);
|
||||
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
if (!Application.isPlaying)
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Metaballs/Bouncing Ball")]
|
||||
public static void CreateBouncingBall(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject newObject = ObjectFactory.CreateGameObject("Ball", typeof(BouncingBall)); // spawn
|
||||
|
||||
SceneView lastView = SceneView.lastActiveSceneView;
|
||||
newObject.transform.position = lastView ? lastView.pivot : Vector3.zero; // spawn position
|
||||
|
||||
StageUtility.PlaceGameObjectInCurrentStage(newObject);
|
||||
GameObjectUtility.EnsureUniqueNameForSibling(newObject);
|
||||
|
||||
|
||||
if (!Application.isPlaying)
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,152 +2,177 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
struct GPUEdgeValues {
|
||||
public float edge0Val, edge1Val, edge2Val, edge3Val, edge4Val, edge5Val, edge6Val, edge7Val;
|
||||
}
|
||||
|
||||
struct GPUPositions {
|
||||
public Vector3 centerPos;
|
||||
public Vector3 edge0Pos, edge1Pos, edge2Pos, edge3Pos, edge4Pos, edge5Pos, edge6Pos, edge7Pos;
|
||||
}
|
||||
|
||||
struct GPUBall {
|
||||
public float factor;
|
||||
public Vector3 position;
|
||||
}
|
||||
|
||||
struct GPUEdgeVertices {
|
||||
public int index;
|
||||
public Vector3 edge0, edge1, edge2, edge3, edge4, edge5, edge6, edge7, edge8, edge9, edge10, edge11;
|
||||
};
|
||||
|
||||
public class CubeGrid {
|
||||
public List<Vector3> vertices;
|
||||
public int width, height, depth;
|
||||
|
||||
private Container container;
|
||||
|
||||
private ComputeShader shader;
|
||||
private int shaderKernel;
|
||||
|
||||
private ComputeBuffer positionsBuffer;
|
||||
private ComputeBuffer valuesBuffer;
|
||||
private ComputeBuffer metaballsBuffer;
|
||||
private ComputeBuffer edgeMapBuffer;
|
||||
private ComputeBuffer verticesBuffer;
|
||||
|
||||
private GPUPositions[] precomputedPositions;
|
||||
|
||||
private bool initized;
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
|
||||
public CubeGrid(Container container, ComputeShader shader) {
|
||||
this.container = container;
|
||||
this.shader = shader;
|
||||
|
||||
this.width = Mathf.RoundToInt(container.transform.localScale.x / this.container.resolution);
|
||||
this.height = Mathf.RoundToInt(container.transform.localScale.y / this.container.resolution);
|
||||
this.depth = Mathf.RoundToInt(container.transform.localScale.z / this.container.resolution);
|
||||
|
||||
this.vertices = new List<Vector3>();
|
||||
|
||||
this.initized = false;
|
||||
namespace MetaBalls
|
||||
{
|
||||
struct GPUEdgeValues
|
||||
{
|
||||
public float edge0Val, edge1Val, edge2Val, edge3Val, edge4Val, edge5Val, edge6Val, edge7Val;
|
||||
}
|
||||
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
struct GPUPositions
|
||||
{
|
||||
public Vector3 centerPos;
|
||||
public Vector3 edge0Pos, edge1Pos, edge2Pos, edge3Pos, edge4Pos, edge5Pos, edge6Pos, edge7Pos;
|
||||
}
|
||||
|
||||
public void evaluateAll(MetaBall[] metaballs) {
|
||||
if(!this.initized) {
|
||||
struct GPUBall
|
||||
{
|
||||
public float factor;
|
||||
public Vector3 position;
|
||||
}
|
||||
|
||||
this.init();
|
||||
}
|
||||
struct GPUEdgeVertices
|
||||
{
|
||||
public int index;
|
||||
public Vector3 edge0, edge1, edge2, edge3, edge4, edge5, edge6, edge7, edge8, edge9, edge10, edge11;
|
||||
};
|
||||
|
||||
this.vertices.Clear();
|
||||
|
||||
// write info about metaballs in format readable by compute shaders
|
||||
GPUBall[] gpuBalls = new GPUBall[metaballs.Length];
|
||||
for(int i = 0; i < metaballs.Length; i++) {
|
||||
MetaBall metaball = metaballs[i];
|
||||
gpuBalls[i].position = metaball.transform.localPosition;
|
||||
gpuBalls[i].factor = metaball.factor;
|
||||
}
|
||||
|
||||
// magic happens here
|
||||
GPUEdgeVertices[] edgeVertices = this.runComputeShader(gpuBalls);
|
||||
public class CubeGrid
|
||||
{
|
||||
public List<Vector3> vertices;
|
||||
public readonly int width, height, depth;
|
||||
|
||||
// perform rest of the marching cubes algorithm
|
||||
for (int x = 0; x < this.width; x++)
|
||||
private Container container;
|
||||
|
||||
private ComputeShader shader;
|
||||
private int shaderKernel;
|
||||
|
||||
private ComputeBuffer positionsBuffer;
|
||||
private ComputeBuffer valuesBuffer;
|
||||
private ComputeBuffer metaballsBuffer;
|
||||
private ComputeBuffer edgeMapBuffer;
|
||||
private ComputeBuffer verticesBuffer;
|
||||
|
||||
private GPUPositions[] precomputedPositions;
|
||||
|
||||
private bool initized;
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
|
||||
public CubeGrid(Container container, ComputeShader shader)
|
||||
{
|
||||
for (int y = 0; y < this.height; y++)
|
||||
this.container = container;
|
||||
this.shader = shader;
|
||||
|
||||
this.width = Mathf.RoundToInt(container.transform.localScale.x / this.container.resolutionX);
|
||||
this.height = Mathf.RoundToInt(container.transform.localScale.y / this.container.resolutionY);
|
||||
this.depth = Mathf.RoundToInt(container.transform.localScale.z / this.container.resolutionZ);
|
||||
|
||||
this.vertices = new List<Vector3>(this.width * this.height * this.depth * 3);
|
||||
|
||||
this.initized = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
|
||||
public void evaluateAll(MetaBall[] metaballs)
|
||||
{
|
||||
if (!this.initized)
|
||||
{
|
||||
for (int z = 0; z < this.depth; z++)
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
this.vertices.Clear();
|
||||
|
||||
// write info about metaballs in format readable by compute shaders
|
||||
GPUBall[] gpuBalls = new GPUBall[metaballs.Length];
|
||||
for (int i = 0; i < metaballs.Length; i++)
|
||||
{
|
||||
MetaBall metaball = metaballs[i];
|
||||
gpuBalls[i].position = metaball.transform.localPosition;
|
||||
gpuBalls[i].factor = metaball.factor;
|
||||
}
|
||||
|
||||
// magic happens here
|
||||
GPUEdgeVertices[] edgeVertices = this.runComputeShader(gpuBalls);
|
||||
|
||||
// perform rest of the marching cubes algorithm
|
||||
int hh = 0;
|
||||
for (int x = 0; x < this.width; x++)
|
||||
{
|
||||
for (int y = 0; y < this.height; y++)
|
||||
{
|
||||
this.updateVertices2(edgeVertices[x + this.width * (y + this.height * z)]);
|
||||
for (int z = 0; z < this.depth; z++)
|
||||
{
|
||||
this.updateVertices2(edgeVertices[x + this.width * (y + this.height * z)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int[] getTriangles()
|
||||
{
|
||||
int num = this.vertices.Count;
|
||||
|
||||
}
|
||||
|
||||
public int[] getTriangles() {
|
||||
int num = this.vertices.Count;
|
||||
if (this.triangleBuffer == null)
|
||||
{
|
||||
// nothing in buffer, create it
|
||||
this.triangleBuffer = new List<int>();
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
this.triangleBuffer.Add(i);
|
||||
}
|
||||
|
||||
if(this.triangleBuffer == null) {
|
||||
// nothing in buffer, create it
|
||||
this.triangleBuffer = new List<int>();
|
||||
for(int i = 0; i < num; i++) {
|
||||
this.triangleBuffer.Add(i);
|
||||
return this.triangleBuffer.ToArray();
|
||||
}
|
||||
else if (this.triangleBuffer.Count < num)
|
||||
{
|
||||
// missing elements in buffer, add them
|
||||
for (int i = this.triangleBuffer.Count; i < num; i++)
|
||||
{
|
||||
this.triangleBuffer.Add(i);
|
||||
}
|
||||
|
||||
return this.triangleBuffer.ToArray();
|
||||
} else if(this.triangleBuffer.Count < num) {
|
||||
// missing elements in buffer, add them
|
||||
for(int i = this.triangleBuffer.Count; i < num; i++) {
|
||||
this.triangleBuffer.Add(i);
|
||||
return this.triangleBuffer.ToArray();
|
||||
}
|
||||
else if (this.triangleBuffer.Count == num)
|
||||
{
|
||||
// buffer is of perfect size, just return it
|
||||
|
||||
return this.triangleBuffer.ToArray();
|
||||
} else if(this.triangleBuffer.Count == num) {
|
||||
// buffer is of perfect size, just return it
|
||||
return this.triangleBuffer.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// buffer is too long, return slice
|
||||
|
||||
return this.triangleBuffer.ToArray();
|
||||
} else {
|
||||
// buffer is too long, return slice
|
||||
|
||||
return this.triangleBuffer.GetRange(0, num).ToArray();
|
||||
return this.triangleBuffer.GetRange(0, num).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
this.positionsBuffer.Release();
|
||||
this.valuesBuffer.Release();
|
||||
this.metaballsBuffer.Release();
|
||||
this.edgeMapBuffer.Release();
|
||||
this.verticesBuffer.Release();
|
||||
this.triangleBuffer = null;
|
||||
}
|
||||
public void destroy()
|
||||
{
|
||||
this.positionsBuffer.Release();
|
||||
this.valuesBuffer.Release();
|
||||
this.metaballsBuffer.Release();
|
||||
this.edgeMapBuffer.Release();
|
||||
this.verticesBuffer.Release();
|
||||
this.triangleBuffer = null;
|
||||
}
|
||||
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
|
||||
private void init() {
|
||||
this.instantiateEdgeMap();
|
||||
this.instantiatePositionMap();
|
||||
this.instantiateGPUPositions();
|
||||
this.instantiateComputeShader();
|
||||
private void init()
|
||||
{
|
||||
this.instantiateEdgeMap();
|
||||
this.instantiatePositionMap();
|
||||
this.instantiateGPUPositions();
|
||||
this.instantiateComputeShader();
|
||||
|
||||
this.initized = true;
|
||||
}
|
||||
this.initized = true;
|
||||
}
|
||||
|
||||
private void instantiateEdgeMap() {
|
||||
this.edgeMap = new Vector3[] {
|
||||
private void instantiateEdgeMap()
|
||||
{
|
||||
this.edgeMap = new Vector3[] {
|
||||
new Vector3(-1, -1, -1),
|
||||
new Vector3(1, -1, -1),
|
||||
new Vector3(1, 1, -1),
|
||||
@@ -158,152 +183,185 @@ public class CubeGrid {
|
||||
new Vector3(-1, 1, 1)
|
||||
};
|
||||
|
||||
// scale edge map
|
||||
for(int i = 0; i < 8; i++) {
|
||||
this.edgeMap[i] /= 2;
|
||||
this.edgeMap[i] = new Vector3(this.edgeMap[i].x / ((float) this.width),
|
||||
this.edgeMap[i].y / ((float) this.height),
|
||||
this.edgeMap[i].z / ((float) this.depth));
|
||||
// scale edge map
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
this.edgeMap[i] /= 2;
|
||||
this.edgeMap[i] = new Vector3(this.edgeMap[i].x / ((float)this.width),
|
||||
this.edgeMap[i].y / ((float)this.height),
|
||||
this.edgeMap[i].z / ((float)this.depth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void instantiatePositionMap() {
|
||||
this.positionMap = new Vector3[width,height,depth];
|
||||
private void instantiatePositionMap()
|
||||
{
|
||||
this.positionMap = new Vector3[width, height, depth];
|
||||
|
||||
for(int x = 0; x < this.width; x++) {
|
||||
for(int y = 0; y < this.height; y++) {
|
||||
for(int z = 0; z < this.depth; z++) {
|
||||
for (int x = 0; x < this.width; x++)
|
||||
{
|
||||
for (int y = 0; y < this.height; y++)
|
||||
{
|
||||
for (int z = 0; z < this.depth; z++)
|
||||
{
|
||||
|
||||
float xCoord = (((float) x) / ((float) this.width)) - 0.475f ;
|
||||
float yCoord = (((float) y) / ((float) this.height)) - 0.475f;
|
||||
float zCoord = (((float) z) / ((float) this.depth)) - 0.46f;
|
||||
float xCoord = (((float)x) / ((float)this.width)) - 0.475f;
|
||||
float yCoord = (((float)y) / ((float)this.height)) - 0.475f;
|
||||
float zCoord = (((float)z) / ((float)this.depth)) - 0.46f;
|
||||
|
||||
this.positionMap[x , y , z] = new Vector3(xCoord, yCoord, zCoord);
|
||||
this.positionMap[x, y, z] = new Vector3(xCoord, yCoord, zCoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void instantiateGPUPositions()
|
||||
{
|
||||
this.precomputedPositions = new GPUPositions[this.width * this.height * this.depth];
|
||||
|
||||
for (int x = 0; x < this.width; x++)
|
||||
private void instantiateGPUPositions()
|
||||
{
|
||||
for (int y = 0; y < this.height; y++)
|
||||
this.precomputedPositions = new GPUPositions[this.width * this.height * this.depth];
|
||||
|
||||
for (int x = 0; x < this.width; x++)
|
||||
{
|
||||
for (int z = 0; z < this.depth; z++)
|
||||
for (int y = 0; y < this.height; y++)
|
||||
{
|
||||
Vector3 centerPoint = this.positionMap[x, y, z];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].centerPos = centerPoint;
|
||||
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge0Pos = centerPoint + this.edgeMap[0];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge1Pos = centerPoint + this.edgeMap[1];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge2Pos = centerPoint + this.edgeMap[2];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge3Pos = centerPoint + this.edgeMap[3];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge4Pos = centerPoint + this.edgeMap[4];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge5Pos = centerPoint + this.edgeMap[5];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge6Pos = centerPoint + this.edgeMap[6];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge7Pos = centerPoint + this.edgeMap[7];
|
||||
}
|
||||
for (int z = 0; z < this.depth; z++)
|
||||
{
|
||||
Vector3 centerPoint = this.positionMap[x, y, z];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].centerPos = centerPoint;
|
||||
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge0Pos = centerPoint + this.edgeMap[0];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge1Pos = centerPoint + this.edgeMap[1];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge2Pos = centerPoint + this.edgeMap[2];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge3Pos = centerPoint + this.edgeMap[3];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge4Pos = centerPoint + this.edgeMap[4];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge5Pos = centerPoint + this.edgeMap[5];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge6Pos = centerPoint + this.edgeMap[6];
|
||||
this.precomputedPositions[x + this.width * (y + this.height * z)].edge7Pos = centerPoint + this.edgeMap[7];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void instantiateComputeShader() {
|
||||
// setup buffers
|
||||
this.positionsBuffer = new ComputeBuffer(this.precomputedPositions.Length, 108);
|
||||
this.positionsBuffer.SetData(this.precomputedPositions);
|
||||
private void instantiateComputeShader()
|
||||
{
|
||||
// setup buffers
|
||||
this.positionsBuffer = new ComputeBuffer(this.precomputedPositions.Length, 108);
|
||||
this.positionsBuffer.SetData(this.precomputedPositions);
|
||||
|
||||
this.edgeMapBuffer = new ComputeBuffer(8, 12);
|
||||
this.edgeMapBuffer.SetData(this.edgeMap);
|
||||
this.edgeMapBuffer = new ComputeBuffer(8, 12);
|
||||
this.edgeMapBuffer.SetData(this.edgeMap);
|
||||
|
||||
this.verticesBuffer = new ComputeBuffer(this.precomputedPositions.Length, 148);
|
||||
this.metaballsBuffer = new ComputeBuffer(this.precomputedPositions.Length, 16);
|
||||
this.verticesBuffer = new ComputeBuffer(this.precomputedPositions.Length, 148);
|
||||
this.metaballsBuffer = new ComputeBuffer(this.precomputedPositions.Length, 16);
|
||||
|
||||
// and assign them to compute shader buffer
|
||||
this.shaderKernel = this.shader.FindKernel("Calculate");
|
||||
// and assign them to compute shader buffer
|
||||
this.shaderKernel = this.shader.FindKernel("Calculate");
|
||||
|
||||
this.shader.SetBuffer(this.shaderKernel, "positions", this.positionsBuffer);
|
||||
this.shader.SetBuffer(this.shaderKernel, "metaballs", this.metaballsBuffer);
|
||||
this.shader.SetBuffer(this.shaderKernel, "edgeMap", this.edgeMapBuffer);
|
||||
this.shader.SetBuffer(this.shaderKernel, "edgeVertices", this.verticesBuffer);
|
||||
}
|
||||
|
||||
//
|
||||
// GPU metaball falloff function summator & part of marching cubes algorithm
|
||||
//
|
||||
|
||||
private GPUEdgeVertices[] runComputeShader(GPUBall[] gpuBalls) {
|
||||
// pass data to the compute shader
|
||||
this.metaballsBuffer.SetData(gpuBalls);
|
||||
this.shader.SetInt("numMetaballs", gpuBalls.Length);
|
||||
this.shader.SetInt("width", this.width);
|
||||
this.shader.SetInt("height", this.height);
|
||||
this.shader.SetFloat("threshold", this.container.threshold);
|
||||
|
||||
// Run, Forrest, run!
|
||||
this.shader.Dispatch(this.shaderKernel, this.width, this.height / 8, this.depth / 8);
|
||||
|
||||
// parse returned vertex data and return it
|
||||
GPUEdgeVertices[] output = new GPUEdgeVertices[this.verticesBuffer.count];
|
||||
this.verticesBuffer.GetData(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
//
|
||||
// Rest of marching cubes algorithm (on CPU)
|
||||
//
|
||||
|
||||
private void updateVertices2(GPUEdgeVertices vert) {
|
||||
int cubeIndex = vert.index;
|
||||
|
||||
for(int k = 0; triTable[cubeIndex][k] != -1; k += 3) {
|
||||
this.vertices.Add(this.findVertex(vert, this.triTable[cubeIndex][k]));
|
||||
this.vertices.Add(this.findVertex(vert, this.triTable[cubeIndex][k + 2]));
|
||||
this.vertices.Add(this.findVertex(vert, this.triTable[cubeIndex][k + 1]));
|
||||
this.shader.SetBuffer(this.shaderKernel, "positions", this.positionsBuffer);
|
||||
this.shader.SetBuffer(this.shaderKernel, "metaballs", this.metaballsBuffer);
|
||||
this.shader.SetBuffer(this.shaderKernel, "edgeMap", this.edgeMapBuffer);
|
||||
this.shader.SetBuffer(this.shaderKernel, "edgeVertices", this.verticesBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 findVertex(GPUEdgeVertices vert, int i) {
|
||||
if(i == 0) {
|
||||
return vert.edge0;
|
||||
} else if(i == 1) {
|
||||
return vert.edge1;
|
||||
} else if(i == 2) {
|
||||
return vert.edge2;
|
||||
} else if(i == 3) {
|
||||
return vert.edge3;
|
||||
} else if(i == 4) {
|
||||
return vert.edge4;
|
||||
} else if(i == 5) {
|
||||
return vert.edge5;
|
||||
} else if(i == 6) {
|
||||
return vert.edge6;
|
||||
} else if(i == 7) {
|
||||
return vert.edge7;
|
||||
} else if(i == 8) {
|
||||
return vert.edge8;
|
||||
} else if(i == 9) {
|
||||
return vert.edge9;
|
||||
} else if(i == 10) {
|
||||
return vert.edge10;
|
||||
} else {
|
||||
return vert.edge11;
|
||||
//
|
||||
// GPU metaball falloff function summator & part of marching cubes algorithm
|
||||
//
|
||||
|
||||
private GPUEdgeVertices[] runComputeShader(GPUBall[] gpuBalls)
|
||||
{
|
||||
// pass data to the compute shader
|
||||
this.metaballsBuffer.SetData(gpuBalls);
|
||||
this.shader.SetInt("numMetaballs", gpuBalls.Length);
|
||||
this.shader.SetInt("width", this.width);
|
||||
this.shader.SetInt("height", this.height);
|
||||
this.shader.SetFloat("threshold", this.container.threshold);
|
||||
|
||||
// Run, Forrest, run!
|
||||
this.shader.Dispatch(this.shaderKernel, this.width, this.height, this.depth);
|
||||
|
||||
// parse returned vertex data and return it
|
||||
GPUEdgeVertices[] output = new GPUEdgeVertices[this.verticesBuffer.count];
|
||||
this.verticesBuffer.GetData(output);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LOOKUP TABLES
|
||||
//
|
||||
//
|
||||
// Rest of marching cubes algorithm (on CPU)
|
||||
//
|
||||
|
||||
private List<int> triangleBuffer;
|
||||
private void updateVertices2(GPUEdgeVertices vert)
|
||||
{
|
||||
int cubeIndex = vert.index;
|
||||
|
||||
private Vector3[,,] positionMap;
|
||||
for (int k = 0; triTable[cubeIndex][k] != -1; k += 3)
|
||||
{
|
||||
this.vertices.Add(this.findVertex(vert, CubeGrid.triTable[cubeIndex][k]));
|
||||
this.vertices.Add(this.findVertex(vert, CubeGrid.triTable[cubeIndex][k + 2]));
|
||||
this.vertices.Add(this.findVertex(vert, CubeGrid.triTable[cubeIndex][k + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3[] edgeMap;
|
||||
|
||||
private int[][] triTable = {
|
||||
private Vector3 findVertex(GPUEdgeVertices vert, int i)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return vert.edge0;
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
return vert.edge1;
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
return vert.edge2;
|
||||
}
|
||||
else if (i == 3)
|
||||
{
|
||||
return vert.edge3;
|
||||
}
|
||||
else if (i == 4)
|
||||
{
|
||||
return vert.edge4;
|
||||
}
|
||||
else if (i == 5)
|
||||
{
|
||||
return vert.edge5;
|
||||
}
|
||||
else if (i == 6)
|
||||
{
|
||||
return vert.edge6;
|
||||
}
|
||||
else if (i == 7)
|
||||
{
|
||||
return vert.edge7;
|
||||
}
|
||||
else if (i == 8)
|
||||
{
|
||||
return vert.edge8;
|
||||
}
|
||||
else if (i == 9)
|
||||
{
|
||||
return vert.edge9;
|
||||
}
|
||||
else if (i == 10)
|
||||
{
|
||||
return vert.edge10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return vert.edge11;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LOOKUP TABLES
|
||||
//
|
||||
|
||||
private List<int> triangleBuffer;
|
||||
|
||||
private Vector3[,,] positionMap;
|
||||
|
||||
private Vector3[] edgeMap;
|
||||
|
||||
static private readonly int[][] triTable = {
|
||||
new int[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
new int[] {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
new int[] {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
@@ -561,4 +619,5 @@ public class CubeGrid {
|
||||
new int[] {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
new int[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class MetaBall : MonoBehaviour {
|
||||
public float radius = 0.09f;
|
||||
public bool negativeBall;
|
||||
|
||||
[HideInInspector]
|
||||
public float factor = 1;
|
||||
Vector3 voidSize;
|
||||
|
||||
public bool DrawGizmos;
|
||||
|
||||
public virtual void OnDrawGizmos()
|
||||
namespace MetaBalls
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class MetaBall : MonoBehaviour
|
||||
{
|
||||
if (!DrawGizmos)
|
||||
return;
|
||||
public float radius = 0.09f;
|
||||
public bool negativeBall;
|
||||
|
||||
if(voidSize != GetComponentInParent<Container>().transform.localScale)
|
||||
[HideInInspector]
|
||||
public float factor = 1;
|
||||
Vector3 voidSize;
|
||||
|
||||
public bool DrawGizmos;
|
||||
|
||||
public virtual void OnDrawGizmos()
|
||||
{
|
||||
voidSize = GetComponentInParent<Container>().transform.localScale;
|
||||
if (!DrawGizmos)
|
||||
return;
|
||||
|
||||
if (voidSize != GetComponentInParent<Container>().transform.localScale)
|
||||
{
|
||||
voidSize = GetComponentInParent<Container>().transform.localScale;
|
||||
}
|
||||
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(transform.position, radius * Mathf.Min(voidSize.x, voidSize.y, voidSize.z));
|
||||
}
|
||||
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(transform.position, radius * Mathf.Min(voidSize.x, voidSize.y, voidSize.z));
|
||||
}
|
||||
public virtual void Start()
|
||||
{
|
||||
this.factor = (this.negativeBall ? -1 : 1) * this.radius * this.radius;
|
||||
}
|
||||
|
||||
public virtual void Start() {
|
||||
this.factor = (this.negativeBall ? -1 : 1) * this.radius * this.radius;
|
||||
}
|
||||
|
||||
public virtual void Update()
|
||||
{
|
||||
this.factor = (this.negativeBall ? -1 : 1) * this.radius * this.radius;
|
||||
public virtual void Update()
|
||||
{
|
||||
this.factor = (this.negativeBall ? -1 : 1) * this.radius * this.radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ RWStructuredBuffer<Vertices> edgeVertices;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int numMetaballs;
|
||||
|
||||
float threshold;
|
||||
@@ -176,12 +177,26 @@ Values zeroValuesStruct() {
|
||||
// field function evaluation
|
||||
//
|
||||
|
||||
float QuakeFastSqrt(float original_number)
|
||||
{
|
||||
float orig_half = 0.5f * original_number;
|
||||
|
||||
int i = (int) original_number;
|
||||
i = 0x5f3759df - (i >> 1);
|
||||
|
||||
original_number = (float)i;
|
||||
original_number = original_number * ( 1.5f - ( orig_half * original_number * original_number));
|
||||
return original_number;
|
||||
|
||||
}
|
||||
|
||||
float metaballFalloffFunction(float factor, float3 dist) {
|
||||
#ifdef GENERIC_METABALL_FUNCTION
|
||||
return factor / (dist.x * dist.x + dist.y * dist.y + dist.z * dist.z);
|
||||
#endif
|
||||
#ifdef ELECTRIC_POTENTIAL_FUNCTION
|
||||
return 8.987551788e9 * factor / sqrt(dist.x * dist.x + dist.y * dist.y + dist.z * dist.z);
|
||||
//return 8.987551788e9 * factor / sqrt(dist.x * dist.x + dist.y * dist.y + dist.z * dist.z);
|
||||
return 8.987551788e9 * factor / QuakeFastSqrt(dist.x * dist.x + dist.y * dist.y + dist.z * dist.z);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -223,8 +238,11 @@ Values evaluateFieldFunction(int pos) {
|
||||
|
||||
[numthreads(8,8,8)]
|
||||
void Calculate(uint3 id : SV_DispatchThreadID) {
|
||||
|
||||
|
||||
int pos = id.x + width * (id.y + height * id.z);
|
||||
|
||||
|
||||
// find scalar values of a field on this position
|
||||
Values edgeValues = evaluateFieldFunction(pos);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user