Initial Commit
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
/*=========================================================================
|
||||
|
||||
Library: iMSTK-Unity
|
||||
|
||||
Copyright (c) Kitware, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
=========================================================================*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace ImstkUnity
|
||||
{
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
/// <summary>
|
||||
/// This component represents connective tissue as a multitude of strands between
|
||||
/// opposing surfaces.
|
||||
/// </summary>
|
||||
/// Given two opposing geometries strands will be generated with
|
||||
/// configurable parameters. The generated object is physical and can be interacted
|
||||
/// with. The connective tissue will consist of multiple "strands" each going from
|
||||
/// one of the reference objects to the other. Each strand will be made up of the give
|
||||
/// number of segments. The amount of strands is roughly NumberOfFaces(ObjectA) * strandsPerFace
|
||||
/// Note that increasing the density and/or the number of segments per strand will also
|
||||
/// increase the computational load to simulation this object.
|
||||
public class ConnectiveTissue : DynamicalModel
|
||||
{
|
||||
/// <value>objectA and deformable are the objects that delimit the connective tissue</value>
|
||||
public Deformable objectA;
|
||||
public Deformable objectB;
|
||||
|
||||
/// <value>
|
||||
/// <c>maxDistance</c> represents the maximum distance between A and B where conn
|
||||
/// connective tissue will be generated
|
||||
/// </value>
|
||||
public double maxDistance = 10;
|
||||
|
||||
/// <value>
|
||||
/// <c>strandsPerFace</c> indicates the amount of strands total number will be roughly
|
||||
/// NumberOfFaces(ObjectA) * strandsPerFace
|
||||
/// </value>
|
||||
public double strandsPerFace = 2.0;
|
||||
|
||||
/// <value>
|
||||
/// <c>segmentsPerStrand</c> indicates how many subdivisions each strand has
|
||||
/// </value>
|
||||
public int segmentsPerStrand = 2;
|
||||
|
||||
/// <value>
|
||||
/// <c>distanceStiffness</c> how much (or little) give the connective tissue has (0-infinity)
|
||||
/// </value>
|
||||
public double distanceStiffness = 10;
|
||||
|
||||
public double uniformMassValue = 0.1;
|
||||
|
||||
public double viscousDampingCoeff = 0.01;
|
||||
|
||||
private Mesh _mesh;
|
||||
private MeshFilter _meshFilter;
|
||||
private MeshRenderer _meshRenderer;
|
||||
|
||||
private Imstk.PbdObject _connectiveTissue;
|
||||
private bool _needUV = true;
|
||||
|
||||
private Vector3[] _normals;
|
||||
private Vector3[] _vertices;
|
||||
private Vector4[] _tangents;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private Imstk.LineMesh _editorCollisionMesh;
|
||||
#endif
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_meshFilter = GetComponent<MeshFilter>();
|
||||
_meshRenderer = GetComponent<MeshRenderer>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
if (objectA == null || objectB == null)
|
||||
{
|
||||
Debug.LogError("Connective Tissue needs two objects to span");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnImstkInit()
|
||||
{
|
||||
if (_connectiveTissue != null) return;
|
||||
|
||||
objectA.ImstkInit();
|
||||
objectB.ImstkInit();
|
||||
|
||||
var aPbdObject = objectA.GetDynamicObject() as Imstk.PbdObject;
|
||||
var bPbdObject = objectB.GetDynamicObject() as Imstk.PbdObject;
|
||||
|
||||
// HS 20230201 TODO can't pass mass and distStiffness as we don't have proximitySelector wrapped
|
||||
_connectiveTissue = Imstk.Utils.makeConnectiveTissue(aPbdObject, bPbdObject, SimulationManager.pbdModel,
|
||||
maxDistance, strandsPerFace, segmentsPerStrand);
|
||||
|
||||
// Superclass object
|
||||
imstkObject = _connectiveTissue;
|
||||
|
||||
var visualGeometry = Imstk.Utils.CastTo<Imstk.PointSet>(_connectiveTissue.getPhysicsGeometry());
|
||||
_mesh = new Mesh();
|
||||
_mesh.name = "Connective Tissue Mesh (Imstk)";
|
||||
_mesh.MarkDynamic();
|
||||
GeomUtil.CopyMesh(visualGeometry.ToMesh(), _mesh);
|
||||
_meshFilter.mesh = _mesh;
|
||||
|
||||
var config = SimulationManager.pbdModel.getConfig();
|
||||
config.enableConstraint(Imstk.PbdModelConfig.ConstraintGenType.Distance, distanceStiffness,
|
||||
_connectiveTissue.getPbdBody().bodyHandle);
|
||||
config.m_linearDampingCoeff = viscousDampingCoeff;
|
||||
//_connectiveTissue.getPbdBody().uniformMassValue = uniformMassValue;
|
||||
|
||||
SimulationManager.pbdModel.configure(config);
|
||||
|
||||
// TODO refactor to move to simulation _manager
|
||||
SimulationManager.sceneManager.getActiveScene().addSceneObject(GetSceneObject());
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var geometry = Imstk.Utils.CastTo<Imstk.LineMesh>(_connectiveTissue.getPhysicsGeometry());
|
||||
|
||||
_vertices = MathUtil.ToVector3Array(geometry.getVertexPositions());
|
||||
|
||||
_mesh.vertices = _vertices;
|
||||
if (_mesh.vertexCount > 0 && _needUV)
|
||||
{
|
||||
GenerateUVAndNormals(_mesh);
|
||||
}
|
||||
|
||||
if (dynamicGeometry)
|
||||
{
|
||||
int[] indices = MathUtil.ToIntArray(geometry.getLinesIndices());
|
||||
_mesh.SetIndices(indices, MeshTopology.Lines, 0);
|
||||
}
|
||||
|
||||
_mesh.RecalculateBounds();
|
||||
UpdateNormals(_mesh);
|
||||
_mesh.MarkModified();
|
||||
}
|
||||
|
||||
public Imstk.SceneObject GetSceneObject()
|
||||
{
|
||||
return Imstk.Utils.CastTo<Imstk.SceneObject>(_connectiveTissue);
|
||||
}
|
||||
|
||||
|
||||
private void GenerateUVAndNormals(Mesh mesh)
|
||||
{
|
||||
var vertices = mesh.vertices;
|
||||
var uvs = new Vector2[vertices.Length];
|
||||
_normals = new Vector3[vertices.Length];
|
||||
_tangents = new Vector4[vertices.Length];
|
||||
|
||||
int pointsPerStrand = segmentsPerStrand + 1;
|
||||
for (int strand = 0; strand < mesh.vertices.Length / pointsPerStrand; ++strand)
|
||||
{
|
||||
float rand = Random.Range(0.1f, 0.9f);
|
||||
for (int i = 0; i < pointsPerStrand; ++i)
|
||||
{
|
||||
Vector3 dir;
|
||||
var index = strand * pointsPerStrand + i;
|
||||
if (i < pointsPerStrand - 1)
|
||||
{
|
||||
dir = vertices[index + 1] - vertices[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = vertices[index] - vertices[index - 1];
|
||||
}
|
||||
|
||||
uvs[index] = new Vector2(rand, (float)i / (float)pointsPerStrand);
|
||||
|
||||
// For now just connect through the origin
|
||||
_normals[index] = vertices[index].normalized;
|
||||
|
||||
// Just a guess for now
|
||||
Vector3 tangent = Vector3.Cross(_normals[index], dir).normalized;
|
||||
_tangents[index] = new Vector4(tangent.x, tangent.y, tangent.z, -1);
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetUVs(0, uvs);
|
||||
mesh.SetNormals(_normals);
|
||||
mesh.SetTangents(_tangents);
|
||||
_needUV = false;
|
||||
}
|
||||
|
||||
private void UpdateNormals(Mesh mesh)
|
||||
{
|
||||
int pointsPerStrand = segmentsPerStrand + 1;
|
||||
|
||||
Vector3 dir;
|
||||
Vector4 tangent;
|
||||
for (int strand = 0; strand < _vertices.Length / pointsPerStrand; ++strand)
|
||||
{
|
||||
for (int i = 0; i < pointsPerStrand; ++i)
|
||||
{
|
||||
|
||||
var index = strand * pointsPerStrand + i;
|
||||
if (i < pointsPerStrand - 1)
|
||||
{
|
||||
dir = _vertices[index + 1] - _vertices[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = _vertices[index] - _vertices[index - 1];
|
||||
}
|
||||
|
||||
_normals[index] = _vertices[index].normalized;
|
||||
|
||||
// Just a guess for now
|
||||
tangent = Vector3.Cross(_normals[index], dir).normalized;
|
||||
_tangents[index].x = tangent.x;
|
||||
_tangents[index].y = tangent.y;
|
||||
_tangents[index].z = tangent.x;
|
||||
}
|
||||
}
|
||||
mesh.SetNormals(_normals);
|
||||
mesh.SetTangents(_tangents);
|
||||
}
|
||||
|
||||
protected override Imstk.CollidingObject InitObject()
|
||||
{
|
||||
return imstkObject;
|
||||
}
|
||||
|
||||
protected override void Configure()
|
||||
{
|
||||
// Don't need this for connective tissue
|
||||
}
|
||||
|
||||
protected override void InitGeometry()
|
||||
{
|
||||
// Don't need this for connective tissue
|
||||
}
|
||||
|
||||
public override Imstk.Geometry GetVisualGeometry()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override Imstk.Geometry GetPhysicsGeometry()
|
||||
{
|
||||
return _connectiveTissue.getPhysicsGeometry();
|
||||
}
|
||||
public override Imstk.Geometry GetCollidingGeometry()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// Editor only, provide the _editorCollisionMesh for
|
||||
// the purpose of detecting the collision type
|
||||
if (_connectiveTissue != null)
|
||||
{
|
||||
return _connectiveTissue.getCollidingGeometry();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_editorCollisionMesh == null)
|
||||
{
|
||||
_editorCollisionMesh = new Imstk.LineMesh();
|
||||
}
|
||||
return _editorCollisionMesh;
|
||||
}
|
||||
#else
|
||||
if (_connectiveTissue != null)
|
||||
{
|
||||
return _connectiveTissue.getCollidingGeometry();
|
||||
}
|
||||
else return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user