Initial Commit

This commit is contained in:
2025-07-04 20:33:06 +03:00
commit 8f09347ae0
9219 changed files with 2447903 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
/*=========================================================================
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
{
[AddComponentMenu("iMSTK/BoundaryCondition")]
/// <summary>
/// Use this behavior to mark vertices on a deformable object as `fixed`.
/// </summary>
/// This means they won't move but are still part of the overall system.
/// In general this will mean that the object will be attached to the points
/// selected. As the shape assigned can be any mesh this is an easy way to fix
/// an object in space. To indicate which points should be you can use any unity
/// Boundary condition points are considered to have infinite mass, this may cause
/// issues with collision response, prefer the "Constraint" behaviors over this one.
public class BoundaryCondition : MonoBehaviour
{
public GameObject bcObj = null;
public bool hideMesh = true;
void Start()
{
var renderer = bcObj.GetComponent<MeshRenderer>();
if (renderer != null && hideMesh)
{
renderer.enabled = false;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf8aea0333eb6ef45a80749e21dc3e65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+289
View File
@@ -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
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bff9fbc647133d24f81f32d47c01d429
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,133 @@
/*=========================================================================
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 System.Collections.Generic;
using UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// This will set up a set of distance constraints between two deformable objects.
/// </summary>
/// The constraints will be limited to the area encompassed by the assigned mesh
/// constraints will be generated for _all_ pairs of points whose distance is smaller than
/// or equal the cutoff distance.The length of the constraint will be set to
/// the original distance * restLength. Use this if you want to attach a deformable
/// to another deformable. E.g. a vessel to another organ.
public class ConstrainDeformables : ImstkBehaviour
{
public Deformable objectA = null;
public Deformable objectB = null;
[Tooltip("Area that is searched for points")]
public MeshFilter constrainedArea = null;
[Tooltip("Hides the constraining mesh")]
public bool hideMesh = true;
[Tooltip("Ignore points that are farther apart than `cutoff`")]
public float cutoff = 0.01f;
[Tooltip("Affects the resting length of the constraint")]
[Min(0)]
public float restLengthFactor = 0.0f;
[Tooltip("How stiff this constraint should be")]
[Min(0)]
public float stiffness = 1.0e5f;
void Start()
{
var renderer = constrainedArea.gameObject.GetComponent<MeshRenderer>();
if (renderer != null && hideMesh)
{
renderer.enabled = false;
}
}
// Needs to run after objectA and deformable have been initialized
protected override void OnImstkStart()
{
if (!isActiveAndEnabled) return;
if (objectA == null || !objectA.isActiveAndEnabled || objectB == null || !objectB.isActiveAndEnabled ||
constrainedArea == null)
{
enabled = false;
Debug.Log(name + " disabled due to missing or disabled dependency.");
return;
}
ImstkMesh bcGeometry = constrainedArea.sharedMesh.ToImstkMesh(constrainedArea.transform.localToWorldMatrix);
Imstk.SurfaceMesh bcImstkGeometry = bcGeometry.ToImstkGeometry() as Imstk.SurfaceMesh;
Imstk.Geometry geomA = (objectA.GetDynamicObject() as Imstk.PbdObject).getPhysicsGeometry();
var pointsA = GeomUtil.PointsInside(bcImstkGeometry, Imstk.Utils.CastTo<Imstk.PointSet>(geomA));
Imstk.Geometry geomB = (objectB.GetDynamicObject() as Imstk.PbdObject).getPhysicsGeometry();
var pointsB = GeomUtil.PointsInside(bcImstkGeometry, Imstk.Utils.CastTo<Imstk.PointSet>(geomB));
if (pointsA.Count == 0 || pointsB.Count == 0)
{
Debug.LogWarning("No points in constraint area " + gameObject.name);
}
ConstrainPoints(objectA, pointsA, objectB, pointsB);
}
private void ConstrainPoints(Deformable objectA, List<uint> pointsA, Deformable objectB, List<uint> pointsB)
{
int count = 0;
// NOTE HS - 20230215 need to investigate type conversion for result of .getVertexPosition() etc
// returns a wrapped swig type rather than Vec3d for example
Imstk.Geometry geomA = (objectA.GetDynamicObject() as Imstk.PbdObject).getPhysicsGeometry();
var pointSetA = Imstk.Utils.CastTo<Imstk.PointSet>(geomA);
var verticesA = MathUtil.ToVector3Array(pointSetA.getVertexPositions());
Imstk.Geometry geomB = (objectB.GetDynamicObject() as Imstk.PbdObject).getPhysicsGeometry();
var pointSetB = Imstk.Utils.CastTo<Imstk.PointSet>(geomB);
var verticesB = MathUtil.ToVector3Array(pointSetB.getVertexPositions());
foreach (var indexA in pointsA)
{
var pointA = verticesA[indexA];
foreach(var indexB in pointsB)
{
var pointB = verticesB[indexB];
var dist = (pointB - pointA).sqrMagnitude;
if (dist <= cutoff)
{
var constraint = new Imstk.PbdDistanceConstraint();
var p1 = new Imstk.IntPair((objectA.GetDynamicObject() as Imstk.PbdObject).getPbdBody().bodyHandle, (int)indexA);
var p2 = new Imstk.IntPair((objectB.GetDynamicObject() as Imstk.PbdObject).getPbdBody().bodyHandle, (int)indexB);
constraint.initConstraint(dist * restLengthFactor, p1, p2);
SimulationManager.pbdModel.getConstraints().addConstraint(constraint);
count++;
}
}
}
Debug.Log(name + " Added " + count.ToString() + " constraints.");
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2d6a9310b1ae3d4e8bf7ad691f4f69e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+157
View File
@@ -0,0 +1,157 @@
/*=========================================================================
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 Imstk;
using System.Collections.Generic;
using UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// This will set up a set of distance constraints between the points of deformable
/// that are found inside the constrained area and virtual points, effectively
/// attaching the deformable to those points in space.
/// </summary>
/// The constraints will be limited to the area encompassed by the assigned mesh
/// constraints will be generated for _all_ points. The length of the constraint will be set to
/// restLength. Use this if you want to attach a deformable to a point in space
/// e.g. Suspend an organ in the body cavity.
public class ConstrainInSpace : ImstkBehaviour
{
public Deformable deformable = null;
[Tooltip("Area that is searched for points")]
public MeshFilter constrainedArea = null;
[Tooltip("Hides the constraining mesh")]
public bool hideMesh = true;
[Tooltip("Affects the resting length of the constraint")]
[Min(0)]
public float restLength = 0.0f;
public float stiffness = 1.0e5f;
public bool runOnStart = true;
List<Imstk.PbdConstraint> _constraints = new List<Imstk.PbdConstraint>();
// Start is called before the first frame update
void Start()
{
var renderer = constrainedArea.gameObject.GetComponent<MeshRenderer>();
if (renderer != null && hideMesh)
{
renderer.enabled = false;
}
}
protected override void OnImstkStart()
{
if (!isActiveAndEnabled) return;
if (deformable == null || !deformable.isActiveAndEnabled ||
constrainedArea == null)
{
enabled = false;
Debug.Log(name + " disabled due to missing or disabled dependency.");
return;
}
if (runOnStart)
{
Constrain();
}
}
public void Constrain()
{
ImstkMesh bcGeometry = constrainedArea.sharedMesh.ToImstkMesh(constrainedArea.transform.localToWorldMatrix);
Imstk.SurfaceMesh bcImstkGeometry = bcGeometry.ToImstkGeometry() as Imstk.SurfaceMesh;
Imstk.Geometry geom = (deformable.GetDynamicObject() as Imstk.PbdObject).getPhysicsGeometry();
var points = PointsInside(bcImstkGeometry, Imstk.Utils.CastTo<Imstk.PointSet>(geom));
if (points.Count == 0)
{
Debug.LogWarning("No points in constraint area " + gameObject.name);
}
ConstrainPoints(deformable, points);
}
public void Release()
{
var model = SimulationManager.pbdModel;
var constraints = model.getConstraints();
foreach (var constraint in _constraints)
{
constraints.removeConstraint(constraint);
}
}
// Refactor to common functions
List<uint> PointsInside(SurfaceMesh enclosingMesh, PointSet sampleMesh)
{
var result = new List<uint>();
// Compute mask of enclosed points
Imstk.SelectEnclosedPoints selectEnclosed = new Imstk.SelectEnclosedPoints();
selectEnclosed.setInputMesh(enclosingMesh);
selectEnclosed.setInputPoints(sampleMesh);
selectEnclosed.setUsePruning(false);
selectEnclosed.update();
Imstk.DataArrayuc isInside = selectEnclosed.getIsInsideMask();
byte[] isInsideBytes = new byte[isInside.size()];
isInside.getValues(isInsideBytes);
for (int i = 0; i < isInsideBytes.Length; i++)
{
if (isInsideBytes[i] == 1)
result.Add((uint)i);
}
return result;
}
private void ConstrainPoints(Deformable deformable, List<uint> points)
{
int count = 0;
Imstk.Geometry geom = (deformable.GetDynamicObject() as Imstk.PbdObject).getPhysicsGeometry();
var pointSet = Imstk.Utils.CastTo<Imstk.PointSet>(geom);
var vertices = MathUtil.ToVector3Array(pointSet.getVertexPositions());
var model = SimulationManager.pbdModel;
Vec3d zero = new Vec3d(0, 0, 0);
foreach(var indexB in points)
{
var pointB = vertices[indexB].ToImstkVec();
var p1 = model.addVirtualParticle(pointB, 0, zero, true);
var constraint = new Imstk.PbdDistanceConstraint();
var p2 = new Imstk.IntPair((deformable.GetDynamicObject() as Imstk.PbdObject).getPbdBody().bodyHandle, (int)indexB);
constraint.initConstraint(restLength, p1, p2);
constraint.setStiffness(stiffness);
model.getConstraints().addConstraint(constraint);
_constraints.Add(constraint);
count++;
}
Debug.Log(name + " Added " + count.ToString() + " constraints.");
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2cb80ed1cc676ca49879918dcfce3566
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a529bbd4ff961aa4088136c67013adab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,31 @@
/*=========================================================================
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
{
public abstract class ImstkControllerBehaviour : MonoBehaviour
{
public TrackingDevice device = null;
public abstract Imstk.DeviceControl GetController();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 698941b5df545604d963b6ae514eebcf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,167 @@
/*=========================================================================
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
{
/// <summary>
/// Object used between a device handled by the user and a ``Rigid``.
/// </summary>
/// It utilizes a mass spring system to correct for latency in the system.
/// It corrects for problems with haptics in simulation systems. By manipulating
/// the spring parameters the haptic response can be tuned to the behavior of
/// the computer and the simulated system.
[AddComponentMenu("iMSTK/RigidController")]
public class RigidController : ImstkControllerBehaviour
{
Imstk.PbdObjectController controller = null;
public Rigid rigid = null;
public double angularKd = 50.0;
public double angularKs = 1000.0;
public double linearKd = 100.0;
public double linearKs = 10000.0;
public bool useCriticalDamping = true;
public double forceScale = 0.00001;
public bool useForceSmoothing = true;
public int forceSmoothingKernelSize = 15;
// All these transforms below could really just be one
public Vector3 attachmentPoint = Vector3.zero;
public Vector3 translationalOffset = Vector3.zero;
public Quaternion rotationalOffset = Quaternion.identity;
public Quaternion localRotationalOffset = Quaternion.identity;
public double translationScaling = 1;
// Unity uses LHS, while imstk uses RHS, invert X positional
public bool invertX = false;
public bool invertY = false;
public bool invertZ = true;
// Unity uses LHS, while imstk uses RHS, invert Y,Z planes
public bool invertRotX = true;
public bool invertRotY = true;
public bool invertRotZ = false;
public bool debugController = false;
#if UNITY_EDITOR
// These are used to drive the editor foldouts
public bool _forceFoldout = false;
public bool _offsetFoldout = false;
public bool _axisMappingFoldout = false;
#endif
public Vector3 GetPosition()
{
Imstk.Vec3d pos = controller.getPosition();
return pos.ToUnityVec();
}
public Quaternion GetOrientation()
{
Imstk.Quatd quat = controller.getOrientation();
return quat.ToUnityQuat();
}
public override Imstk.DeviceControl GetController()
{
if (device == null)
{
Debug.LogError("Failed to create controller, no device given");
return null;
}
if (rigid == null)
{
Debug.LogError("Failed to create controller, no controlled object given");
return null;
}
if (controller != null)
{
return controller;
}
controller = new Imstk.PbdObjectController(gameObject.name);
controller.setControlledObject(rigid.GetDynamicObject());
controller.setDevice(device.GetDevice());
controller.setAngularKd(angularKd);
controller.setAngularKs(angularKs);
controller.setLinearKd(linearKd);
controller.setLinearKs(linearKs);
controller.setUseCritDamping(useCriticalDamping);
controller.setForceScaling(forceScale);
controller.setUseForceSmoothening(useForceSmoothing);
controller.setSmoothingKernelSize(forceSmoothingKernelSize);
controller.setHapticOffset(attachmentPoint.ToImstkVec());
;
controller.setTranslationOffset((translationalOffset + transform.TransformDirection(attachmentPoint)).ToImstkVec());
controller.setRotationOffset(rotationalOffset.ToImstkQuat());
controller.setEffectorRotationOffset(localRotationalOffset.ToImstkQuat());
controller.setTranslationScaling(translationScaling);
Imstk.TrackingDeviceControl.InvertFlag invertFlag = 0x00;
if (invertX)
{
invertFlag = invertFlag | Imstk.TrackingDeviceControl.InvertFlag.transX;
}
if (invertY)
{
invertFlag = invertFlag | Imstk.TrackingDeviceControl.InvertFlag.transY;
}
if (invertZ)
{
invertFlag = invertFlag | Imstk.TrackingDeviceControl.InvertFlag.transZ;
}
if (invertRotX)
{
invertFlag = invertFlag | Imstk.TrackingDeviceControl.InvertFlag.rotX;
}
if (invertRotY)
{
invertFlag = invertFlag | Imstk.TrackingDeviceControl.InvertFlag.rotY;
}
if (invertRotZ)
{
invertFlag = invertFlag | Imstk.TrackingDeviceControl.InvertFlag.rotZ;
}
controller.setInversionFlags((byte)invertFlag);
return controller;
}
#if UNITY_EDITOR
// Leaving this on in the built version causes unexpected behavior
public void Update()
{
if (debugController)
{
gameObject.transform.SetPositionAndRotation(GetPosition(), GetOrientation());
}
}
#endif
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 170eeb0fc124ca24f9d638781ae042cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+188
View File
@@ -0,0 +1,188 @@
/*=========================================================================
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 System.Collections.Generic;
using UnityEngine;
namespace ImstkUnity
{
[AddComponentMenu("iMSTK/Deformable")]
/// <summary>
/// Use this to represent deformable objects. Position Based Dynamics (PBD),
/// is used to model the deformation.
/// </summary>
/// This model supports Lines (1D), Surface Meshes (2D) and, Tetrahedral Meshes (3D)
/// dynamical models see the iMSTK Documentation <https://imstk.gitlab.io/Dynamical_Models/PbdModel.html>
/// for more information on constraints and models. Visual, physics and collision
/// geometry can be assigned separately. If you do, a separate map will be necessary
/// to update the various meshes.
/// The physics geometry determines the type of constraint that can be used,
/// an invalid constraint may cause problems.
/// | Physics Geometry Type | Valid Constraints |
/// | --------------------- | ----------------- |
/// | Line Mesh(Threads) | Distance Stiffness, Bend Stiffness |
/// | Surface Mesh(Membranes, Bags) | Distance Stiffness, Dihedral Stiffness, Area Stiffness |
/// | Volumetric Mesh(Tissue) | Distance Stiffness, Volume Stiffness, Fem(all models) |
public class Deformable : DeformableModel
{
public double distanceStiffness = 100.0;
public bool useDistanceConstraint = true;
public double dihedralStiffness = 10.0;
public bool useDihedralConstraint = true;
public double areaStiffness = 10.0;
public bool useAreaConstraint = true;
public double bendStiffness = 10.0;
public int maxBendStride = 2;
public bool useBendConstraint = false;
public double volumeStiffness = 10.0;
public bool useVolumeConstraint = false;
public double youngsModulus = 5000.0;
public double possionsRatio = 0.4;
public double mu = 0.0;
public double lambda = 0.0;
public double viscousDampingCoeff = 0.01;
public bool useYoungsModulus = true;
public bool useFEMConstraint = false;
public Imstk.PbdFemConstraint.MaterialType materialType = Imstk.PbdFemConstraint.MaterialType.StVK;
public double uniformMassValue = 1.0;
public HashSet<int> fixedIndices = new HashSet<int>();
public bool useBodyDamping = false;
public double linearDampingCoeff = 0.01;
public double angularDampingCoeff = 0.01;
protected override Imstk.CollidingObject InitObject()
{
Imstk.PbdObject pbdObject = new Imstk.PbdObject(GetFullName());
pbdObject.setDynamicalModel(SimulationManager.pbdModel);
return pbdObject;
}
protected override void Configure()
{
Imstk.PbdModelConfig config = SimulationManager.pbdModel.getConfig();
Imstk.PbdBody pbdBody = (imstkObject as Imstk.PbdObject).getPbdBody();
int bodyHandle = pbdBody.bodyHandle;
if (useDistanceConstraint)
config.enableConstraint(Imstk.PbdModelConfig.ConstraintGenType.Distance, distanceStiffness, bodyHandle);
if (useDihedralConstraint)
config.enableConstraint(Imstk.PbdModelConfig.ConstraintGenType.Dihedral, dihedralStiffness, bodyHandle);
if (useAreaConstraint)
config.enableConstraint(Imstk.PbdModelConfig.ConstraintGenType.Area, areaStiffness, bodyHandle);
if (useVolumeConstraint)
config.enableConstraint(Imstk.PbdModelConfig.ConstraintGenType.Volume, volumeStiffness, bodyHandle);
if (useBendConstraint)
{
for (int i = 1; i <= maxBendStride; i++)
{
config.enableBendConstraint(bendStiffness, i, true, bodyHandle);
}
}
if (useFEMConstraint)
{
if ((imstkObject as Imstk.DynamicObject).getPhysicsGeometry().getTypeName() != "TetrahedralMesh")
{
Debug.Log("Currently only Tetrahedral mesh is supported for FEM constraints");
}
else
{
if (useYoungsModulus)
{
config.m_femParams = new Imstk.PbdFemConstraintConfig(0.0, 0.0, youngsModulus, possionsRatio);
}
else
{
config.m_femParams = new Imstk.PbdFemConstraintConfig(mu, lambda, 0.0, 0.0);
}
config.enableFemConstraint(materialType,bodyHandle);
}
}
if (useBodyDamping)
{
config.setBodyDamping(bodyHandle, linearDampingCoeff, angularDampingCoeff);
}
pbdBody.uniformMassValue = uniformMassValue;
pbdBody.bodyGravity = !ignoreGravity;
var fixedNodes = new Imstk.VectorInt();
foreach (int id in fixedIndices)
{
fixedNodes.Add(id);
}
pbdBody.fixedNodeIds = fixedNodes;
}
protected override void ProcessBoundaryConditions(BoundaryCondition[] conditions)
{
// This model currently uses fixed vertices for BC, this is what we will compute
// Clear them to start with
fixedIndices.Clear();
if (conditions.Length == 0)
return;
// For every BC test intersection to find fixed vertices
foreach (BoundaryCondition condition in conditions)
{
if (!condition.enabled) return;
// Create the surface mesh the points will be tested if inside of
MeshFilter meshFilter = condition.bcObj.GetComponent<MeshFilter>();
Transform transform = condition.bcObj.GetComponent<Transform>();
if (meshFilter == null)
continue;
// Convert unity to imstk geometry
ImstkMesh bcGeometry = meshFilter.sharedMesh.ToImstkMesh(transform.localToWorldMatrix);
Imstk.SurfaceMesh bcImstkGeometry = bcGeometry.ToImstkGeometry() as Imstk.SurfaceMesh;
// Compute mask of enclosed points
Imstk.SelectEnclosedPoints selectEnclosed = new Imstk.SelectEnclosedPoints();
selectEnclosed.setInputMesh(bcImstkGeometry);
Imstk.Geometry physicsGeom = (imstkObject as Imstk.PbdObject).getPhysicsGeometry();
selectEnclosed.setInputPoints(Imstk.Utils.CastTo<Imstk.PointSet>(physicsGeom));
selectEnclosed.setUsePruning(false);
selectEnclosed.update();
Imstk.DataArrayuc isInside = selectEnclosed.getIsInsideMask();
byte[] isInsideBytes = new byte[isInside.size()];
isInside.getValues(isInsideBytes);
for (int i = 0; i < isInsideBytes.Length; i++)
{
if (isInsideBytes[i] == 1)
fixedIndices.Add(i);
}
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8010250de4d49fa4296e91342e4f0907
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+65
View File
@@ -0,0 +1,65 @@
/*=========================================================================
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
{
/// <summary>
/// Allows the use of separate meshes for the deformable, visual and collision representation.
/// </summary>
/// Will move the vertices of the target mesh according to matching points on the source mesh.
/// The points do not have to completely coincide. In almost all cases you will need to map
/// FROM the physics mesh TO the visual mesh, and FROM the physics mesh TO the collision mesh.
[AddComponentMenu("iMSTK/DeformableMap")]
public class DeformableMap : GeometryMap
{
public bool forceOneOne = false;
protected override Imstk.GeometryMap MakeMap()
{
Imstk.Geometry parent = parentGeom.GetOutputGeometry();
Imstk.Geometry child = childGeom.GetOutputGeometry();
if (parentGeom == null || childGeom == null)
{
Debug.LogError("GeometryMap: can't create map when one or more inputs is null");
}
if (!forceOneOne && (parent.getTypeName() == Imstk.TetrahedralMesh.getStaticTypeName()
|| child.getTypeName() == Imstk.TetrahedralMesh.getStaticTypeName()))
{
Debug.Log("Trying to make tetrahedral map with " + parent.getTypeName() + " and " + child.getTypeName());
var map = new Imstk.PointToTetMap(parent, child);
map.compute();
return map;
}
else
{
Debug.Log("Trying to make one to one map with " + parent.getTypeName() + " and " + child.getTypeName());
var map = new Imstk.PointwiseMap(parent, child);
// Tolerance needed to avoid issues with double/float conversions
map.setTolerance(1e-4);
map.compute();
return map;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 127fba25d5cdc4445a9fa44afd5ec2a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+250
View File
@@ -0,0 +1,250 @@
/*=========================================================================
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 Unity.Profiling;
using UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// Used for models with deformable vertices. That is the vertices are changing
/// per update of the model in global configuration.
/// </summary>
public abstract class DeformableModel : DynamicalModel
{
static readonly ProfilerMarker s_UpdatePerfMarker = new ProfilerMarker(ProfilerCategory.Physics, "Imstk.DeformableUpdate");
TimingBuffer _updateTimes = new TimingBuffer(100);
// These filters can accept either imstk or unity geometry input
// and output imstk geometry
public GeometryFilter visualGeomFilter = null;
public GeometryFilter physicsGeomFilter = null;
public GeometryFilter collisionGeomFilter = null;
public bool cleanVisualMesh;
public TimingBuffer UpdateTimes {
get { return _updateTimes; }
}
protected override void OnImstkInit()
{
if (imstkObject != null) return;
// Get dependencies
meshFilter = visualGeomFilter.gameObject.GetComponentFatal<MeshFilter>();
if (meshFilter.mesh == null)
{
meshFilter.mesh = new Mesh();
}
// Make sure mesh filter is read/writable
meshFilter.mesh.MarkDynamic();
if (!meshFilter.mesh.isReadable)
{
Debug.LogError(gameObject.name + "'s MeshFilter Mesh must be readable (check the meshes import settings)");
return;
}
imstkObject = InitObject();
// TODO move to simulation manager
SimulationManager.sceneManager.getActiveScene().addSceneObject(imstkObject);
InitGeometry();
InitGeometryMaps();
ProcessBoundaryConditions(gameObject.GetComponents<BoundaryCondition>());
Configure();
}
protected override void InitGeometry()
{
// Copy all the geometries over to imstk, set the transform and
// apply later. (to avoid applying transform twice *since two
// geometries could point to the same one*)
Imstk.Geometry visualGeom = null;
// Setup the visual geometry
if (visualGeomFilter != null)
{
visualGeom = GetVisualGeometry();
visualGeomFilter.MoveToGlobalSpace();
imstkObject.setVisualGeometry(visualGeom);
}
// Visual geometry is Unity this also means it's either a surface or a line mesh
// For either we do want to clean up the mesh.
// As the indices not going to match after cleanup a map from the (cleaned) physics mesh
// to the visual mesh needs to be added as well
Imstk.Geometry physicsGeom = null;
Imstk.PointwiseMap physicsToUnityMeshMap = null;
if (visualGeomFilter == physicsGeomFilter && cleanVisualMesh)
{
var visualMesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(visualGeom);
Debug.Assert(visualMesh != null);
Debug.Log("Cleaning Mesh");
Debug.Log("Visual Mesh " + visualMesh.getNumVertices() + " vertices");
var cleaner = new Imstk.CleanMesh();
cleaner.setInputMesh(visualMesh);
cleaner.setTolerance(0.001);
cleaner.update();
var physicsMesh = cleaner.getOutputMesh();
physicsGeom = physicsMesh;
Debug.Log("Physics Mesh " + physicsMesh.getNumVertices() + " vertices");
physicsToUnityMeshMap = new Imstk.PointwiseMap(physicsGeom, visualGeom);
// Tolerance needed to avoid issues with double/float conversions
physicsToUnityMeshMap.setTolerance(1e-4);
physicsToUnityMeshMap.compute();
// TODO Should warn the user if the map doesn't actually map any points
(imstkObject as Imstk.DynamicObject).setPhysicsGeometry(physicsGeom);
(imstkObject as Imstk.DynamicObject).getDynamicalModel().setModelGeometry(physicsGeom);
(imstkObject as Imstk.DynamicObject).setPhysicsToVisualMap(physicsToUnityMeshMap);
}
else if (physicsGeomFilter != null)
{
physicsGeom = GetPhysicsGeometry();
physicsGeomFilter.MoveToGlobalSpace();
(imstkObject as Imstk.DynamicObject).setPhysicsGeometry(physicsGeom);
(imstkObject as Imstk.DynamicObject).getDynamicalModel().setModelGeometry(physicsGeom);
}
else
{
Debug.LogError("No physics geometry provided to DynamicalModel on object " + gameObject.name);
}
if (collisionGeomFilter != null)
{
if (visualGeomFilter == collisionGeomFilter && visualGeomFilter == physicsGeomFilter)
{
imstkObject.setCollidingGeometry(physicsGeom);
}
else
{
Imstk.Geometry colGeom = GetCollidingGeometry();
collisionGeomFilter.MoveToGlobalSpace();
imstkObject.setCollidingGeometry(colGeom);
}
}
else
{
Debug.LogError("No collision geometry provided to DynamicalModel on object " + gameObject.name);
}
}
protected void InitGeometryMaps()
{
// Setup any geometry maps on the object
// \todo: Generalize geometry maps in imstk, currently
// well test geometry types to figure out maps
GeometryMap[] geomMaps = gameObject.GetComponents<GeometryMap>();
// \todo: Currently imstk only supports physicstovisual and physicstocollision
// this needs to be generalized. For now we will only support two maps. There are
// some other minute but tricky details to be worked out here.
for (int i = 0; i < geomMaps.Length; i++)
{
GeometryMap map = geomMaps[i];
// Test if map contains physics or visual
if (map.parentGeom == physicsGeomFilter &&
map.childGeom == collisionGeomFilter)
{
Imstk.DynamicObject dynObj = imstkObject as Imstk.DynamicObject;
Imstk.GeometryMap geomMap = map.GetMap();
if (geomMap != null)
{
dynObj.setPhysicsToCollidingMap(geomMap);
Debug.Log("Set up Physics to Collision Map");
geomMap.compute();
}
}
else if (map.parentGeom == physicsGeomFilter &&
map.childGeom == visualGeomFilter)
{
Imstk.DynamicObject dynObj = imstkObject as Imstk.DynamicObject;
Imstk.GeometryMap geomMap = map.GetMap();
if (geomMap != null)
{
dynObj.setPhysicsToVisualMap(geomMap);
Debug.Log("Set up Physics to Visual Map");
geomMap.compute();
}
}
else if (map.parentGeom == collisionGeomFilter &&
map.childGeom == visualGeomFilter)
{
Imstk.GeometryMap geomMap = map.GetMap();
if (geomMap != null)
{
imstkObject.setCollidingToVisualMap(geomMap);
Debug.Log("Set up Physics to Visual Map");
geomMap.compute();
}
}
}
}
/// <summary>
/// Visual update of the geometry (only needs to call before render)
/// </summary>
public void Update()
{
if (SimulationManager.sceneManager == null)
{
Debug.LogWarning("Failed to update dynamical model on " + gameObject.name + " no sceneManager from the SimulationManager");
return;
}
s_UpdatePerfMarker.Begin();
_updateTimes.Begin();
Imstk.PointSet visualGeom = Imstk.Utils.CastTo<Imstk.PointSet>(imstkObject.getVisualGeometry());
meshFilter.mesh.vertices = MathUtil.ToVector3Array(visualGeom.getVertexPositions());
if (meshFilter.mesh.GetTopology(0) == MeshTopology.Triangles ||
meshFilter.mesh.GetTopology(0) == MeshTopology.Quads)
{
meshFilter.mesh.RecalculateNormals();
}
meshFilter.mesh.RecalculateBounds();
_updateTimes.End();
s_UpdatePerfMarker.End();
}
public override Imstk.Geometry GetVisualGeometry()
{
return visualGeomFilter.GetOutputGeometry();
}
public override Imstk.Geometry GetPhysicsGeometry()
{
return physicsGeomFilter.GetOutputGeometry();
}
public override Imstk.Geometry GetCollidingGeometry()
{
return collisionGeomFilter.GetOutputGeometry();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0b6c41fdfe3e6cd488427dbb4c2b5899
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a2bd3c65d7e413c4f99541baad2babac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,129 @@
/*=========================================================================
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;
using System.Threading;
namespace ImstkUnity
{
// HS-2022-feb-02 Should be refactored to remove the "manager" functionality from the
// Device, see the VRPNDevice for the pattern. Remove `static` components
// from here
#if IMSTK_USE_OPENHAPTICS
// If this is not defined iMSTK was not built with Open Haptics enabled
// to use build iMSTK with the flag iMSTK_USE_OpenHaptics set to ON
[AddComponentMenu("iMSTK/OpenHapticsDevice")]
public class OpenHapticsDevice : TrackingDevice
{
public string deviceName = "default";
public static Imstk.OpenHapticDeviceManager openHapticDeviceManager = null;
public static bool hapticsRunning = false;
public static Thread hapticThread = null;
public static void InitManager()
{
if (openHapticDeviceManager != null)
{
openHapticDeviceManager.init();
}
}
public void Start()
{
GetDevice();
}
public static void StartManager()
{
// Launch haptics on a separate thread if using
if (openHapticDeviceManager != null)
{
hapticsRunning = true;
Debug.Log("OpenHaptics Thread Starting");
hapticThread = new Thread(() =>
{
while (hapticsRunning)
{
if (openHapticDeviceManager != null)
{
openHapticDeviceManager.update();
}
}
});
hapticThread.Start();
}
}
public static void StopManager()
{
if (openHapticDeviceManager != null)
{
hapticsRunning = false;
hapticThread.Join();
Debug.Log("OpenHaptics Thread Stopping");
openHapticDeviceManager.uninit();
openHapticDeviceManager = null;
hapticThread = null;
}
}
protected override Imstk.DeviceClient MakeDevice()
{
if (openHapticDeviceManager == null)
{
openHapticDeviceManager = new Imstk.OpenHapticDeviceManager();
}
Debug.Log("MakeDeviceClient <" + deviceName + ">");
// Creates the default device (specify name for specific one)
if (deviceName == "default")
{
return openHapticDeviceManager.makeDeviceClient();
}
else
{
return openHapticDeviceManager.makeDeviceClient(deviceName);
}
}
}
#else
public class OpenHapticsDevice : TrackingDevice
{
public string deviceName = "default";
public static void InitManager()
{
Debug.LogError("OpenHaptics is not enable in this build");
}
public void Start() {}
public static void StartManager() {}
public static void StopManager() {}
protected override Imstk.DeviceClient MakeDevice() {
Debug.LogError("OpenHaptics is not enable in this build, " +
"see the documentation for more information ");
return null;
}
}
#endif
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c8117a352c4c15c4893e11073f5a3a39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,105 @@
/*=========================================================================
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
{
enum ButtonState
{
// From Imstk
BUTTON_RELEASED = 0,
BUTTON_TOUCHED = 1,
BUTTON_UNTOUCHED = 2,
BUTTON_PRESSED = 3
}
public abstract class TrackingDevice : MonoBehaviour
{
Imstk.DeviceClient trackingDevice = null;
public Vector3 GetPosition()
{
Imstk.Vec3d pos = trackingDevice.getPosition();
return pos.ToUnityVec();
}
public Quaternion GetOrientation()
{
Imstk.Quatd quat = trackingDevice.getOrientation();
return quat.ToUnityQuat();
}
public Vector3 GetForce()
{
Imstk.Vec3d vec = trackingDevice.getForce();
return vec.ToUnityVec();
}
public bool IsButtonDown(int id)
{
var val = trackingDevice.getButton(id);
if (val == (int)ButtonState.BUTTON_PRESSED || val == (int)ButtonState.BUTTON_TOUCHED) return true;
else return false;
}
public int[] GetButtons()
{
var result = new int[8];
for (int i = 0; i<8;++i)
{
result[i] = trackingDevice.getButton(i);
}
var b = trackingDevice.getButtons();
return result;
}
public float GetAnalog(int id)
{
var values = trackingDevice.getAnalog();
if (values.Count > id) return (float)values[id];
else
{
Debug.LogWarning("Id " + id.ToString() + " not found ");
return 0;
}
}
protected abstract Imstk.DeviceClient MakeDevice();
public void Update()
{
// This is not directly used, but displayed
Transform transform = gameObject.GetComponentFatal<Transform>();
transform.SetPositionAndRotation(GetPosition(), GetOrientation());
}
public Imstk.DeviceClient GetDevice()
{
if (trackingDevice == null)
{
trackingDevice = MakeDevice();
trackingDevice.setButtonsEnabled(true);
}
return trackingDevice;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c4b75e1c7ff86c46be94008f67ce2e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,57 @@
/*=========================================================================
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
{
[AddComponentMenu("iMSTK/VrpnDevice")]
public class VrpnDevice : TrackingDevice
{
public string Name = "Tracker0";
private int _type = 0;
public int Type { get { return _type; } }
public bool TrackAnalog = false;
public bool TrackButtons = false;
public bool TrackPosition = true;
public ImstkUnity.VrpnDeviceManager manager;
public void Awake()
{
if (TrackAnalog) _type |= 0x1;
if (TrackButtons) _type |= 0x2;
if (TrackPosition) _type |= 0x4;
}
public void Start()
{
GetDevice();
}
protected override Imstk.DeviceClient MakeDevice()
{
return manager.MakeDeviceClient(this);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 79de4454bc1384f40b18333f30326fb5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,126 @@
/*=========================================================================
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 System.Threading;
using UnityEngine;
namespace ImstkUnity
{
#if IMSTK_USE_VRPN
// If this is not defined iMSTK was not built with VRPN enabled
// to use build iMSTK with the flag iMSTK_USE_VRPN set to ON
[AddComponentMenu("iMSTK/VrpnDeviceManager")]
public class VrpnDeviceManager : MonoBehaviour
{
private static VrpnDeviceManager _instance;
// Probably Refactor to Singleton base class
public static VrpnDeviceManager Instance
{
get { return _instance; }
}
public string host = "localhost";
public int port = 3883;
private Imstk.VRPNDeviceManager _manager;
private Thread thread;
private bool running = false;
public void Awake()
{
_instance = this;
}
public void InitManager()
{
if (_manager == null)
{
_manager = new Imstk.VRPNDeviceManager(host, port);
if (_manager == null) Debug.LogError("Could not create VRPNDevice Manager");
_manager.setSleepDelay(20);
_manager.init();
}
}
public Imstk.DeviceClient MakeDeviceClient(ImstkUnity.VrpnDevice device)
{
InitManager();
return _manager.makeDeviceClient(device.Name, device.Type);
}
public void StartManager()
{
if (running) return;
InitManager();
running = true;
Debug.Log("VRPN Thread Starting");
thread = new Thread(() =>
{
while (running)
{
_manager.update();
}
});
thread.Start();
}
public void StopManager()
{
if (_manager == null) return;
if (!running) return;
running = false;
thread.Join();
Debug.Log("VRPN Thread Stopping");
_manager.uninit();
thread = null;
}
}
#else
[AddComponentMenu("iMSTK/VrpnDeviceManager")]
public class VrpnDeviceManager : MonoBehaviour
{
// Probably Refactor to Singleton base class
public static VrpnDeviceManager Instance
{
get {
Debug.LogError("VRPN is not enable in this build");
return null;
}
}
public void Awake()
{
var a = Instance;
}
public void InitManager() {}
public Imstk.DeviceClient MakeDeviceClient(ImstkUnity.VrpnDevice device) {
return null;
}
public void StartManager() {}
public void StopManager() {}
}
#endif
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1644d13714b4c8446a7bc7df42c96612
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+70
View File
@@ -0,0 +1,70 @@
/*=========================================================================
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(Transform))]
public abstract class DynamicalModel : ImstkBehaviour
{
// HS 20221220 Need to figure out what we need at this level
// - What is common setup, what can just move into Deformable/Rigid
// - What distinguishes an object that can collied to one that doesn't (this is
// needed for setting up the collision handling object)
// Components
protected MeshFilter meshFilter = null;
protected Imstk.CollidingObject imstkObject;
// Indicates that geometry changes may happen as opposed to just
// position changes
// If true update needs to refresh vertex and triangle indices rather
// than just copying positions
public bool dynamicGeometry = false;
// Tells the object to ignore the global gravity parameter
public bool ignoreGravity = false;
/// <summary>
/// Get the pointer to the object in c (not available until after initialize)
/// </summary>
/// <returns></returns>
public Imstk.CollidingObject GetDynamicObject() { return imstkObject; }
// NOTE HS 20221220 Refactor readonly properties, initialize in each object
public abstract Imstk.Geometry GetVisualGeometry();
public abstract Imstk.Geometry GetPhysicsGeometry();
public abstract Imstk.Geometry GetCollidingGeometry();
protected abstract Imstk.CollidingObject InitObject();
protected abstract void Configure();
/// <summary>
/// Each subclassed model may *apply* boundary conditions differently
/// </summary>
/// <param name="conditions">All the conditions to be processed</param>
protected virtual void ProcessBoundaryConditions(BoundaryCondition[] conditions) { }
protected abstract void InitGeometry();
};
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf91fa9a7a7898e479e5e362b62d2a0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4971aef8039238944818264e2cf5a626
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,117 @@
using Imstk;
using ImstkUnity;
using UnityEditor;
using UnityEngine;
namespace ImstkEditor
{
[CustomEditor(typeof(ImstkUnity.CollisionInteraction), true)]
public class CollisionInteractionEditor : Editor
{
double _friction = 0.0;
double _restitution = 0.0;
double _deformableStiffness1 = 0.2;
double _deformableStiffness2 = 0.2;
double _rigidBodyCompliance = 0.0001;
DynamicalModel _model1;
DynamicalModel _model2;
static string[] _options;
public static string[] CDOptions
{
get
{
if (_options == null)
{
var names = CDObjectFactory.getNames();
_options = new string[names.Count + 1];
_options[0] = "Auto";
for (int i = 0; i < names.Count; ++i)
{
_options[i + 1] = names[i];
}
}
return _options;
}
}
string _message;
public override void OnInspectorGUI()
{
var script = target as ImstkUnity.CollisionInteraction;
EditorGUI.BeginChangeCheck();
_message = "Model 1 " + GetGeometryType(script.model1);
_model1 = EditorGUILayout.ObjectField(_message, script.model1, typeof(DynamicalModel), true) as DynamicalModel;
_message = "Model 2 " + GetGeometryType(script.model2);
_model2 = EditorGUILayout.ObjectField(_message, script.model2, typeof(DynamicalModel), true) as DynamicalModel;
var selected = System.Array.IndexOf(CDOptions, script.collisionTypeName);
selected = EditorGUILayout.Popup("Detection Type", selected, CDOptions);
_message = "Auto Type: ";
if (_model1 != null && _model1.GetCollidingGeometry() != null &&
_model2 != null && _model2.GetCollidingGeometry() != null)
{
_message += ImstkUnity.CollisionInteraction.GetCDType(_model1, _model2);
}
else
{
_message += " None";
}
EditorGUILayout.LabelField(_message);
_friction = EditorGUILayout.DoubleField("Friction", script.friction);
_restitution = EditorGUILayout.DoubleField("Restitution", script.restitution);
var guiContent = new GUIContent("Deform. Stiffness 1", "A good default value is 1/number of iterations from the simulation manager");
_deformableStiffness1 = EditorGUILayout.DoubleField(guiContent, script.deformableStiffness1);
guiContent = new GUIContent("Deform. Stiffness 2", "A good default value is 1/number of iterations from the simulation manager");
_deformableStiffness2 = EditorGUILayout.DoubleField(guiContent, script.deformableStiffness2);
_rigidBodyCompliance = EditorGUILayout.DoubleField("Rigid Compliance", script.rigidBodyCompliance);
if (EditorGUI.EndChangeCheck())
{
script.friction = _friction;
script.restitution = _restitution;
script.model1 = _model1;
script.model2 = _model2;
script.collisionTypeName = CDOptions[selected];
script.deformableStiffness1 = _deformableStiffness1;
script.deformableStiffness2 = _deformableStiffness2;
script.rigidBodyCompliance = _rigidBodyCompliance;
}
}
private string GetGeometryType(DynamicalModel model)
{
if (model == null)
{
return "";
}
Imstk.Geometry geom = model.GetCollidingGeometry();
if (geom == null)
{
return "<no geometry>";
}
else
{
return "<" + geom.getTypeName() + ">";
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e1e3f82b50dba9749aa16e4b978717e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,66 @@
using ImstkUnity;
using UnityEditor;
using UnityEngine;
namespace ImstkEditor
{
[CustomEditor(typeof(ConnectiveTissue))]
public class ConnectiveTissueEditor : Editor
{
// Local variables for caching editor results
Deformable sideA;
Deformable sideB;
double maxDistance;
double strandsPerFace;
int segmentsPerStrand;
double distanceStiffness;
double uniformMassValue;
double viscousDampingCoeff;
GUIContent sideAContent = new GUIContent("Side A", "One side of the objects that should be connected.");
GUIContent sideBContent = new GUIContent("Side B", "One side of the objects that should be connected.");
GUIContent maxDistContent = new GUIContent("Maximum Distance", "If side a and b are closer than this value" +
" connective tissue strands will be generated. If 0 the distance between the centers will be used");
GUIContent strandsPerFaceContent = new GUIContent("Strands per Face", "Indicates the density of strands " +
"that are being generated, fractions can be used e.g. 0.5 will generate a strand for half the faces");
GUIContent segmentsPerStrandContent = new GUIContent("Segments per Strand", "Determines the number of " +
"segments for each strand");
GUIContent distanceStiffnessContent = new GUIContent("Distance Stiffness", "Determines how much the " +
"connective tissue will resist extension.");
GUIContent massValueContent = new GUIContent("Uniform Mass Value", "Mass per vertex of the object");
GUIContent viscousDampingContent = new GUIContent("Viscous Damping", "Dampens the system");
public override void OnInspectorGUI()
{
var script = target as ConnectiveTissue;
EditorGUI.BeginChangeCheck();
sideA = EditorGUILayout.ObjectField(sideAContent, script.objectA, typeof(ImstkUnity.Deformable), true) as ImstkUnity.Deformable;
sideB = EditorGUILayout.ObjectField(sideBContent,script.objectB, typeof(ImstkUnity.Deformable), true) as ImstkUnity.Deformable;
maxDistance = EditorGUILayout.DoubleField(maxDistContent, script.maxDistance);
strandsPerFace = EditorGUILayout.DoubleField(strandsPerFaceContent, script.strandsPerFace);
segmentsPerStrand = EditorGUILayout.IntField(segmentsPerStrandContent, script.segmentsPerStrand);
distanceStiffness = EditorGUILayout.DoubleField(distanceStiffnessContent, script.distanceStiffness);
uniformMassValue = EditorGUILayout.DoubleField(massValueContent, script.uniformMassValue);
viscousDampingCoeff = EditorGUILayout.DoubleField(viscousDampingContent, script.viscousDampingCoeff);
if (EditorGUI.EndChangeCheck())
{
if ((sideA == null && sideB == null) || sideA != sideB)
{
script.objectA = sideA;
script.objectB = sideB;
}
script.maxDistance = maxDistance;
script.strandsPerFace = strandsPerFace;
script.segmentsPerStrand = segmentsPerStrand;
script.distanceStiffness = distanceStiffness;
script.uniformMassValue = uniformMassValue;
script.viscousDampingCoeff = viscousDampingCoeff;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b4588cff62e4364d93013f493396304
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// Adds the given define symbols to PlayerSettings define symbols.
/// Just add your own define symbols to the Symbols property at the below.
/// see https://forum.unity.com/threads/scripting-define-symbols-access-in-code.174390/
/// </summary>
[InitializeOnLoad]
public class DefineSymbols : Editor
{
/// <summary>
/// Symbols that will be added to the editor
/// </summary>
public static readonly string[] StaticSymbols = new string[] { };
public static bool runonce = false;
/// <summary>
/// Add define symbols as soon as Unity gets done compiling.
/// </summary>
static DefineSymbols()
{
string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
List<string> allDefines = definesString.Split(';').ToList();
List<string> originalDefines = new List<string>(allDefines);
allDefines.AddRange(StaticSymbols.Except(allDefines));
allDefines.AddRange(GetDeviceSymbols().Except(allDefines));
if (Enumerable.SequenceEqual(allDefines, originalDefines)) return;
PlayerSettings.SetScriptingDefineSymbolsForGroup(
EditorUserBuildSettings.selectedBuildTargetGroup,
string.Join(";", allDefines.ToArray()));
}
/// <summary>
/// Check through the known device names and see if it exists in the factory,
/// if yes, set the appropriate symbol so that the device class will be compiled
/// </summary>
private static List<string> GetDeviceSymbols()
{
var factory = new Imstk.DeviceManagerFactory();
var names = new string[] { "OpenHapticDeviceManager", "IMSTK_USE_OPENHAPTICS",
"HaplyDeviceManager", "IMSTK_USE_HAPLY",
"VRPNDeviceManager", "IMSTK_USE_VRPN" };
var symbols = new List<string>();
for (int i = 0; i < names.Length; i += 2)
{
if (Imstk.DeviceManagerFactory.contains(names[i]))
{
symbols.Add(names[i + 1]);
}
}
return symbols;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5409589cb14fa6e4eb717abe09f3a86b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,195 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
[CustomEditor(typeof(Deformable))]
public class DeformableEditor : DynamicalModelEditor
{
bool _cleanVisualMesh = false;
bool _bodyDamping = false;
double _linearDampingCoeff = 0.0;
double _angularDampingCoeff = 0.0;
public override void OnInspectorGUI()
{
Deformable script = target as Deformable;
EditorGUI.BeginChangeCheck();
GeometryFilter visualGeomFilter = EditorUtils.GeomFilterField("Visual Geometry", script.visualGeomFilter);
GeometryFilter physicsGeomFilter = EditorUtils.GeomFilterField("Physics Geometry", script.physicsGeomFilter);
GeometryFilter collisionGeomFilter = EditorUtils.GeomFilterField("Collision Geometry", script.collisionGeomFilter);
if (visualGeomFilter != null && visualGeomFilter == physicsGeomFilter)
{
bool val = script.cleanVisualMesh;
if (visualGeomFilter != script.visualGeomFilter)
{
val = visualGeomFilter.type == GeometryType.UnityMesh;
}
GUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.HelpBox(
"Some Mesh import may create `duplicate vertices` this will cause your physics object" +
" to fall apart at seams that might not be visible in the data. use the `Clean Visual Mesh` option" +
" to prevent this." ,MessageType.Warning);
_cleanVisualMesh = EditorGUILayout.Toggle("Clean Visual Mesh", val);
GUILayout.EndVertical();
}
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useDistanceConstraint = EditorGUILayout.Toggle("Distance Stiffness", script.useDistanceConstraint);
double distanceStiffness = script.distanceStiffness;
if (useDistanceConstraint)
distanceStiffness = EditorGUILayout.DoubleField("Stiffness", script.distanceStiffness);
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useBendConstraint = EditorGUILayout.Toggle("Bend Stiffness", script.useBendConstraint);
double bendStiffness = script.bendStiffness;
int bendStride = script.maxBendStride;
if (useBendConstraint)
{
bendStiffness = EditorGUILayout.DoubleField("Stiffness", script.bendStiffness);
bendStride = EditorGUILayout.IntField("Stride", script.maxBendStride);
}
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useDihedralConstraint = EditorGUILayout.Toggle("Dihedral Stiffness", script.useDihedralConstraint);
double dihedralStiffness = script.dihedralStiffness;
if (useDihedralConstraint)
dihedralStiffness = EditorGUILayout.DoubleField("Stiffness", script.dihedralStiffness);
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useAreaConstraint = EditorGUILayout.Toggle("Area Stiffness", script.useAreaConstraint);
double areaStiffness = script.areaStiffness;
if (useAreaConstraint)
areaStiffness = EditorGUILayout.DoubleField("Stiffness", script.areaStiffness);
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useVolumeConstraint = EditorGUILayout.Toggle("Volume Stiffness", script.useVolumeConstraint);
double volumeStiffness = script.volumeStiffness;
if (useVolumeConstraint)
volumeStiffness = EditorGUILayout.DoubleField("Stiffness", script.volumeStiffness);
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useFEMConstraint = EditorGUILayout.Toggle("FEM", script.useFEMConstraint);
double youngsModulus = script.youngsModulus;
double possionsRatio = script.possionsRatio;
bool useYoungsModulus = script.useYoungsModulus;
double mu = script.mu;
double lambda = script.lambda;
Imstk.PbdFemConstraint.MaterialType materialType = script.materialType;
if (useFEMConstraint)
{
useYoungsModulus = EditorGUILayout.Toggle("Use Youngs Modulus", script.useYoungsModulus);
if (useYoungsModulus)
{
youngsModulus = EditorGUILayout.DoubleField("Youngs Modulus", script.youngsModulus);
possionsRatio = EditorGUILayout.DoubleField("Possions Ratio", script.possionsRatio);
}
else
{
mu = EditorGUILayout.DoubleField("Mu", script.mu);
lambda = EditorGUILayout.DoubleField("Lambda", script.lambda);
}
materialType = (Imstk.PbdFemConstraint.MaterialType)EditorGUILayout.EnumPopup("Material Type", script.materialType);
}
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool ignoreGravity = EditorGUILayout.Toggle("Ignore Gravity", script.ignoreGravity);
double uniformMassValue = EditorGUILayout.DoubleField("Uniform Mass Value", script.uniformMassValue);
if (script.physicsGeomFilter != null)
{
var physicsGeom = Imstk.Utils.CastTo<Imstk.PointSet>(script.GetPhysicsGeometry());
if (physicsGeom != null)
{
var count = physicsGeom.getNumVertices();
double mass = EditorGUILayout.DoubleField("Mass ", count * uniformMassValue);
if (mass != count * uniformMassValue)
{
uniformMassValue = mass / count;
}
}
}
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
_bodyDamping = EditorGUILayout.Toggle("Use Body Damping", script.useBodyDamping);
if (_bodyDamping)
{
_linearDampingCoeff = EditorGUILayout.Slider("Linear Damping Coeff", (float)script.linearDampingCoeff, 0, 1);
_angularDampingCoeff = EditorGUILayout.Slider("Angular Damping Coeff", (float)script.angularDampingCoeff, 0, 1);
}
GUILayout.EndVertical();
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(script, "Change of Parameters");
script.useDistanceConstraint = useDistanceConstraint;
script.distanceStiffness = distanceStiffness;
script.useBendConstraint = useBendConstraint;
script.bendStiffness = bendStiffness;
script.maxBendStride = bendStride;
script.useDihedralConstraint = useDihedralConstraint;
script.dihedralStiffness = dihedralStiffness;
script.useAreaConstraint = useAreaConstraint;
script.areaStiffness = areaStiffness;
script.useVolumeConstraint = useVolumeConstraint;
script.volumeStiffness = volumeStiffness;
script.useFEMConstraint = useFEMConstraint;
script.youngsModulus = youngsModulus;
script.possionsRatio = possionsRatio;
script.mu = mu;
script.lambda = lambda;
script.uniformMassValue = uniformMassValue;
script.useYoungsModulus = useYoungsModulus;
script.materialType = materialType;
script.useBodyDamping = _bodyDamping;
script.linearDampingCoeff = _linearDampingCoeff;
script.angularDampingCoeff = _angularDampingCoeff;
script.visualGeomFilter = visualGeomFilter;
script.cleanVisualMesh = _cleanVisualMesh;
script.physicsGeomFilter = physicsGeomFilter;
script.collisionGeomFilter = collisionGeomFilter;
script.ignoreGravity = ignoreGravity;
}
base.HandleColliders(script);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9387229fe45d625478e06d841a78066b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,146 @@
using ImstkUnity;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace ImstkEditor
{
public class DynamicalModelEditor : Editor
{
bool _collisionsFolded = false;
List<DynamicalModel> _allDeformables;
public DynamicalModelEditor()
{
EditorApplication.hierarchyChanged += OnHierarchyChanged;
}
~DynamicalModelEditor()
{
EditorApplication.hierarchyChanged -= OnHierarchyChanged;
}
public void OnEnable()
{
}
private void OnHierarchyChanged()
{
_allDeformables = (Resources.FindObjectsOfTypeAll(typeof(DynamicalModel)) as DynamicalModel[]).ToList<DynamicalModel>();
SimulationManager.Instance().collisions.RemoveAllNull();
}
public void HandleColliders(DynamicalModel script)
{
if (_allDeformables == null)
{
OnHierarchyChanged();
}
EditorGUI.BeginChangeCheck();
var editorData = DrawColliders(script);
if (EditorGUI.EndChangeCheck())
{
var simulationManager = SimulationManager.Instance();
Undo.RegisterCompleteObjectUndo(simulationManager, "Update Collisions");
simulationManager.collisions = editorData;
}
}
protected CollisionInteractions DrawColliders(DynamicalModel script)
{
var allCollisions = SimulationManager.Instance().collisions;
var editorData = new CollisionInteractions(allCollisions);
_collisionsFolded = EditorGUILayout.Foldout(_collisionsFolded, "Colliding Objects");
if (_collisionsFolded)
{
EditorGUILayout.BeginVertical();
for (int i = 0; i < _allDeformables.Count; ++i)
{
var item = _allDeformables[i];
if (item == script) continue;
EditorGUILayout.BeginVertical();
// Title line with Toggle
EditorGUILayout.BeginHorizontal();
var enabled = allCollisions.IsEnabled(script, item);
var autoType = ImstkUnity.CollisionInteraction.GetCDType(script, item);
var newEnabled = false;
EditorGUI.BeginDisabledGroup(autoType == "");
newEnabled = EditorGUILayout.Toggle(enabled, GUILayout.Width(20));
EditorGUI.EndDisabledGroup();
if (enabled != newEnabled)
{
if (newEnabled)
{
editorData.Add(script, item);
}
else
{
editorData.Remove(script, item);
}
}
EditorGUI.BeginDisabledGroup(!newEnabled && autoType == "");
EditorGUILayout.LabelField(item.name);
if (autoType == "")
{
EditorGUILayout.LabelField("No collision type available");
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndHorizontal();
if (newEnabled)
{
EditorGUILayout.BeginVertical();
var d = editorData.GetData(script, item);
var _message = "Auto Type: ";
if (d.model1 != null && d.model1.GetCollidingGeometry() != null &&
d.model2 != null && d.model2.GetCollidingGeometry() != null)
{
_message += ImstkUnity.CollisionInteraction.GetCDType(d.model1, d.model2);
}
else
{
_message += " None ";
}
EditorGUILayout.LabelField(_message);
var selected = System.Array.IndexOf(CollisionInteractionEditor.CDOptions, d.collisionTypeName);
if (selected < 0) selected = 0;
selected = EditorGUILayout.Popup("Detection Type", selected, CollisionInteractionEditor.CDOptions);
d.collisionTypeName = CollisionInteractionEditor.CDOptions[selected];
d.friction = EditorGUILayout.DoubleField("Friction", d.friction);
d.restitution = EditorGUILayout.DoubleField("Restitution", d.restitution);
var guiContent = new GUIContent("Deform. Stiffness 1", "A good default value is 1/number of iterations from the simulation manager");
d.deformableStiffness1 = EditorGUILayout.DoubleField(guiContent, d.deformableStiffness1);
guiContent = new GUIContent("Deform. Stiffness 2", "A good default value is 1/number of iterations from the simulation manager");
d.deformableStiffness2 = EditorGUILayout.DoubleField(guiContent, d.deformableStiffness2);
d.rigidBodyCompliance = EditorGUILayout.DoubleField("Rigid Compliance", d.rigidBodyCompliance);
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndVertical();
// Needs to move into the undo section
}
EditorGUILayout.EndVertical();
}
return editorData;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8717cb3ee56ae44ba778d9c36370886
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+132
View File
@@ -0,0 +1,132 @@
/*=========================================================================
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 System.IO;
using UnityEditor;
using UnityEngine;
using ImstkUnity;
namespace ImstkEditor
{
public static class EditorUtils
{
public static GeometryFilter GeomFilterField(string fieldName, GeometryFilter filter)
{
return EditorGUILayout.ObjectField(fieldName, filter, typeof(GeometryFilter), true) as GeometryFilter;
}
/// <summary>
/// Clears all plugins and iMSTKSharp directory ".cs" files. Reinstalls
/// from installSourcePath
/// </summary>
/// <param name="installSourcePath"></param>
public static void InstallImstk(string installSourcePath)
{
// Get the install directory
if (installSourcePath.Length != 0)
{
// First check the directory exists
if (!Directory.Exists(installSourcePath))
{
Debug.LogError("Failed to install imstk, source location does not exist: " + installSourcePath);
}
// Next check that a file exists to lightly verify we have the right directory
if (!Directory.Exists(installSourcePath + "/lib/cmake/iMSTK-5.0") ||
!File.Exists(installSourcePath + "/lib/cmake/iMSTK-5.0/iMSTKConfig.cmake"))
{
Debug.LogError("Could not find relevant files, check the imstk install directory is specified properly: " + installSourcePath);
}
// Determine the directory what this script resides in and therefore the location of
// the Plugins directory
string[] res = System.IO.Directory.GetFiles(Application.dataPath, "EditorUtils.cs", SearchOption.AllDirectories);
if (res.Length == 0)
{
Debug.LogError("Could not find target directory");
return;
}
string dataPath = res[0].Replace("EditorUtils.cs", "").Replace("\\", "/") + "../../";
// Clear plugins directory and copy all files from bin to plugins
ClearFiles(dataPath + "/Plugins/");
CopyFiles(installSourcePath + "/bin/", dataPath + "/Plugins/", new string[] { ".dll", ".so" });
AssetDatabase.Refresh();
}
}
/// <summary>
/// Clear all files at path
/// </summary>
public static void ClearFiles(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
else
{
string[] files = Directory.GetFiles(path);
for (int i = 0; i < files.Length; i++)
{
File.Delete(files[i]);
}
Directory.Delete(path);
Directory.CreateDirectory(path);
}
}
/// <summary>
/// Copy all files from srcPath to destPath directory
/// </summary>
public static void CopyFiles(string srcPath, string destPath, string[] extFilter)
{
if (!Directory.Exists(srcPath))
{
return;
}
if (!Directory.Exists(destPath))
{
Directory.CreateDirectory(destPath);
}
string[] hi = Directory.GetFiles(srcPath);
for (int i = 0; i < hi.Length; i++)
{
string ext = Path.GetExtension(hi[i]);
bool validExt = false;
for (int j = 0; j < extFilter.Length; j++)
{
if (ext == extFilter[j])
{
validExt = true;
}
}
if (validExt)
{
File.Copy(hi[i], destPath + Path.GetFileName(hi[i]));
}
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f60b332d6af09a04e9fc7bf700b3df3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,371 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// This class adds menu items for various parts of Unity
/// </summary>
/// It can also do other things
public class GameObjectMenuItems : Editor
{
[MenuItem("GameObject/iMSTK/SimulationManager")]
[MenuItem("CONTEXT/iMSTK/SimulationManager")]
[MenuItem("iMSTK/GameObject/SimulationManager")]
private static void CreateSimulationManagerGameObject()
{
GameObject newObj = new GameObject("SimulationManager");
newObj.AddComponent(typeof(SimulationManager));
}
/// <summary>
/// Creates a GameObject with a Deformable and Tet cube
/// </summary>
[MenuItem("GameObject/iMSTK/Deformables/Cube")]
[MenuItem("CONTEXT/iMSTK/Deformables/Cube")]
[MenuItem("iMSTK/GameObject/Deformables/Cube")]
private static void CreateDeformableVolume()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
newObj.name = "Cube";
DestroyImmediate(newObj.GetComponent<Collider>());
Deformable model = newObj.AddComponent<Deformable>();
model.useDistanceConstraint = false;
model.useAreaConstraint = false;
model.useDihedralConstraint = false;
model.useVolumeConstraint = false;
model.useFEMConstraint = true;
model.viscousDampingCoeff = 0.01;
ImstkMesh tetCubeMesh = Utility.GetTetCubeMesh();
Imstk.TetrahedralMesh imstkTetMesh = tetCubeMesh.ToImstkGeometry() as Imstk.TetrahedralMesh;
ImstkMesh surfMesh = imstkTetMesh.extractSurfaceMesh().ToImstkMesh();
surfMesh.name = tetCubeMesh.name + "_surface";
MeshFilter meshFilter = newObj.GetComponent<MeshFilter>();
meshFilter.sharedMesh = surfMesh.ToMesh();
GeometryFilter visualGeom = newObj.AddComponent<GeometryFilter>();
visualGeom.SetGeometry(meshFilter.sharedMesh);
visualGeom.showHandles = false;
GeometryFilter physicsGeom = newObj.AddComponent<GeometryFilter>();
physicsGeom.SetGeometry(tetCubeMesh);
physicsGeom.showHandles = false;
model.visualGeomFilter = visualGeom;
model.physicsGeomFilter = physicsGeom;
model.collisionGeomFilter = visualGeom;
DeformableMap map = newObj.AddComponent<DeformableMap>();
map.parentGeom = physicsGeom;
map.childGeom = visualGeom;
}
/// <summary>
/// Creates a GameObject with a Deformable and a Plane
/// </summary>
[MenuItem("GameObject/iMSTK/Deformables/Cloth")]
[MenuItem("CONTEXT/iMSTK/Deformables/Cloth")]
[MenuItem("iMSTK/GameObject/Deformables/Cloth")]
private static void CreatePbdCloth()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Plane);
newObj.name = "Cloth";
DestroyImmediate(newObj.GetComponent<Collider>());
Deformable model = newObj.AddComponent<Deformable>();
model.useDistanceConstraint = true;
model.useDihedralConstraint = true;
model.useAreaConstraint = false;
model.useVolumeConstraint = false;
model.useFEMConstraint = false;
model.distanceStiffness = 100.0;
model.dihedralStiffness = 10.0;
model.viscousDampingCoeff = 0.01;
model.uniformMassValue = 0.05;
ImstkMesh mesh = Utility.GetXYPlane(19, 19);
MeshFilter meshFilter = newObj.GetComponent<MeshFilter>();
meshFilter.sharedMesh = mesh.ToMesh();
GeometryFilter visualGeom = newObj.AddComponent<GeometryFilter>();
visualGeom.SetGeometry(meshFilter.sharedMesh);
visualGeom.showHandles = false;
model.visualGeomFilter = visualGeom;
model.physicsGeomFilter = visualGeom;
model.collisionGeomFilter = visualGeom;
}
/// <summary>
/// Creates a GameObject with a Deformable and tetrahedral grid
/// </summary>
[MenuItem("GameObject/iMSTK/Deformables/Subdivided Cube")]
[MenuItem("CONTEXT/iMSTK/Deformables/Subdivided Cube")]
[MenuItem("iMSTK/GameObject/Deformables/Subdivided Cube")]
private static void CreatePbdGridVolume()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
newObj.name = "Cube";
DestroyImmediate(newObj.GetComponent<Collider>());
// Add PbdModel to the object
Deformable model = newObj.AddComponent<Deformable>();
model.useDistanceConstraint = false;
model.useAreaConstraint = false;
model.useDihedralConstraint = false;
model.useVolumeConstraint = false;
model.useFEMConstraint = true;
model.viscousDampingCoeff = 0.01;
model.youngsModulus = 5000.0;
model.possionsRatio = 0.4;
model.materialType = Imstk.PbdFemConstraint.MaterialType.StVK;
// Create a new mesh, store the old one
MeshFilter meshFilter = newObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
// Create a new tet geometry
GeometryFilter physicsGeom = newObj.AddComponent<GeometryFilter>();
ImstkMesh tetMesh = ScriptableObject.CreateInstance<ImstkMesh>();
tetMesh.geomType = GeometryType.TetrahedralMesh;
physicsGeom.SetGeometry(tetMesh);
physicsGeom.showHandles = false;
GeometryFilter visualGeom = newObj.AddComponent<GeometryFilter>();
visualGeom.SetGeometry(meshFilter.sharedMesh);
visualGeom.showHandles = false;
model.visualGeomFilter = visualGeom;
model.physicsGeomFilter = physicsGeom;
model.collisionGeomFilter = visualGeom;
DeformableMap map = newObj.AddComponent<DeformableMap>();
map.parentGeom = physicsGeom;
map.childGeom = visualGeom;
// Use editor to add fill geometries
TetrahedralGridEditor.Init(meshFilter.sharedMesh, physicsGeom.inputImstkGeom as ImstkMesh);
}
/// <summary>
/// Creates a GameObject with a Deformable and line mesh
/// </summary>
[MenuItem("GameObject/iMSTK/Deformables/Thread")]
[MenuItem("CONTEXT/iMSTK/Deformables/Thread")]
[MenuItem("iMSTK/GameObject/Deformables/Thread")]
private static void CreatePbdThread()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
newObj.name = "PbdThread";
DestroyImmediate(newObj.GetComponent<Collider>());
// Add PbdModel to the object
Deformable model = newObj.AddComponent<Deformable>();
model.useDistanceConstraint = true;
model.useBendConstraint = true;
model.useAreaConstraint = false;
model.useDihedralConstraint = false;
model.useVolumeConstraint = false;
model.useFEMConstraint = false;
model.viscousDampingCoeff = 0.01;
model.distanceStiffness = 100.0;
model.bendStiffness = 100.0;
model.maxBendStride = 3;
// Create a new mesh, store the old one
MeshFilter meshFilter = newObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
inputMesh.name = "LineMesh";
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
GeometryFilter visualGeom = newObj.AddComponent<GeometryFilter>();
visualGeom.SetGeometry(meshFilter.sharedMesh);
visualGeom.showHandles = false;
model.visualGeomFilter = visualGeom;
model.physicsGeomFilter = visualGeom;
model.collisionGeomFilter = visualGeom;
// Use editor to add fill geometries
LineMeshEditor.Init(meshFilter.sharedMesh);
}
/// <summary>
/// Creates a GameObject with a RbdModel and sphere
/// </summary>
[MenuItem("GameObject/iMSTK/Rigids/Sphere")]
[MenuItem("CONTEXT/iMSTK/Rigids/Sphere")]
[MenuItem("iMSTK/GameObject/Rigids/Sphere")]
private static void CreateRigidSphere()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
newObj.name = "Rigid Sphere";
DestroyImmediate(newObj.GetComponent<Collider>());
// Add PbdModel to the object
Rigid model = newObj.AddComponent<Rigid>();
model.mass = 1.0;
model.inertia = new Vector3[]
{
new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 0.0f, 1.0f)
};
// Create a new mesh, store the old one
MeshFilter meshFilter = newObj.GetComponentOrCreate<MeshFilter>();
GeometryFilter visualGeom = newObj.AddComponent<GeometryFilter>();
visualGeom.SetGeometry(meshFilter.sharedMesh);
visualGeom.showHandles = false;
Sphere sphere = CreateInstance<Sphere>();
sphere.radius = 0.5f;
sphere.center = Vector3.zero;
GeometryFilter collisionGeom = newObj.AddComponent<GeometryFilter>();
collisionGeom.SetGeometry(sphere);
model.visualGeomFilter = visualGeom;
model.physicsGeomFilter = collisionGeom;
model.collisionGeomFilter = collisionGeom;
}
/// <summary>
/// Creates a GameObject with an OpenHapticsDevice
/// </summary>
[MenuItem("GameObject/iMSTK/Devices/OpenHapticsDevice")]
[MenuItem("CONTEXT/iMSTK/Devices/OpenHapticsDevice")]
[MenuItem("iMSTK/GameObject/Devices/OpenHapticsDevice")]
private static void CreateOpenHapticsDevice()
{
GameObject newObj = new GameObject("OpenHapticsDevice");
newObj.AddComponent(typeof(OpenHapticsDevice));
}
[MenuItem("GameObject/iMSTK/Static Objects/Line")]
[MenuItem("CONTEXT/iMSTK/Static Objects/Line")]
[MenuItem("iMSTK/GameObject/Static Objects/Line")]
private static void CreateLineStaticObject()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
newObj.name = "StaticLineObject";
DestroyImmediate(newObj.GetComponent<Collider>());
StaticModel model = newObj.AddComponent<StaticModel>();
ImstkMesh mesh = ScriptableObject.CreateInstance<ImstkMesh>();
mesh.geomType = GeometryType.LineMesh;
mesh.vertices = new Vector3[] { new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f) };
mesh.indices = new int[] { 0, 1 };
MeshFilter meshFilter = newObj.GetComponent<MeshFilter>();
meshFilter.sharedMesh = mesh.ToMesh();
meshFilter.sharedMesh.name = "LineMesh";
GeometryFilter collisionGeom = newObj.AddComponent<GeometryFilter>();
collisionGeom.SetGeometry(meshFilter.sharedMesh);
model.collisionGeomFilter = collisionGeom;
}
[MenuItem("GameObject/iMSTK/Static Objects/Sphere")]
[MenuItem("CONTEXT/iMSTK/Static Objects/Sphere")]
[MenuItem("iMSTK/GameObject/Static Objects/Sphere")]
private static void CreateSphereStaticObject()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
newObj.name = "Static Sphere";
DestroyImmediate(newObj.GetComponent<Collider>());
StaticModel model = newObj.AddComponent<StaticModel>();
Sphere sphere = new Sphere();
GeometryFilter collisionGeom = newObj.AddComponent<GeometryFilter>();
collisionGeom.SetGeometry(sphere);
model.collisionGeomFilter = collisionGeom;
}
[MenuItem("GameObject/iMSTK/Static Objects/Capsule")]
[MenuItem("CONTEXT/iMSTK/Static Objects/Capsule")]
[MenuItem("iMSTK/GameObject/Static Objects/Capsule")]
private static void CreateCapsuleStaticObject()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Capsule);
newObj.name = "Static Capsule";
DestroyImmediate(newObj.GetComponent<Collider>());
StaticModel model = newObj.AddComponent<StaticModel>();
Capsule capsule = new Capsule();
GeometryFilter collisionGeom = newObj.AddComponent<GeometryFilter>();
collisionGeom.SetGeometry(capsule);
model.collisionGeomFilter = collisionGeom;
}
[MenuItem("GameObject/iMSTK/Static Objects/Oriented Box")]
[MenuItem("CONTEXT/iMSTK/Static Objects/Oriented Box")]
[MenuItem("iMSTK/GameObject/Static Objects/Oriented Box")]
private static void CreateOrientedBoxStaticObject()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
newObj.name = "StaticOrientedBoxObject";
DestroyImmediate(newObj.GetComponent<Collider>());
StaticModel model = newObj.AddComponent<StaticModel>();
OrientedBox obb = new OrientedBox();
GeometryFilter collisionGeom = newObj.AddComponent<GeometryFilter>();
collisionGeom.SetGeometry(obb);
model.collisionGeomFilter = collisionGeom;
}
[MenuItem("GameObject/iMSTK/Static Objects/Plane")]
[MenuItem("CONTEXT/iMSTK/Static Objects/Plane")]
[MenuItem("iMSTK/GameObject/Static Objects/Plane")]
private static void CreatePlaneStaticObject()
{
GameObject newObj = GameObject.CreatePrimitive(PrimitiveType.Plane);
newObj.name = "StaticPlaneObject";
DestroyImmediate(newObj.GetComponent<Collider>());
StaticModel model = newObj.AddComponent<StaticModel>();
ImstkUnity.Plane plane = new ImstkUnity.Plane();
plane.visualWidth = 5.1f;
GeometryFilter collisionGeom = newObj.AddComponent<GeometryFilter>();
collisionGeom.SetGeometry(plane);
model.collisionGeomFilter = collisionGeom;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bafd05c20034eca4081b3d878dd89662
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
/*=========================================================================
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;
using UnityEditor;
namespace ImstkUnity
{
/// <summary>
/// Editor for the asset, most commonly shown when selecting the asset in
/// the project explorer
/// </summary>
[CustomEditor(typeof(Geometry), true)]
class GeometryEditor : Editor
{
private PreviewRenderUtility m_PreviewUtility = null;
private Material previewMaterial = null;
private Mesh previewMesh = null;
public override void OnInspectorGUI()
{
// Check the config file toggle for change
Geometry asset = target as Geometry;
if (asset.IsMesh)
{
ImstkMesh mesh = asset as ImstkMesh;
GUILayout.Label("Vertex Count: " + mesh.vertices.Length);
GUILayout.Label("Index Count: " + mesh.indices.Length);
GUILayout.Label("Cell Count: " + mesh.indices.Length / ImstkMesh.typeToNumPts[mesh.geomType]);
}
GUILayout.Label("Geom Type: " + asset.geomType.ToString());
}
public override bool HasPreviewGUI() { return true; }
public override GUIContent GetPreviewTitle() { return new GUIContent(target.name); }
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
Geometry asset = target as Geometry;
// Preview only works with meshes
if (!asset.IsMesh)
return;
ImstkMesh imstkMesh = asset as ImstkMesh;
if (m_PreviewUtility == null)
{
m_PreviewUtility = new PreviewRenderUtility();
previewMaterial = new Material(Shader.Find("Diffuse"));
// If a tet or hex mesh extract surface for display (we could use some other method to better indicate
// that this is a tet mesh)
if (asset.IsVolume)
{
// Extract the surface mesh for display
Imstk.TetrahedralMesh tetMesh = Imstk.Utils.CastTo<Imstk.TetrahedralMesh>(imstkMesh.ToPointSet());
Imstk.SurfaceMesh surfMesh = tetMesh.extractSurfaceMesh();
previewMesh = surfMesh.ToMesh();
}
}
if (Event.current.type != EventType.Repaint)
{
return;
}
Camera camera = m_PreviewUtility.camera;
float size = previewMesh.bounds.size.magnitude;
Vector3 center = previewMesh.bounds.center;
camera.transform.position = center + new Vector3(0.0f, size * 2.0f, -size * 2.0f);
camera.transform.LookAt(center);
camera.farClipPlane = 300.0f;
m_PreviewUtility.BeginPreview(r, background);
m_PreviewUtility.DrawMesh(previewMesh, Matrix4x4.identity, previewMaterial, 0);
bool fog = RenderSettings.fog;
Unsupported.SetRenderSettingsUseFogNoDirty(false);
m_PreviewUtility.camera.Render();
Unsupported.SetRenderSettingsUseFogNoDirty(fog);
Texture texture = m_PreviewUtility.EndPreview();
GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false);
}
void OnDisable()
{
previewMaterial = null;
previewMesh = null;
if (m_PreviewUtility != null)
{
m_PreviewUtility.Cleanup();
m_PreviewUtility = null;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73289ab03e7c85b418a57465a634e813
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fe4d6df5f481eb2478ab3cf67d3ac5f8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,98 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// Laplacian smoothens an input unity Mesh providing
/// an output one
/// </summary>
public class LaplaceSmoothEditor : EditorWindow
{
public int numIterations = 20;
public double relaxationFactor = 0.01;
public double convergence = 0.0;
public double featureAngle = 45.0;
public double edgeAngle = 15.0;
public bool featureEdgeSmoothing = false;
public bool boundarySmoothing = true;
public Mesh inputMesh = null;
public Mesh outputMesh = null;
public static void Init(Mesh inputMesh, Mesh outputMesh)
{
LaplaceSmoothEditor window = GetWindow(typeof(LaplaceSmoothEditor)) as LaplaceSmoothEditor;
window.inputMesh = inputMesh;
window.outputMesh = outputMesh;
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
inputMesh = EditorGUILayout.ObjectField("Input Mesh: ", inputMesh, typeof(Mesh), true) as Mesh;
int tNumIterations = EditorGUILayout.IntField("Number Of Smoothing Iterations: ", numIterations);
double tRelaxationFactor = EditorGUILayout.DoubleField("Relaxation Factor: ", relaxationFactor);
double tConvergence = EditorGUILayout.DoubleField("Convergence: ", convergence);
double tFeatureAngle = EditorGUILayout.DoubleField("Feature Angle: ", featureAngle);
double tEdgeAngle = EditorGUILayout.DoubleField("Edge Angle: ", edgeAngle);
bool tFeatureEdgeSmoothing = EditorGUILayout.Toggle("Use Feature Edge Smoothing: ", featureEdgeSmoothing);
bool tBoundarySmoothing = EditorGUILayout.Toggle("Use Boundary Smoothing: ", boundarySmoothing);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
numIterations = MathUtil.Max(tNumIterations, 1);
relaxationFactor = MathUtil.Max(tRelaxationFactor, 0.0);
convergence = MathUtil.Max(tConvergence, 0.0);
featureAngle = MathUtil.Max(tFeatureAngle, 0.0);
edgeAngle = MathUtil.Max(tEdgeAngle, 0.0);
featureEdgeSmoothing = tFeatureEdgeSmoothing;
boundarySmoothing = tBoundarySmoothing;
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
Imstk.SurfaceMesh surfMesh = inputMesh.ToImstkGeometry() as Imstk.SurfaceMesh;
Imstk.SurfaceMeshSmoothen smoothen = new Imstk.SurfaceMeshSmoothen();
smoothen.setInputMesh(surfMesh);
smoothen.setNumberOfIterations(numIterations);
smoothen.setRelaxationFactor(relaxationFactor);
smoothen.setConvergence(convergence);
smoothen.setFeatureAngle(featureAngle);
smoothen.setEdgeAngle(edgeAngle);
smoothen.setFeatureEdgeSmoothing(featureEdgeSmoothing);
smoothen.setBoundarySmoothing(boundarySmoothing);
smoothen.update();
Imstk.SurfaceMesh outputSurfMesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(smoothen.getOutput());
GeomUtil.CopyMesh(outputSurfMesh.ToMesh(), outputMesh);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ea044bfac569c644b427c75bffa1bd8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,102 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// Generates a plane mesh for MeshFilter
/// </summary>
public class LineMeshEditor : EditorWindow
{
public Vector3 start = Vector3.zero;
public Vector3 direction = new Vector3(1.0f, 0.0f, 0.0f);
public int divisions = 10;
public double length = 1.0;
public Mesh outputMesh = null;
public static void Init(Mesh outputMesh)
{
LineMeshEditor window = GetWindow(typeof(LineMeshEditor)) as LineMeshEditor;
window.outputMesh = outputMesh;
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
outputMesh = EditorGUILayout.ObjectField("Input Mesh: ", outputMesh, typeof(Mesh), true) as Mesh;
Vector3 tStart = EditorGUILayout.Vector3Field("Start", start);
Vector3 tDirection = EditorGUILayout.Vector3Field("Direction", direction);
int tDivisions = EditorGUILayout.IntField("Divisions", divisions);
double tLength = EditorGUILayout.DoubleField("Length", length);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
start = tStart;
direction = tDirection;
if (direction == Vector3.zero)
{
direction = new Vector3(1.0f, 0.0f, 0.0f);
}
divisions = Mathf.Max(tDivisions, 1);
length = MathUtil.Max(tLength, 0.0);
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
int numVerts = divisions + 1;
int numCells = divisions;
Vector3[] vertices = new Vector3[numVerts];
int[] indices = new int[numCells * 2];
direction = direction.normalized;
for (int i = 0; i < numVerts; i++)
{
float t = (float)i / (numVerts - 1); // 0-1
vertices[i] = start + direction * t * (float)length;
}
for (int i = 0; i < numCells; i++)
{
indices[i * 2] = i;
indices[i * 2 + 1] = i + 1;
}
outputMesh.triangles = null;
outputMesh.normals = null;
outputMesh.tangents = null;
outputMesh.vertices = vertices;
outputMesh.SetIndices(indices, MeshTopology.Lines, 0);
outputMesh.RecalculateBounds();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33c64bf93157c484abdc881055be248f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,73 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// Generates a plane mesh for MeshFilter
/// </summary>
public class PlaneMeshEditor : EditorWindow
{
//public Vector3 size = new Vector3(1.0f, 0.25f, 1.0f);
public Vector2Int dim = new Vector2Int(8, 8);
//public Vector3 center = new Vector3(0.0f, 0.0f, 0.0f);
public Mesh outputMesh = null;
public static void Init(Mesh outputMesh)
{
PlaneMeshEditor window = GetWindow(typeof(PlaneMeshEditor)) as PlaneMeshEditor;
window.outputMesh = outputMesh;
if (outputMesh.name.Length == 0) outputMesh.name = "plane mesh";
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
outputMesh = EditorGUILayout.ObjectField("Input Mesh: ", outputMesh, typeof(Mesh), true) as Mesh;
name = EditorGUILayout.TextField("Name: ", outputMesh.name);
//Vector3 tSize = EditorGUILayout.Vector3Field("Size: ", size);
Vector2Int tDim = EditorGUILayout.Vector2IntField("Grid Dimensions: ", dim);
//Vector3 tCenter = EditorGUILayout.Vector3Field("Center: ", center);
// \todo: How to get undo to also call UpdateInputObj?
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
//size = tSize.cwiseMax(new Vector3(0.0f, 0.0f, 0.0f));
dim = tDim.cwiseMax(new Vector2Int(2, 2));
//center = tCenter;
outputMesh.name = name;
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
ImstkMesh planeMesh = Utility.GetXYPlane(dim.x, dim.y);
GeomUtil.CopyMesh(planeMesh.ToMesh(), outputMesh);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe3bffa442f54d04ea8dcec7b28e5535
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,86 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
public enum SubdivideMeshType
{
Linear,
Loop,
Butterfly
}
/// <summary>
/// Laplacian smoothens an input unity Mesh providing
/// an output one
/// </summary>
public class SubdivideMeshEditor : EditorWindow
{
public int numSubdivisions = 1;
public Imstk.SurfaceMeshSubdivide.Type subdivType = Imstk.SurfaceMeshSubdivide.Type.LINEAR;
public Mesh inputMesh = null;
public Mesh outputMesh = null;
public static void Init(Mesh inputMesh, Mesh outputMesh)
{
SubdivideMeshEditor window = GetWindow(typeof(SubdivideMeshEditor)) as SubdivideMeshEditor;
window.inputMesh = inputMesh;
window.outputMesh = outputMesh;
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
inputMesh = EditorGUILayout.ObjectField("Input Mesh: ", inputMesh, typeof(Mesh), true) as Mesh;
int tNumSubdivisions = EditorGUILayout.IntField("Number Of Subdivisions: ", numSubdivisions);
Imstk.SurfaceMeshSubdivide.Type tSubdivType =
(Imstk.SurfaceMeshSubdivide.Type)EditorGUILayout.EnumPopup("Subdivision Type: ", subdivType);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
numSubdivisions = MathUtil.Max(tNumSubdivisions, 0);
subdivType = tSubdivType;
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
Imstk.SurfaceMesh surfMesh = inputMesh.ToImstkGeometry() as Imstk.SurfaceMesh;
Imstk.SurfaceMeshSubdivide subdiv = new Imstk.SurfaceMeshSubdivide();
subdiv.setInputMesh(surfMesh);
subdiv.setNumberOfSubdivisions(numSubdivisions);
subdiv.setSubdivisionType(subdivType);
subdiv.update();
Imstk.SurfaceMesh outputSurfMesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(subdiv.getOutput());
GeomUtil.CopyMesh(outputSurfMesh.ToMesh(), outputMesh);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b8962d5e32621842895493399fea036
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,80 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// Generates a tetrahedral mesh PhysicsGeometry
/// </summary>
public class TetrahedralGridEditor : EditorWindow
{
public Vector3 size = new Vector3(1.0f, 0.25f, 1.0f);
public Vector3Int dim = new Vector3Int(8, 4, 8);
public Vector3 center = new Vector3(0.0f, 0.0f, 0.0f);
public Mesh outputSurfMesh = null;
public ImstkMesh outputTetMesh = null;
public static void Init(
Mesh outputSurfMesh,
ImstkMesh outputTetMesh)
{
TetrahedralGridEditor window = GetWindow(typeof(TetrahedralGridEditor)) as TetrahedralGridEditor;
window.outputSurfMesh = outputSurfMesh;
window.outputTetMesh = outputTetMesh;
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
outputSurfMesh = EditorGUILayout.ObjectField("Input Surface MeshFilter: ", outputSurfMesh, typeof(Mesh), true) as Mesh;
outputTetMesh = EditorGUILayout.ObjectField("Input Tet GeometryFilter: ", outputTetMesh, typeof(ImstkMesh), true) as ImstkMesh;
Vector3 tSize = EditorGUILayout.Vector3Field("Size: ", size);
Vector3Int tDim = EditorGUILayout.Vector3IntField("Grid Dimensions: ", dim);
Vector3 tCenter = EditorGUILayout.Vector3Field("Center: ", center);
// \todo: How to get undo to also call UpdateInputObj?
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
size = tSize.cwiseMax(new Vector3(0.0f, 0.0f, 0.0f));
dim = tDim.cwiseMax(new Vector3Int(2, 2, 2));
center = tCenter;
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
ImstkMesh tetMesh = Utility.GetTetGridMesh(size, dim, center);
GeomUtil.CopyMesh(tetMesh, outputTetMesh);
Imstk.TetrahedralMesh imstkTetMesh = Imstk.Utils.CastTo<Imstk.TetrahedralMesh>(tetMesh.ToImstkGeometry());
Imstk.SurfaceMesh surfMesh = imstkTetMesh.extractSurfaceMesh();
GeomUtil.CopyMesh(surfMesh.ToMesh(), outputSurfMesh);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f18b03d2fbaf8448913420009e4e51e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,132 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
public enum UVPlaneOptions
{
XY,
YZ,
XZ,
Custom
}
/// <summary>
/// Generates UV plane coords
/// </summary>
public class UVPlaneProjectEditor : EditorWindow
{
public Vector3 planeNormal = new Vector3(0.0f, 1.0f, 0.0f);
public UVPlaneOptions planeOption = UVPlaneOptions.XZ;
public Vector2 uvScale = new Vector2(1.0f, 1.0f);
public Vector2 uvShift = Vector2.zero;
public Mesh inputMesh = null;
public Mesh outputMesh = null;
public static void Init(Mesh inputMesh, Mesh outputMesh)
{
UVPlaneProjectEditor window = GetWindow(typeof(UVPlaneProjectEditor)) as UVPlaneProjectEditor;
window.inputMesh = inputMesh;
window.outputMesh = outputMesh;
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
inputMesh = EditorGUILayout.ObjectField("Input Mesh: ", inputMesh, typeof(Mesh), true) as Mesh;
Vector3 tPlaneNormal = EditorGUILayout.Vector3Field("Plane Normal: ", planeNormal);
UVPlaneOptions tPlaneOption = (UVPlaneOptions)EditorGUILayout.EnumPopup("Plane: ", planeOption);
Vector2 tUvScale = EditorGUILayout.Vector2Field("UV Scale", uvScale);
Vector2 tUvShift = EditorGUILayout.Vector2Field("UV Shift", uvShift);
// \todo: How to get undo to also call UpdateInputObj?
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
// IF the plane normal was changed
if (tPlaneNormal != planeNormal)
{
if (tPlaneNormal == new Vector3(0.0f, 1.0f, 0.0f))
{
tPlaneOption = UVPlaneOptions.XZ;
}
else if (tPlaneNormal == new Vector3(1.0f, 0.0f, 0.0f))
{
tPlaneOption = UVPlaneOptions.YZ;
}
else if (tPlaneNormal == new Vector3(0.0f, 0.0f, 1.0f))
{
tPlaneOption = UVPlaneOptions.XY;
}
else
{
tPlaneOption = UVPlaneOptions.Custom;
}
}
if (tPlaneOption != planeOption)
{
if (tPlaneOption == UVPlaneOptions.XY)
{
tPlaneNormal = new Vector3(0.0f, 0.0f, 1.0f);
}
else if (tPlaneOption == UVPlaneOptions.XZ)
{
tPlaneNormal = new Vector3(0.0f, 1.0f, 0.0f);
}
else if (tPlaneOption == UVPlaneOptions.YZ)
{
tPlaneNormal = new Vector3(1.0f, 0.0f, 0.0f);
}
}
planeNormal = tPlaneNormal;
planeOption = tPlaneOption;
uvScale = tUvScale;
uvShift = tUvShift;
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
GeomUtil.CopyMesh(inputMesh, outputMesh);
Bounds bounds = outputMesh.bounds;
Vector3 size = bounds.size;
Vector3[] vertices = outputMesh.vertices;
Vector2[] uvs = new Vector2[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
uvs[i] = new Vector2(vertices[i].x / size.x, vertices[i].z / size.z) * uvScale + uvShift;
}
outputMesh.SetUVs(0, uvs);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9deef960c4623f0438f908d9a5841cfa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,88 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// Generates UV sphere tcoords via imgui
/// </summary>
public class UVSphereProjectEditor : EditorWindow
{
public float radius = 1.0f;
public float uvScale = 2.0f;
public Vector3 center = new Vector3(0.0f, 0.0f, 0.0f);
public Mesh inputMesh = null;
public Mesh outputMesh = null;
public static void Init(Mesh inputMesh, Mesh outputMesh)
{
UVSphereProjectEditor window = GetWindow(typeof(UVSphereProjectEditor)) as UVSphereProjectEditor;
window.inputMesh = inputMesh;
window.outputMesh = outputMesh;
// Initialize to the bounds of the input mesh
window.center = inputMesh.bounds.center;
window.radius = inputMesh.bounds.size.magnitude * 0.5f;
window.UpdateEditorResults();
window.Show();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
inputMesh = EditorGUILayout.ObjectField("Input Mesh: ", inputMesh, typeof(Mesh), true) as Mesh;
Vector3 tCenter = EditorGUILayout.Vector3Field("Center: ", center);
float tRadius = EditorGUILayout.FloatField("Radius: ", radius);
float tUvScale = EditorGUILayout.FloatField("UV Scale: ", uvScale);
// \todo: How to get undo to also call UpdateInputObj?
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(this, "Change of Parameters");
radius = Mathf.Max(tRadius, 0.0f);
uvScale = tUvScale;
center = tCenter;
UpdateEditorResults();
}
}
private void UpdateEditorResults()
{
GeomUtil.CopyMesh(inputMesh, outputMesh);
Vector3[] vertices = outputMesh.vertices;
Vector2[] uvs = new Vector2[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
Vector3 diff = vertices[i] - center;
// Compute phi and theta on the sphere
float theta = Mathf.Asin(diff.x / radius);
float phi = Mathf.Atan2(diff.y, diff.z);
uvs[i] = new Vector2(phi / (Mathf.PI * 2.0f) + 0.5f, theta / (Mathf.PI * 2.0f) + 0.5f) * uvScale;
}
outputMesh.SetUVs(0, uvs);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 29dbcb8127ce46e40a5aedbf66f68d77
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,317 @@
/*=========================================================================
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 ImstkUnity;
using System;
using UnityEditor;
using UnityEngine;
namespace ImstkEditor
{
/// <summary>
/// Used to display geometry components in the editor view and inspector
/// </summary>
[CustomEditor(typeof(GeometryFilter), true)]
[InitializeOnLoad]
class GeometryFilterEditor : Editor
{
public override void OnInspectorGUI()
{
OnGeomGUI();
OnPrimitiveGeomGUI();
}
protected void OnGeomGUI()
{
GeometryFilter geomFilter = target as GeometryFilter;
EditorGUI.BeginChangeCheck();
bool showHandles = EditorGUILayout.Toggle("Show Handles", geomFilter.showHandles);
GeometryType newType = (GeometryType)EditorGUILayout.EnumPopup("Geom Type", geomFilter.type);
UnityEngine.Object abstractMesh = null;
// If unity mesh, let user slot an asset
if (newType == GeometryType.UnityMesh)
{
// Accepts either a Mesh or MeshFilter. If MeshFilter, then pulls the mesh out and uses that
// This is because users
UnityEngine.Object obj = EditorGUILayout.ObjectField("Mesh", geomFilter.inputUnityGeom, typeof(UnityEngine.Object), true);
if (obj as MeshFilter != null)
{
abstractMesh = (obj as MeshFilter).sharedMesh;
}
else if (obj as Mesh != null)
{
abstractMesh = obj as Mesh;
}
else
{
if (abstractMesh != null)
{
Debug.LogWarning("Tried to set object of type " + abstractMesh.GetType().Name + " on GeometryFilter");
}
}
}
// If an imstk mesh, let user slot an asset for it
else if (newType == GeometryType.SurfaceMesh ||
newType == GeometryType.LineMesh ||
newType == GeometryType.TetrahedralMesh ||
newType == GeometryType.HexahedralMesh ||
newType == GeometryType.PointSet)
{
abstractMesh = EditorGUILayout.ObjectField("iMSTKMesh", geomFilter.inputImstkGeom, typeof(Geometry), true);
}
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(geomFilter, "Change of GeomFilter");
geomFilter.showHandles = showHandles;
// If the type changed unslot the geometry from the component
if (newType != geomFilter.type)
{
geomFilter.inputImstkGeom = null;
geomFilter.inputUnityGeom = null;
geomFilter.type = newType;
abstractMesh = null;
}
// If the mesh changed, call the appropriate setter for it
if (abstractMesh != null)
{
if ((abstractMesh as Mesh) != null)
geomFilter.SetGeometry(abstractMesh as Mesh);
else if ((abstractMesh as Geometry) != null)
geomFilter.SetGeometry(abstractMesh as Geometry);
}
SceneView.RepaintAll();
}
if (geomFilter.type == GeometryType.SurfaceMesh ||
geomFilter.type == GeometryType.UnityMesh)
{
if (GUILayout.Button("Write Mesh"))
{
WriteMesh(geomFilter, ".ply");
}
}
}
protected void OnPrimitiveGeomGUI()
{
GeometryFilter geomFilter = target as GeometryFilter;
if (geomFilter.type == GeometryType.Capsule)
{
if (geomFilter.inputImstkGeom == null)
{
geomFilter.SetGeometry(CreateInstance<Capsule>());
}
Capsule source = geomFilter.inputImstkGeom as Capsule;
Capsule target = CreateInstance<Capsule>();
EditorGUI.BeginChangeCheck();
target.center = EditorGUILayout.Vector3Field("Center", source.center);
target.radius = Mathf.Max(EditorGUILayout.FloatField("Radius", source.radius), float.Epsilon);
target.length = Mathf.Max(EditorGUILayout.FloatField("Length", source.length), float.Epsilon);
target.orientation = EditorGUILayout.Vector4Field("Orientation", source.orientation.ToVector4()).ToQuat();
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(geomFilter, "Change of GeomFilter Geom");
geomFilter.inputImstkGeom = target;
SceneView.RepaintAll();
}
}
else if (geomFilter.type == GeometryType.Cylinder)
{
if (geomFilter.inputImstkGeom == null)
{
geomFilter.SetGeometry(CreateInstance<Cylinder>());
}
Cylinder source = geomFilter.inputImstkGeom as Cylinder;
Cylinder target = CreateInstance<Cylinder>();
EditorGUI.BeginChangeCheck();
target.center = EditorGUILayout.Vector3Field("Center", source.center);
target.radius = Mathf.Max(EditorGUILayout.FloatField("Radius", source.radius), float.Epsilon);
target.length = Mathf.Max(EditorGUILayout.FloatField("Length", source.length), float.Epsilon);
target.orientation = EditorGUILayout.Vector4Field("Orientation", source.orientation.ToVector4()).ToQuat();
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(geomFilter, "Change of GeomFilter Geom");
geomFilter.inputImstkGeom = target;
SceneView.RepaintAll();
}
}
else if (geomFilter.type == GeometryType.OrientedBox)
{
if (geomFilter.inputImstkGeom == null)
{
geomFilter.SetGeometry(CreateInstance<OrientedBox>());
}
OrientedBox source = geomFilter.inputImstkGeom as OrientedBox;
OrientedBox target = CreateInstance<OrientedBox>();
EditorGUI.BeginChangeCheck();
target.center = EditorGUILayout.Vector3Field("Center", source.center);
target.extents = EditorGUILayout.Vector3Field("Extents", source.extents).cwiseMax(new Vector3(float.Epsilon, float.Epsilon, float.Epsilon)); ;
target.orientation = EditorGUILayout.Vector4Field("Orientation", source.orientation.ToVector4()).ToQuat();
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(geomFilter, "Change of GeomFilter Geom");
geomFilter.inputImstkGeom = target;
SceneView.RepaintAll();
}
}
else if (geomFilter.type == GeometryType.Plane)
{
if (geomFilter.inputImstkGeom == null)
{
geomFilter.SetGeometry(CreateInstance<ImstkUnity.Plane>());
}
ImstkUnity.Plane source = geomFilter.inputImstkGeom as ImstkUnity.Plane;
ImstkUnity.Plane target = CreateInstance<ImstkUnity.Plane>();
EditorGUI.BeginChangeCheck();
target.center = EditorGUILayout.Vector3Field("Center", source.center);
target.normal = EditorGUILayout.Vector3Field("Normal", source.normal);
target.visualWidth = Mathf.Max(EditorGUILayout.FloatField("Visual Width", source.visualWidth), float.Epsilon);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(geomFilter, "Change of GeomFilter Geom");
geomFilter.inputImstkGeom = target;
SceneView.RepaintAll();
}
}
else if (geomFilter.type == GeometryType.Sphere)
{
if (geomFilter.inputImstkGeom == null)
{
geomFilter.SetGeometry(CreateInstance<Sphere>());
}
Sphere source = geomFilter.inputImstkGeom as Sphere;
Sphere target = CreateInstance<Sphere>();
EditorGUI.BeginChangeCheck();
target.center = EditorGUILayout.Vector3Field("Center", source.center);
target.radius = Mathf.Max(EditorGUILayout.FloatField("Radius", source.radius), float.Epsilon);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(geomFilter, "Change of GeomFilter Geom");
geomFilter.inputImstkGeom = target;
SceneView.RepaintAll();
}
}
}
[DrawGizmo(GizmoType.InSelectionHierarchy | GizmoType.NotInSelectionHierarchy)]
static void DrawHandles(GeometryFilter geomFilter, GizmoType gizmoType)
{
if (!geomFilter.showHandles) return;
if (geomFilter.inputUnityGeom == null && geomFilter.inputImstkGeom == null) return;
if (geomFilter.type == GeometryType.UnityMesh)
{
Transform transform = geomFilter.gameObject.GetComponent<Transform>();
Mesh mesh = geomFilter.inputUnityGeom;
ImstkGizmos.DrawMesh(mesh, transform.position, transform.rotation, transform.lossyScale);
}
else
{
Transform transform = geomFilter.gameObject.GetComponent<Transform>();
Geometry geom = geomFilter.inputImstkGeom;
if (geom.geomType == GeometryType.Capsule)
{
Capsule capsule = geom as Capsule;
Mesh displayMesh = capsule.GetMesh();
Gizmos.DrawWireMesh(displayMesh, 0, transform.position, transform.rotation, new Vector3(1.0f, 1.0f, 1.0f));
}
else if (geom.geomType == GeometryType.Cylinder)
{
Cylinder cylinder = geom as Cylinder;
Mesh displayMesh = cylinder.GetMesh();
Gizmos.DrawWireMesh(displayMesh, 0, transform.position, transform.rotation, new Vector3(1.0f, 1.0f, 1.0f));
}
else if (geom.geomType == GeometryType.OrientedBox)
{
OrientedBox orientedBox = geom as OrientedBox;
Mesh displayMesh = orientedBox.GetMesh();
Gizmos.DrawWireMesh(displayMesh, 0, transform.position, transform.rotation, transform.localScale);
}
else if (geom.geomType == GeometryType.Plane)
{
// Unity's planes default config for drawing is normal along z. So we rotate from z to normal
ImstkUnity.Plane plane = geom as ImstkUnity.Plane;
Handles.RectangleHandleCap(0, plane.GetTransformedCenter(transform),
Quaternion.FromToRotation(Vector3.forward, plane.GetTransformedNormal(transform)), plane.visualWidth, EventType.Repaint);
}
else if (geom.geomType == GeometryType.Sphere)
{
Sphere sphere = geom as Sphere;
Mesh displayMesh = sphere.GetMesh();
Gizmos.DrawWireMesh(displayMesh, 0, transform.position, transform.rotation, transform.lossyScale);
}
else if (geom.geomType == GeometryType.PointSet ||
geom.geomType == GeometryType.LineMesh ||
geom.geomType == GeometryType.SurfaceMesh)
{
ImstkMesh mesh = geom as ImstkMesh;
ImstkGizmos.DrawMesh(mesh.ToMesh(), transform.position, transform.rotation, transform.localScale);
}
else if (geom.geomType == GeometryType.TetrahedralMesh)
{
var tetMesh = Imstk.Utils.CastTo<Imstk.TetrahedralMesh>(geomFilter.GetOutputGeometry());
Imstk.SurfaceMesh surfMesh = tetMesh.extractSurfaceMesh();
Debug.Assert(tetMesh != null);
var toWorld = transform.localToWorldMatrix;
surfMesh.transform(toWorld.ToMat4d());
surfMesh.updatePostTransformData();
// Note probably not really performant ...
Gizmos.DrawWireMesh(surfMesh.ToMesh());
}
}
}
private void WriteMesh(GeometryFilter script, string type)
{
var components = script.GetComponents<GeometryFilter>();
int i = Array.IndexOf(components, script);
script.WriteMesh(script.gameObject.name + "_" + i.ToString() + type);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: beaa834f9e135c04e8538c213b9b5db2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,137 @@
/*=========================================================================
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
{
/// <summary>
/// This class reads in various types of geometry utilized by Imstk
/// </summary>
[UnityEditor.AssetImporters.ScriptedImporter(1, new string[] { "vtk", "vtu", "vtp", "stl", "ply", "veg", "msh", "mhd" })]
public class GeometryImporter : UnityEditor.AssetImporters.ScriptedImporter
{
/// <summary>
/// When on, reverses winding of cells (currently only works for surface meshes)
/// </summary>
public bool reverseWinding = false;
// Default is mirror along the X-Axis
public Matrix4x4 transform = Matrix4x4.Scale(new Vector3(-1, 1, 1));
[Tooltip("If true, will center the mesh around the origin")]
public bool centerMesh = false;
public override void OnImportAsset(UnityEditor.AssetImporters.AssetImportContext ctx)
{
string assetsPath = Application.dataPath;
assetsPath = assetsPath.Replace("Assets", "");
string filePath = assetsPath + ctx.assetPath;
string fileName = System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath);
// Read the geometry using imstk, warning: type not correct use conversion funcs
Imstk.PointSet pointSet = Imstk.MeshIO.read(filePath);
// Create resource to load into
// Setup a default cube, remove BoxCollider, replace mesh, add Geometry (Imstk), replace Mesh (Unity)
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
DestroyImmediate(obj.GetComponent<BoxCollider>());
obj.name = fileName;
if (centerMesh)
{
var vertices = pointSet.getVertexPositions();
var center = new Imstk.Vec3d(0, 0, 0);
for (uint i = 0; i < vertices.size(); ++i)
{
center += vertices[i];
}
center = center / vertices.size();
pointSet.translate(center*-1.0, Imstk.Geometry.TransformType.ApplyToData);
}
if (pointSet.getTypeName() == Imstk.LineMesh.getStaticTypeName())
{
Imstk.LineMesh lineMesh = Imstk.Utils.CastTo<Imstk.LineMesh>(pointSet);
lineMesh.transform(transform.ToMat4d(), Imstk.Geometry.TransformType.ApplyToData);
lineMesh.updatePostTransformData();
Mesh mesh = lineMesh.ToMesh();
foreach (var v in mesh.vertices)
{
Debug.Log(v);
}
mesh.name = fileName + "_mesh";
obj.GetComponent<MeshFilter>().sharedMesh = mesh;
ctx.AddObjectToAsset(obj.name, obj);
ctx.AddObjectToAsset(mesh.name, mesh); // Add to the load asset
}
else if (pointSet.getTypeName() == Imstk.SurfaceMesh.getStaticTypeName())
{
Imstk.SurfaceMesh surfMesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(pointSet);
surfMesh.transform(transform.ToMat4d(), Imstk.Geometry.TransformType.ApplyToData);
surfMesh.updatePostTransformData();
if (reverseWinding)
{
surfMesh.flipNormals();
}
Mesh mesh = surfMesh.ToMesh();
mesh.name = fileName + "_mesh";
obj.GetComponent<MeshFilter>().sharedMesh = mesh;
ctx.AddObjectToAsset(obj.name, obj);
ctx.AddObjectToAsset(mesh.name, mesh); // Add to the load asset
}
else if (pointSet.getTypeName() == Imstk.TetrahedralMesh.getStaticTypeName())
{
Imstk.TetrahedralMesh tetMesh = Imstk.Utils.CastTo<Imstk.TetrahedralMesh>(pointSet);
if (tetMesh == null)
{
return;
}
tetMesh.transform(transform.ToMat4d(), Imstk.Geometry.TransformType.ApplyToData);
tetMesh.updatePostTransformData();
Imstk.SurfaceMesh surfMesh = tetMesh.extractSurfaceMesh();
if (reverseWinding)
{
surfMesh.flipNormals();
}
Geometry tetGeom = tetMesh.ToImstkMesh();
tetGeom.name = fileName + "_mesh";
Mesh mesh = surfMesh.ToMesh();
mesh.name = fileName + "_mesh_surface";
obj.GetComponent<MeshFilter>().sharedMesh = mesh;
ctx.AddObjectToAsset(obj.name, obj);
ctx.AddObjectToAsset(mesh.name, mesh); // Add to the load asset
// \todo: Add a custom thumbnail for the tetrahedral mesh
ctx.AddObjectToAsset(tetGeom.name, tetGeom);
}
ctx.SetMainObject(obj);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e43119e965e82b041aac262bc0f72039
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,183 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// For menu'd geometry operations. Could spin off into own GUI as it gets larger.
/// GUI for parameters needs to be done up as well for some
/// </summary>
class GeometryMenuItems
{
/// <summary>
/// Creates UVs per vertex on plane for GameObjects MeshFilter mesh
/// </summary>
[MenuItem("iMSTK/Geometry/ProjectUVPlane")]
private static void ProjectUVPlane()
{
Vector2 scale = new Vector2(1.0f, 1.0f);
// \todo: Plane option
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogWarning("ProjectUVPlane failed, no object selected.");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
UVPlaneProjectEditor.Init(inputMesh, meshFilter.sharedMesh);
}
/// <summary>
/// Creates UVs per vertex on sphere for GameObjects MeshFilter mesh
/// </summary>
[MenuItem("iMSTK/Geometry/ProjectUVSphere")]
private static void ProjectUVSphere()
{
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogWarning("ProjectUVSphere failed, no object selected.");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
UVSphereProjectEditor.Init(inputMesh, meshFilter.sharedMesh);
}
/// <summary>
/// Laplacian smoothens a mesh
/// </summary>
[MenuItem("iMSTK/Geometry/LaplaceSmoothMesh")]
private static void LaplaceSmoothMesh()
{
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogWarning("LaplaceSmoothMesh failed, no object selected.");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
LaplaceSmoothEditor.Init(inputMesh, meshFilter.sharedMesh);
}
/// <summary>
/// Subdivides a triangle mesh
/// </summary>
[MenuItem("iMSTK/Geometry/SubdivideMesh")]
private static void SubdivideMesh()
{
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogWarning("LaplaceSmoothMesh failed, no object selected.");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
SubdivideMeshEditor.Init(inputMesh, meshFilter.sharedMesh);
}
/// <summary>
/// Generates a tet grid on the currently selected object
/// </summary>
[MenuItem("iMSTK/Geometry/Generate TetGrid")]
private static void GenerateTetGrid()
{
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogWarning("TetGrid generation failed, no object selected.");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
Mesh inputMesh = meshFilter.sharedMesh;
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputMesh.name;
GeometryFilter tetGridFilter = inputObj.AddComponent<GeometryFilter>();
ImstkMesh tetMesh = ScriptableObject.CreateInstance<ImstkMesh>();
tetMesh.geomType = GeometryType.TetrahedralMesh;
tetGridFilter.SetGeometry(tetMesh);
// Operates on the whole object as it provides the tetrahedral mesh on a separate geometry
TetrahedralGridEditor.Init(meshFilter.sharedMesh, tetGridFilter.inputImstkGeom as ImstkMesh);
}
/// <summary>
/// Generates a plane mesh on the currently selected object
/// </summary>
[MenuItem("iMSTK/Geometry/Generate Plane")]
private static void GeneratePlane()
{
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogWarning("Plane generation failed, no object selected.");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
PlaneMeshEditor.Init(meshFilter.sharedMesh);
}
/// <summary>
/// Generates a line mesh on the currently selected object
/// </summary>
[MenuItem("iMSTK/Geometry/Generate LineMesh")]
private static void GenerateLineMesh()
{
GameObject inputObj = Selection.activeObject as GameObject;
if (inputObj == null)
{
Debug.LogError("Select an object before opening the LineMesh Editor");
return;
}
MeshFilter meshFilter = inputObj.GetComponentOrCreate<MeshFilter>();
inputObj.GetComponentOrCreate<MeshRenderer>();
if (meshFilter.sharedMesh == null)
{
meshFilter.sharedMesh = new Mesh();
meshFilter.sharedMesh.name = inputObj.name + "_mesh";
} else
{
Debug.LogWarning("This will overwrite the current mesh.");
}
LineMeshEditor.Init(meshFilter.sharedMesh);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8934b7d83f4f03246ae61fe806001275
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,129 @@
using ImstkUnity;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace ImstkEditor
{
[CustomEditor(typeof(GraspingManager))]
public class GraspingManagerEditor : Editor
{
bool _folded = true;
Rigid _rigid;
GeometryFilter _graspingGeometry;
List<GraspingManager.GraspingData> _graspingData;
List<DynamicalModel> _allDeformables = new List<DynamicalModel>();
GUIContent _warning;
double _deformableGraspingStiffness;
double _rigidGraspingStiffness;
GraspingManagerEditor()
{
EditorApplication.hierarchyChanged += OnHierarchyChanged;
}
private void OnHierarchyChanged()
{
_allDeformables = (Resources.FindObjectsOfTypeAll(typeof(DynamicalModel)) as DynamicalModel[]).ToList<DynamicalModel>();
}
public override void OnInspectorGUI()
{
if (_allDeformables.Count == 0) OnHierarchyChanged();
var script = target as GraspingManager;
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal();
_rigid = EditorGUILayout.ObjectField("Grasping Object",
script.rigid, typeof(ImstkUnity.Rigid), true) as ImstkUnity.Rigid;
if (script.rigid == null)
{
_warning = EditorGUIUtility.IconContent("Error", "|Grasping Object Can't be null");
EditorGUILayout.LabelField(_warning, GUILayout.Width(_warning.image.width));
}
EditorGUILayout.EndHorizontal();
_graspingGeometry = EditorGUILayout.ObjectField("Grasping Geometry (Optional)",
script.graspingGeometry, typeof(GeometryFilter), true) as GeometryFilter;
GUILayout.BeginVertical(EditorStyles.helpBox);
_deformableGraspingStiffness = EditorGUILayout.DoubleField("Deformable Grasping Stiffness", script.deformableGraspingStiffness);
_rigidGraspingStiffness = EditorGUILayout.DoubleField("Rigid Grasping Stiffness", script.rigidGraspingStiffness);
GUILayout.EndVertical();
// Maybe this is something we should do for all imstk components
// as we can't edit them during runtime anyway
if (_rigid != null && !Application.isPlaying)
{
// Takes up a lot of resources when playing, just don't execute
HandleGraspingData(script);
UpdateScript(script);
}
else
{
EditorGUI.EndChangeCheck();
}
}
private void UpdateScript(GraspingManager script)
{
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(script, "Change of Parameters");
script.rigid = _rigid;
script.graspingGeometry = _graspingGeometry;
script.graspingData = new List<GraspingManager.GraspingData>(_graspingData);
script.deformableGraspingStiffness = _deformableGraspingStiffness;
script.rigidGraspingStiffness = _rigidGraspingStiffness;
}
}
private void HandleGraspingData(GraspingManager script)
{
// if there aren't any items to grasp, make sure ...
if (_allDeformables.Count == 0) OnHierarchyChanged();
_graspingData = new List<GraspingManager.GraspingData>(script.graspingData);
foreach (var item in _allDeformables)
{
if (item is StaticModel || item == _rigid) continue;
if (_graspingData.FindIndex(x => x.target == item) < 0)
{
GraspingManager.GraspingData graspingData = new GraspingManager.GraspingData();
graspingData.enabled = false;
graspingData.type = Grasping.GraspType.Cell;
graspingData.target = item;
_graspingData.Add(graspingData);
}
}
// Remove stale Objects
_graspingData.RemoveAll(x => !_allDeformables.Contains(x.target));
_folded = EditorGUILayout.Foldout(_folded, "Graspable Objects");
if (_folded)
{
EditorGUILayout.BeginVertical();
for (int i = 0; i < _graspingData.Count; ++i)
{
var item = _graspingData[i];
EditorGUILayout.BeginHorizontal();
item.enabled = EditorGUILayout.Toggle(item.enabled, GUILayout.Width(20));
EditorGUI.BeginDisabledGroup(!item.enabled);
EditorGUILayout.LabelField(item.target.name);
item.type = (Grasping.GraspType)EditorGUILayout.EnumPopup(item.type);
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndHorizontal();
_graspingData[i] = item;
}
EditorGUILayout.EndVertical();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 90bae2d9e1ecd124b913832a0a5a1abb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,113 @@
/*=========================================================================
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 ImstkUnity;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace ImstkEditor
{
/// <summary>
/// Defines the gui to fill ImstkSettings
/// </summary>
class ImstkSettingsProvider : SettingsProvider
{
private ImstkSettings settings;
public ImstkSettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope) { }
public static bool IsSettingsAvailable() { return File.Exists(ImstkSettings.settingsPath); }
// Read existing settings or create settings if they don't exist when user clicks them
public override void OnActivate(string searchContext, VisualElement rootElement) { settings = ImstkSettings.Instance(); }
public override void OnGUI(string searchContext)
{
EditorGUI.BeginChangeCheck();
bool useOptimalNumberOfThreads = EditorGUILayout.Toggle("Use Optimal # Threads", settings.useOptimalNumberOfThreads);
//int numThreads = settings.numThreads;
//if (!useOptimalNumberOfThreads)
// numThreads = EditorGUILayout.IntField("# Threads", numThreads);
EditorGUILayout.HelpBox(
"When developer mode is on you will be prompted to install imstk " +
" this can only be done by restarting unity as the editor will may load dll's preventing you from installing imstk" +
" while the editor is running.", MessageType.Warning);
bool useDevMode = EditorGUILayout.Toggle("Use Developer Mode", settings.useDeveloperMode);
string installPath = settings.installSourcePath;
if (useDevMode)
{
GUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.BeginHorizontal();
GUILayout.Label("iMSTK Install Directory");
installPath = EditorGUILayout.TextField(installPath);
if (GUILayout.Button("Open Directory"))
{
installPath = EditorUtility.OpenFolderPanel("iMSTK Install Directory (Development Use)", settings.installSourcePath, "");
}
GUILayout.EndHorizontal();
EditorGUILayout.HelpBox("Force install will attempt to perform an install now. This may not work if " +
"any imstk libraries are already loaded.",
MessageType.Warning);
if (GUILayout.Button("Force Install"))
{
EditorUtils.InstallImstk(installPath);
}
GUILayout.EndVertical();
}
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(settings, "Change of Settings");
settings.useDeveloperMode = useDevMode;
settings.useOptimalNumberOfThreads = useOptimalNumberOfThreads;
//settings.numThreads = numThreads;
settings.installSourcePath = installPath;
if (!System.IO.Directory.Exists(ImstkSettings.settingsDirectory))
{
System.IO.Directory.CreateDirectory(ImstkSettings.settingsDirectory);
}
EditorUtility.SetDirty(settings);
AssetDatabase.SaveAssets();
}
}
/// <summary>
/// Register the SettingsProvider so it can be found in Editor->Project Settings
/// </summary>
[SettingsProvider]
public static SettingsProvider CreateMyCustomSettingsProvider()
{
var provider = new ImstkSettingsProvider("Project/iMSTK Settings", SettingsScope.Project);
provider.keywords = new HashSet<string>(new string[] { "Debug", "Logger", "Threads", "iMSTK" });
return provider;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 195737e5160741b4a8d43f53837040df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
/*=========================================================================
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 ImstkUnity;
using UnityEditor;
namespace ImstkEditor
{
/// <summary>
/// This class observes the play mode state to properly pause and step
/// Imstk in the Unity editor
/// </summary>
[InitializeOnLoad]
class PlayModeStateObserver
{
static PlayModeStateObserver()
{
#if UNITY_EDITOR
// Perform imstk install if developer mode is on
ImstkSettings settings = ImstkSettings.Instance();
if (settings.useDeveloperMode &&
EditorUtility.DisplayDialog("Do you want to install imstk",
"To install imstk select yes and provide your imstk build/install directory. If you would not " +
"like to be prompted again, please turn off developer mode in imstk settings. Note: " +
"This prompt will be displayed upon installation again, select no second time.", "Yes", "No"))
{
settings.installSourcePath =
EditorUtility.OpenFolderPanel("iMSTK Install Directory (Development Use)", settings.installSourcePath, "");
EditorUtils.InstallImstk(settings.installSourcePath);
EditorUtility.SetDirty(settings);
AssetDatabase.SaveAssets();
}
#endif
//EditorApplication.playModeStateChanged += playModeStateChanged;
EditorApplication.pauseStateChanged += pauseStateChanged;
}
private static void pauseStateChanged(PauseState state)
{
if (SimulationManager.sceneManager != null)
{
bool paused = SimulationManager.sceneManager.getPaused();
if (paused)
{
SimulationManager.sceneManager.setPaused(true);
}
else
{
SimulationManager.sceneManager.setPaused(false);
}
}
}
//private static void playModeStateChanged(PlayModeStateChange state) { }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e6b12b0479820f43b977a10b5399b5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,196 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
[CustomEditor(typeof(RigidController))]
public class RigidControllerEditor : Editor
{
Vector3 _attachmentPoint;
Vector3 _translationalOffset;
Vector3 _rotationalOffset;
Vector3 _localRotationalOffset;
double _translationScaling;
public override void OnInspectorGUI()
{
RigidController script = target as RigidController;
EditorGUI.BeginChangeCheck();
GUILayout.BeginVertical(EditorStyles.helpBox);
TrackingDevice results = script.device;
Object obj = EditorGUILayout.ObjectField("Device", results, typeof(Object), true) as Object;
if (obj is TrackingDevice)
{
results = obj as TrackingDevice;
}
else if (obj is GameObject)
{
results = (obj as GameObject).GetComponent<TrackingDevice>();
}
else
{
Debug.LogWarning("Cannot set object on field, expects TrackingDevice or game object with TrackingDevice");
}
Rigid rigid = EditorGUILayout.ObjectField("Rigid", script.rigid, typeof(Rigid), true) as Rigid;
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
bool useCriticalDamping = EditorGUILayout.Toggle("Critical Damping", script.useCriticalDamping);
double linearKs = EditorGUILayout.DoubleField("Linear Spring Constant", script.linearKs);
double linearKd = script.linearKd;
if (!useCriticalDamping)
{
linearKd = EditorGUILayout.DoubleField("Linear Damping", script.linearKd);
}
double angularKs = EditorGUILayout.DoubleField("Angular Spring Constant", script.angularKs);
double angularKd = script.angularKd;
if (!useCriticalDamping)
{
angularKd = EditorGUILayout.DoubleField("Angular Damping", script.angularKd);
}
GUILayout.EndVertical();
script._forceFoldout = EditorGUILayout.Foldout(script._forceFoldout, "Force Settings");
double forceScaling = script.forceScale;
bool useForceSmoothing = script.useForceSmoothing;
int forceSmoothKernelSize = script.forceSmoothingKernelSize;
if (script._forceFoldout)
{
GUILayout.BeginVertical(EditorStyles.helpBox);
forceScaling = EditorGUILayout.DoubleField("Force Scaling", script.forceScale);
useForceSmoothing = EditorGUILayout.Toggle("Use Force Smoothing", script.useForceSmoothing);
forceSmoothKernelSize =
EditorGUILayout.IntField("Force Smooth Kernel Size", script.forceSmoothingKernelSize);
GUILayout.EndVertical();
}
var offsetContent = new GUIContent("Offsets", "Settings that will transform the controlled objects coordinate system in " +
"relation to the device coordinate system");
script._offsetFoldout = EditorGUILayout.Foldout(script._offsetFoldout, offsetContent);
// Initialize in case the foldout is closed
_attachmentPoint = script.attachmentPoint;
_translationScaling = script.translationScaling;
_translationalOffset = script.translationalOffset;
_rotationalOffset = script.rotationalOffset.eulerAngles;
_localRotationalOffset = script.localRotationalOffset.eulerAngles;
if (script._offsetFoldout)
{
GUILayout.BeginVertical(EditorStyles.helpBox);
_attachmentPoint = EditorGUILayout.Vector3Field("Attachment Point", script.attachmentPoint);
if (GUILayout.Button("Copy Translational Offset from Transform"))
{
_translationalOffset = script.transform.position;
} else
{
_translationalOffset =
EditorGUILayout.Vector3Field("Translational Offset", script.translationalOffset);
}
_rotationalOffset =
EditorGUILayout.Vector3Field("Rotational Offset", script.rotationalOffset.eulerAngles);
_localRotationalOffset =
EditorGUILayout.Vector3Field("Local Rotational Offset", script.localRotationalOffset.eulerAngles);
_translationScaling =
EditorGUILayout.DoubleField("Translation Scaling", script.translationScaling);
GUILayout.EndVertical();
}
script._axisMappingFoldout = EditorGUILayout.Foldout(script._axisMappingFoldout, "Coordinate Transforms");
bool invertX = script.invertX;
bool invertY = script.invertY;
bool invertZ = script.invertZ;
bool rotInvertX = script.invertRotX;
bool rotInvertY = script.invertRotY;
bool rotInvertZ = script.invertRotZ;
if (script._axisMappingFoldout)
{
GUILayout.BeginVertical(EditorStyles.helpBox);
invertX = EditorGUILayout.Toggle("Invert X", script.invertX);
invertY = EditorGUILayout.Toggle("Invert Y", script.invertY);
invertZ = EditorGUILayout.Toggle("Invert Z", script.invertZ);
rotInvertX = EditorGUILayout.Toggle("Rotation Invert X", script.invertRotX);
rotInvertY = EditorGUILayout.Toggle("Rotation Invert Y", script.invertRotY);
rotInvertZ = EditorGUILayout.Toggle("Rotation Invert Z", script.invertRotZ);
GUILayout.EndVertical();
}
bool debugController = EditorGUILayout.Toggle("Write Controller transform", script.debugController);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(script, "Change of Parameters");
script.device = results;
script.rigid = rigid;
script.angularKd = angularKd;
script.angularKs = angularKs;
script.linearKd = linearKd;
script.linearKs = linearKs;
script.useCriticalDamping = useCriticalDamping;
script.forceScale = forceScaling;
script.useForceSmoothing = useForceSmoothing;
script.forceSmoothingKernelSize = forceSmoothKernelSize;
script.attachmentPoint = _attachmentPoint;
script.translationalOffset = _translationalOffset;
script.rotationalOffset.eulerAngles = _rotationalOffset;
script.localRotationalOffset.eulerAngles = _localRotationalOffset;
script.translationScaling = _translationScaling;
script.invertX = invertX;
script.invertY = invertY;
script.invertZ = invertZ;
script.invertRotX = rotInvertX;
script.invertRotY = rotInvertY;
script.invertRotZ = rotInvertZ;
script.debugController = debugController;
}
}
[DrawGizmo(GizmoType.InSelectionHierarchy)]
static void DrawHandles(RigidController scr, GizmoType gizmoType)
{
var pos = scr.transform.localToWorldMatrix.MultiplyPoint(scr.attachmentPoint);
// Draw a sphere at the haptic attachment point
Gizmos.color = Color.red;
Gizmos.DrawSphere(pos, 0.02f);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b142915e0959468428258cc9dc36f4b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+155
View File
@@ -0,0 +1,155 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
using Imstk;
namespace ImstkEditor
{
[CustomEditor(typeof(Rigid))]
class RigidEditor : DynamicalModelEditor
{
GeometryFilter _physicsGeometryFilter;
bool _drawPhysicsGeometry = false;
GeometryFilter _collisionGeometryFilter;
bool _drawCollisionGeometry = false;
bool _bodyDamping = false;
double _linearDampingCoeff = 0.0;
double _angularDampingCoeff = 0.0;
readonly GUIContent _debugContent = new GUIContent("","Draw debug mesh");
readonly GUILayoutOption _checkBoxWidth = GUILayout.Width(20);
public override void OnInspectorGUI()
{
Rigid script = target as Rigid;
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal();
_physicsGeometryFilter = EditorUtils.GeomFilterField("Physics Geometry", script.physicsGeomFilter);
_drawPhysicsGeometry = EditorGUILayout.Toggle(_debugContent, script.drawPhysicsGeometry, _checkBoxWidth);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
_collisionGeometryFilter = EditorUtils.GeomFilterField("Collision Geometry", script.collisionGeomFilter);
_drawCollisionGeometry = EditorGUILayout.Toggle(_debugContent, script.drawCollisionGeometry, _checkBoxWidth);
EditorGUILayout.EndHorizontal();
GUILayout.BeginVertical(EditorStyles.helpBox);
double mass = EditorGUILayout.DoubleField("Mass", script.mass);
if (mass < 0.0)
{
Debug.LogWarning("Mass cannot be negative!");
mass = 0.0;
}
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.Label("Inertia Tensor");
Vector3 inertiaRow1 = EditorGUILayout.Vector3Field("", script.inertia[0]);
Vector3 inertiaRow2 = EditorGUILayout.Vector3Field("", script.inertia[1]);
Vector3 inertiaRow3 = EditorGUILayout.Vector3Field("", script.inertia[2]);
GUILayout.EndVertical();
var ignoreGravity = EditorGUILayout.Toggle("Ignore Gravity", script.ignoreGravity);
GUILayout.BeginVertical(EditorStyles.helpBox);
_bodyDamping = EditorGUILayout.Toggle("Use Body Damping", script.useBodyDamping);
if (_bodyDamping)
{
_linearDampingCoeff = EditorGUILayout.Slider("Linear Damping Coeff", (float)script.linearDampingCoeff, 0, 1);
_angularDampingCoeff = EditorGUILayout.Slider("Angular Damping Coeff", (float)script.angularDampingCoeff, 0, 1);
}
GUILayout.EndVertical();
// Need to update PbdBody class to better support this when accessing it through the wrapper
// GUILayout.BeginVertical(EditorStyles.helpBox);
// Vector3 initVel = EditorGUILayout.Vector3Field("Initial Linear Velocity", script.initVelocity);
// Vector3 initAngularVel = EditorGUILayout.Vector3Field("Initial Angular Velocity", script.initAngularVelocity);
// GUILayout.EndVertical();
//
// GUILayout.BeginVertical(EditorStyles.helpBox);
// Vector3 initForce = EditorGUILayout.Vector3Field("Initial Force", script.initForce);
// Vector3 initTorque = EditorGUILayout.Vector3Field("Initial Torque", script.initTorque);
// GUILayout.EndVertical();
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(script, "Change of Parameters");
script.physicsGeomFilter = _physicsGeometryFilter;
script.drawPhysicsGeometry = _drawPhysicsGeometry;
script.collisionGeomFilter = _collisionGeometryFilter;
script.drawCollisionGeometry = _drawCollisionGeometry;
script.mass = mass;
script.inertia[0] = inertiaRow1;
script.inertia[1] = inertiaRow2;
script.inertia[2] = inertiaRow3;
script.ignoreGravity = ignoreGravity;
script.useBodyDamping = _bodyDamping;
script.linearDampingCoeff = _linearDampingCoeff;
script.angularDampingCoeff = _angularDampingCoeff;
// script.initVelocity = initVel;
// script.initAngularVelocity = initAngularVel;
// script.initForce = initForce;
// script.initTorque = initTorque;
}
base.HandleColliders(script);
}
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
public static void DrawRigidGizmo(Rigid rigid, GizmoType gizmoType)
{
var dyn = rigid.GetDynamicObject();
var pbdObj = Imstk.Utils.CastTo<PbdObject>(dyn);
if (pbdObj != null)
{
if (rigid.drawCollisionGeometry)
{
DrawGeometryGizmo(pbdObj.getCollidingGeometry());
}
if (rigid.drawPhysicsGeometry)
{
DrawGeometryGizmo(pbdObj.getPhysicsGeometry());
}
}
}
public static void DrawGeometryGizmo(Imstk.Geometry geom)
{
var pointSet = Imstk.Utils.CastTo<PointSet>(geom);
if (pointSet != null)
{
ImstkGizmos.DrawMesh(pointSet, UnityEngine.Color.red);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68c782406a24eda4d946cef6db6f01cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,78 @@
/*=========================================================================
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 ImstkUnity;
using UnityEngine;
using UnityEditor;
namespace ImstkEditor
{
[CustomEditor(typeof(SimulationManager))]
public class SimulationManagerEditor : Editor
{
public override void OnInspectorGUI()
{
// Define a style for centering text
var centeredStyle = GUI.skin.GetStyle("Label");
centeredStyle.alignment = TextAnchor.UpperCenter;
// Begin the script modification!
SimulationManager script = target as SimulationManager;
EditorGUI.BeginChangeCheck();
GUILayout.Label("Scene Settings", centeredStyle);
GUILayout.BeginVertical(EditorStyles.helpBox);
bool writeTaskGraph = EditorGUILayout.Toggle("Write Task Graph", script.writeTaskGraph);
EditorGUILayout.HelpBox(
"This is the timestep that iMSTK will used to advance the simulation, use the stats" +
" display and testing to arrive at a reasonable value for your simulation." ,
MessageType.Warning);
float fixedTimestep = EditorGUILayout.FloatField("Fixed Timestep", script.fixedTimestep);
GUILayout.EndVertical();
GUILayout.Label("Pbd Simulation Settings", centeredStyle);
GUILayout.BeginVertical(EditorStyles.helpBox);
var c = new PbdModelConfiguration();
c.gravity = EditorGUILayout.Vector3Field("Gravity", script.pbdModelConfiguration.gravity);
c.iterations = EditorGUILayout.IntField("Max # Iterations", script.pbdModelConfiguration.iterations);
c.useRealtime = EditorGUILayout.Toggle("Use Realtime", script.pbdModelConfiguration.useRealtime);
if (!script.pbdModelConfiguration.useRealtime)
{
c.dt = EditorGUILayout.DoubleField("Delta Time", script.pbdModelConfiguration.dt);
}
c.linearDampingCoeff = EditorGUILayout.DoubleField("Linear Damping Coefficient",
script.pbdModelConfiguration.linearDampingCoeff);
c.angularDampingCoeff = EditorGUILayout.DoubleField("Angular Damping Coefficient",
script.pbdModelConfiguration.angularDampingCoeff);
c.doPartitioning = EditorGUILayout.Toggle("Partitioning", script.pbdModelConfiguration.doPartitioning);
GUILayout.EndVertical();
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(script, "Change of Parameters");
script.writeTaskGraph = writeTaskGraph;
script.pbdModelConfiguration = c;
script.fixedTimestep = fixedTimestep;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 22dc68fd2e5f4144295545ee2ff229bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,43 @@
/*=========================================================================
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 ImstkUnity;
using UnityEditor;
namespace ImstkEditor
{
[CustomEditor(typeof(StaticModel))]
class StaticModelEditor : Editor
{
public override void OnInspectorGUI()
{
StaticModel script = target as StaticModel;
EditorGUI.BeginChangeCheck();
GeometryFilter collisionGeomFilter = EditorUtils.GeomFilterField("Collision Geometry", script.collisionGeomFilter);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(script, "Change of Parameters");
script.collisionGeomFilter = collisionGeomFilter;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f318b9a7ac342f4c94f8ad8d9b618af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e91f2f601c7c29748857ba2c30b5c510
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+54
View File
@@ -0,0 +1,54 @@
/*=========================================================================
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
{
public class Capsule : Geometry
{
public Vector3 center = Vector3.zero;
public float radius = 0.5f;
public Quaternion orientation = Quaternion.identity;
public float length = 1.0f;
public Capsule()
{
geomType = GeometryType.Capsule;
}
public Vector3 GetTransformedCenter(Transform transform)
{
return transform.TransformPoint(center);
}
public Quaternion GetTransformedOrientation(Transform transform)
{
return orientation * transform.rotation;
}
public Mesh GetMesh()
{
Imstk.Capsule geom = this.ToImstkGeometry() as Imstk.Capsule;
Imstk.SurfaceMesh surfMesh = Imstk.Utils.toSurfaceMesh(geom);
return surfMesh.ToMesh();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f81a111151cf2074bb509ea399de47b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+54
View File
@@ -0,0 +1,54 @@
/*=========================================================================
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
{
public class Cylinder : Geometry
{
public Vector3 center = Vector3.zero;
public float radius = 0.5f;
public Quaternion orientation = Quaternion.identity;
public float length = 1.0f;
public Cylinder()
{
geomType = GeometryType.Cylinder;
}
public Vector3 GetTransformedCenter(Transform transform)
{
return transform.TransformPoint(center);
}
public Quaternion GetTransformedOrientation(Transform transform)
{
return orientation * transform.rotation;
}
public Mesh GetMesh()
{
Imstk.Cylinder geom = this.ToImstkGeometry() as Imstk.Cylinder;
Imstk.SurfaceMesh surfMesh = Imstk.Utils.toSurfaceMesh(geom);
return surfMesh.ToMesh();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f2f6dc9b9f9eb8c4cba5968e2b98bed2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+488
View File
@@ -0,0 +1,488 @@
/*=========================================================================
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 Imstk;
using System.Collections.Generic;
using UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// Various geometryic utility functions
/// </summary>
public static class GeomUtil
{
/// <summary>
/// Map of GeometryType to MeshTopology
/// </summary>
public static Dictionary<GeometryType, MeshTopology> geomTypeToMeshTopology = new Dictionary<GeometryType, MeshTopology>()
{
{ GeometryType.PointSet, MeshTopology.Points },
{ GeometryType.LineMesh, MeshTopology.Lines },
{ GeometryType.SurfaceMesh, MeshTopology.Triangles }
};
/// <summary>
/// Map of MeshTopology to GeometryType
/// </summary>
public static Dictionary<MeshTopology, GeometryType> meshTopologyToGeomType = new Dictionary<MeshTopology, GeometryType>()
{
{ MeshTopology.Points, GeometryType.PointSet },
{ MeshTopology.Lines, GeometryType.LineMesh },
{ MeshTopology.Triangles, GeometryType.SurfaceMesh }
};
/// <summary>
/// Preforms a simple mesh copy (only works with triangles)
/// </summary>
public static void CopyMesh(Mesh srcMesh, Mesh destMesh)
{
destMesh.triangles = null;
destMesh.vertices = srcMesh.vertices;
destMesh.uv = srcMesh.uv;
destMesh.normals = srcMesh.normals;
destMesh.colors = srcMesh.colors;
destMesh.tangents = srcMesh.tangents;
for (int i = 0; i < srcMesh.subMeshCount; i++)
{
destMesh.SetIndices(srcMesh.GetIndices(i),
srcMesh.GetTopology(i), i);
}
}
public static void CopyMesh(ImstkMesh srcMesh, ImstkMesh destMesh)
{
destMesh.vertices = srcMesh.vertices;
destMesh.indices = srcMesh.indices;
destMesh.texCoords = srcMesh.texCoords;
destMesh.geomType = srcMesh.geomType;
}
/// <summary>
/// Converts Imstk.PointSet to Unity Mesh
/// SurfaceMesh
/// </summary>
public static Mesh ToMesh(this Imstk.PointSet geom)
{
string typeName = geom.getTypeName();
if (typeName != "LineMesh" &&
typeName != "SurfaceMesh" &&
typeName != "PointSet")
{
return null;
}
Imstk.PointSet pointSet = Imstk.Utils.CastTo<Imstk.PointSet>(geom);
Mesh results = new Mesh();
Vector3[] vertices = MathUtil.ToVector3Array(pointSet.getVertexPositions());
results.SetVertices(vertices);
if (typeName == "PointSet")
{
int[] indices = new int[vertices.Length];
for (int i = 0; i < indices.Length; i++)
{
indices[i] = i;
}
results.SetIndices(indices, MeshTopology.Points, 0);
}
else if (typeName == "LineMesh")
{
Imstk.LineMesh lineMesh = Imstk.Utils.CastTo<Imstk.LineMesh>(geom);
int[] indices = MathUtil.ToIntArray(lineMesh.getLinesIndices());
results.SetIndices(indices, MeshTopology.Lines, 0);
}
else if (typeName == "SurfaceMesh")
{
Imstk.SurfaceMesh surfMesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(geom);
int[] indices = MathUtil.ToIntArray(surfMesh.getTriangleIndices());
results.SetIndices(indices, MeshTopology.Triangles, 0);
results.RecalculateNormals();
}
if (pointSet.getVertexTCoords() != null)
{
Vector2[] tCoords = MathUtil.ToVector2Array(pointSet.getVertexTCoords());
results.SetUVs(0, tCoords);
results.RecalculateNormals();
}
results.RecalculateBounds();
return results;
}
/// <summary>
/// Converts ImstkMesh to Unity Mesh
/// </summary>
public static Mesh ToMesh(this ImstkMesh geom)
{
if (geom.IsVolume)
return null;
Mesh results = new Mesh();
results.name = geom.name;
results.SetVertices(geom.vertices);
results.SetIndices(geom.indices, geomTypeToMeshTopology[geom.geomType], 0);
if (geom.texCoords.Length > 0)
{
results.SetUVs(0, geom.texCoords);
}
results.RecalculateBounds();
if (results.GetTopology(0) == MeshTopology.Triangles ||
results.GetTopology(0) == MeshTopology.Quads)
{
results.RecalculateNormals();
}
return results;
}
/// <summary>
/// Converts Unity Mesh to ImstkUnity Geometry
/// </summary>
public static ImstkMesh ToImstkMesh(this Mesh mesh)
{
// A Unity mesh can be made up multiple submeshes we only support 1
ImstkMesh geom = ScriptableObject.CreateInstance<ImstkMesh>();
geom.name = mesh.name;
geom.SetVertices(mesh.vertices);
geom.SetIndices(mesh.GetIndices(0));
geom.texCoords = new Vector2[mesh.uv.Length];
mesh.uv.CopyTo(geom.texCoords, 0);
geom.geomType = meshTopologyToGeomType[mesh.GetTopology(0)];
return geom;
}
/// <summary>
/// Converts Unity Mesh to ImstkUnity Geometry with transform applied
/// </summary>
public static ImstkMesh ToImstkMesh(this Mesh mesh, Matrix4x4 transform)
{
ImstkMesh geometry = ScriptableObject.CreateInstance<ImstkMesh>();
geometry.name = mesh.name;
geometry.geomType = meshTopologyToGeomType[mesh.GetTopology(0)];
geometry.SetVertices(mesh.vertices, transform);
int[] indices = mesh.GetIndices(0);
geometry.indices = new int[indices.Length];
mesh.triangles.CopyTo(geometry.indices, 0);
geometry.texCoords = new Vector2[mesh.uv.Length];
mesh.uv.CopyTo(geometry.texCoords, 0);
return geometry;
}
/// <summary>
/// Converts ImstkMesh to Imstk PointSet
/// </summary>
/// <param name="geometry"></param>
/// <returns></returns>
public static Imstk.PointSet ToPointSet(this ImstkMesh geometry)
{
Imstk.VecDataArray3d vertices = MathUtil.ToVecDataArray3d(geometry.vertices);
if (geometry.geomType == GeometryType.PointSet)
{
Imstk.PointSet pointSet = new Imstk.PointSet();
pointSet.initialize(vertices);
return pointSet;
}
else if (geometry.geomType == GeometryType.LineMesh)
{
Imstk.LineMesh mesh = new Imstk.LineMesh();
Imstk.VecDataArray2i indices = MathUtil.ToVecDataArray2i(geometry.indices);
mesh.initialize(vertices, indices);
return mesh;
}
else if (geometry.geomType == GeometryType.SurfaceMesh)
{
Imstk.SurfaceMesh mesh = new Imstk.SurfaceMesh();
Imstk.VecDataArray3i indices = MathUtil.ToVecDataArray3i(geometry.indices);
mesh.initialize(vertices, indices);
return mesh;
}
else if (geometry.geomType == GeometryType.TetrahedralMesh)
{
Imstk.TetrahedralMesh mesh = new Imstk.TetrahedralMesh();
Imstk.VecDataArray4i indices = MathUtil.ToVecDataArray4i(geometry.indices);
mesh.initialize(vertices, indices);
return mesh;
}
return null;
}
/// <summary>
/// Converts Geometry to Imstk Geometry
/// </summary>
public static Imstk.Geometry ToImstkGeometry(this Geometry geom)
{
if (geom == null)
{
Debug.LogError("ToImstkgeometry called with null");
}
if (geom.IsMesh)
{
return (geom as ImstkMesh).ToPointSet();
}
else if (geom.geomType == GeometryType.Capsule)
{
Capsule capsule = geom as Capsule;
Imstk.Capsule imstkCapsule = new Imstk.Capsule();
imstkCapsule.setPosition(capsule.center.ToImstkVec());
imstkCapsule.setRadius(capsule.radius);
imstkCapsule.setLength(capsule.length);
imstkCapsule.setOrientation(capsule.orientation.ToImstkQuat());
imstkCapsule.updatePostTransformData();
return imstkCapsule;
}
else if (geom.geomType == GeometryType.Cylinder)
{
Cylinder cylinder = geom as Cylinder;
Imstk.Cylinder imstkCylinder = new Imstk.Cylinder();
imstkCylinder.setPosition(cylinder.center.ToImstkVec());
imstkCylinder.setRadius(cylinder.radius);
imstkCylinder.setLength(cylinder.length);
imstkCylinder.setOrientation(cylinder.orientation.ToImstkQuat());
imstkCylinder.updatePostTransformData();
return imstkCylinder;
}
else if (geom.geomType == GeometryType.OrientedBox)
{
OrientedBox orientedBox = geom as OrientedBox;
Imstk.OrientedBox imstkOrientedBox = new Imstk.OrientedBox();
imstkOrientedBox.setPosition(orientedBox.center.ToImstkVec());
imstkOrientedBox.setOrientation(orientedBox.orientation.ToImstkQuat());
imstkOrientedBox.setExtents(orientedBox.extents.ToImstkVec());
imstkOrientedBox.updatePostTransformData();
return imstkOrientedBox;
}
else if (geom.geomType == GeometryType.Plane)
{
Plane plane = geom as Plane;
Imstk.Plane imstkPlane = new Imstk.Plane();
imstkPlane.setPosition(plane.center.ToImstkVec());
imstkPlane.setNormal(plane.normal.ToImstkVec());
imstkPlane.updatePostTransformData();
return imstkPlane;
}
else if (geom.geomType == GeometryType.Sphere)
{
Sphere sphere = geom as Sphere;
Imstk.Sphere imstkSphere = new Imstk.Sphere();
imstkSphere.setPosition(sphere.center.ToImstkVec());
imstkSphere.setRadius(sphere.radius);
imstkSphere.updatePostTransformData();
return imstkSphere;
}
return null;
}
/// <summary>
/// Lossy conversion, doesn't support mixed topologies
/// </summary>
public static Imstk.Geometry ToImstkGeometry(this Mesh mesh)
{
if (mesh.GetTopology(0) == MeshTopology.Points)
{
Imstk.PointSet geom = new Imstk.PointSet();
geom.initialize(MathUtil.ToVecDataArray3d(mesh.vertices));
return geom;
}
else if (mesh.GetTopology(0) == MeshTopology.Lines)
{
Imstk.LineMesh geom = new Imstk.LineMesh();
geom.initialize(
MathUtil.ToVecDataArray3d(mesh.vertices),
MathUtil.ToVecDataArray2i(mesh.GetIndices(0)));
return geom;
}
else if (mesh.GetTopology(0) == MeshTopology.Triangles)
{
Imstk.SurfaceMesh geom = new Imstk.SurfaceMesh();
geom.initialize(
MathUtil.ToVecDataArray3d(mesh.vertices),
MathUtil.ToVecDataArray3i(mesh.GetIndices(0)));
return geom;
}
return null;
}
/// <summary>
/// Converts Imstk PointSet to ImstkMesh
/// </summary>
public static ImstkMesh ToImstkMesh(this Imstk.PointSet pointSet)
{
ImstkMesh geom = ScriptableObject.CreateInstance<ImstkMesh>();
geom.vertices = MathUtil.ToVector3Array(pointSet.getVertexPositions());
string pointSetName = pointSet.getTypeName();
if (pointSetName == "PointSet")
{
geom.geomType = GeometryType.PointSet;
geom.indices = new int[geom.vertices.Length];
for (int i = 0; i < geom.indices.Length; i++)
{
geom.indices[i] = i;
}
}
else if (pointSetName == "LineMesh")
{
geom.geomType = GeometryType.LineMesh;
Imstk.LineMesh mesh = Imstk.Utils.CastTo<Imstk.LineMesh>(pointSet);
geom.indices = MathUtil.ToIntArray(mesh.getLinesIndices());
}
else if (pointSetName == "SurfaceMesh")
{
geom.geomType = GeometryType.SurfaceMesh;
Imstk.SurfaceMesh mesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(pointSet);
geom.indices = MathUtil.ToIntArray(mesh.getTriangleIndices());
}
else if (pointSetName == "TetrahedralMesh")
{
geom.geomType = GeometryType.TetrahedralMesh;
Imstk.TetrahedralMesh mesh = Imstk.Utils.CastTo<Imstk.TetrahedralMesh>(pointSet);
geom.indices = MathUtil.ToIntArray(mesh.getTetrahedraIndices());
}
return geom;
}
public static Geometry ToGeometry(this Mesh mesh)
{
return mesh.ToImstkMesh();
}
/// <summary>
/// Converts Imstk Geometry to Geometry
/// </summary>
public static Geometry ToGeometry(Imstk.Geometry geom)
{
string name = geom.getTypeName();
if (name == "PointSet" || name == "LineMesh" ||
name == "SurfaceMesh" || name == "TetrahedralMesh")
{
Imstk.PointSet pointSet = Imstk.Utils.CastTo<Imstk.PointSet>(geom);
return pointSet.ToImstkMesh();
}
else if (name == "Capsule")
{
Imstk.Capsule imstkCapsule = Imstk.Utils.CastTo<Imstk.Capsule>(geom);
Imstk.Vec3d center = imstkCapsule.getCenter();
Imstk.Quatd quat = imstkCapsule.getOrientation();
Capsule capsule = ScriptableObject.CreateInstance<Capsule>();
capsule.center = center.ToUnityVec();
capsule.radius = (float)imstkCapsule.getRadius();
capsule.length = (float)imstkCapsule.getLength();
capsule.orientation = quat.ToUnityQuat();
return capsule;
}
else if (name == "Cylinder")
{
Imstk.Cylinder imstkCapsule = Imstk.Utils.CastTo<Imstk.Cylinder>(geom);
Imstk.Vec3d center = imstkCapsule.getCenter();
Imstk.Quatd quat = imstkCapsule.getOrientation();
Cylinder cylinder = ScriptableObject.CreateInstance<Cylinder>();
cylinder.center = center.ToUnityVec();
cylinder.radius = (float)imstkCapsule.getRadius();
cylinder.length = (float)imstkCapsule.getLength();
cylinder.orientation = quat.ToUnityQuat();
return cylinder;
}
else if (name == "OrientedBox")
{
Imstk.OrientedBox imstkOrientedBox = Imstk.Utils.CastTo<Imstk.OrientedBox>(geom);
Imstk.Vec3d center = imstkOrientedBox.getCenter();
Imstk.Vec3d extents = imstkOrientedBox.getExtents();
Imstk.Quatd orientation = imstkOrientedBox.getOrientation();
OrientedBox orientedBox = ScriptableObject.CreateInstance<OrientedBox>();
orientedBox.center = center.ToUnityVec();
orientedBox.extents = extents.ToUnityVec();
orientedBox.orientation = orientation.ToUnityQuat();
return orientedBox;
}
else if (name == "Plane")
{
Imstk.Plane imstkPlane = Imstk.Utils.CastTo<Imstk.Plane>(geom);
Imstk.Vec3d center = imstkPlane.getCenter();
Imstk.Vec3d normal = imstkPlane.getNormal();
Plane plane = ScriptableObject.CreateInstance<Plane>();
plane.center = center.ToUnityVec();
plane.normal = normal.ToUnityVec();
return plane;
}
else if (name == "Sphere")
{
Imstk.Sphere imstkSphere = Imstk.Utils.CastTo<Imstk.Sphere>(geom);
Imstk.Vec3d center = imstkSphere.getCenter();
Sphere sphere = ScriptableObject.CreateInstance<Sphere>();
sphere.center = center.ToUnityVec();
sphere.radius = (float)imstkSphere.getRadius();
return sphere;
}
return null;
}
/// <summary>Calculate list of vertices inside of a given mesh contained by unity meshfilter.
/// The points sampled need to be in world space as the enclosing mesh will also be transfered
/// into world space.</summary>
/// <param name="enclosingMesh">Unity.MeshFilter for enclosing mesh</param>
/// <param name="sampleMesh">Imstk.PointSet for sample mesh</param>
/// <returns>Return list of indices of of the sample mesh that are contained within the enclosing mesh</returns>
public static List<uint> PointsInside(MeshFilter enclosingMesh, PointSet sampleMesh)
{
Debug.Assert(enclosingMesh != null && sampleMesh != null);
ImstkMesh imstkEnclosingMesh = enclosingMesh.sharedMesh.ToImstkMesh(enclosingMesh.transform.localToWorldMatrix);
return PointsInside(imstkEnclosingMesh.ToImstkGeometry() as Imstk.SurfaceMesh, sampleMesh);
}
public static List<uint> PointsInside(SurfaceMesh enclosingMesh, PointSet sampleMesh)
{
var result = new List<uint>();
// Compute mask of enclosed points
Imstk.SelectEnclosedPoints selectEnclosed = new Imstk.SelectEnclosedPoints();
selectEnclosed.setInputMesh(enclosingMesh);
selectEnclosed.setInputPoints(sampleMesh);
selectEnclosed.setUsePruning(false);
selectEnclosed.update();
Imstk.DataArrayuc isInside = selectEnclosed.getIsInsideMask();
byte[] isInsideBytes = new byte[isInside.size()];
isInside.getValues(isInsideBytes);
for (int i = 0; i < isInsideBytes.Length; i++)
{
if (isInsideBytes[i] == 1)
result.Add((uint)i);
}
return result;
}
};
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20a65b11fe8bd5a499fd46809b237b1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+60
View File
@@ -0,0 +1,60 @@
/*=========================================================================
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
{
public enum GeometryType
{
Capsule,
Cylinder,
HexahedralMesh,
ImageData,
LineMesh,
OrientedBox,
Plane,
PointSet,
Sphere,
SurfaceMesh,
TetrahedralMesh,
UnityMesh
};
/// <summary>
/// We need to reimplement storage for all geometry classes in iMSTK as Unity
/// import and transfer from editor to runtime works via serialization
/// afaik it would be quite significant undertaking, and very possibly impossible
/// to serialize non C# classes, not to mention sensitive to changes. Thus the
/// base iMSTK geometry cannot be used for geometry storage
/// </summary>
public class Geometry : ScriptableObject
{
public GeometryType geomType = GeometryType.Plane;
public bool IsMesh { get { return
(geomType == GeometryType.PointSet ||
geomType == GeometryType.LineMesh ||
geomType == GeometryType.SurfaceMesh ||
geomType == GeometryType.TetrahedralMesh ||
geomType == GeometryType.HexahedralMesh); } }
public bool IsVolume { get { return (geomType == GeometryType.TetrahedralMesh || geomType == GeometryType.HexahedralMesh); } }
};
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ea518f5190165c408289bf14f91f808
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,132 @@
/*=========================================================================
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
{
/// <summary>
/// Similar to a MeshFilter in Unity.It provides an input and output geometry.
/// It may take in any iMSTK geometry, as well as a Unity Mesh
/// (one can also drag/drop a MeshFilter to it). These are instances of geometries
/// used in all of iMSTK unity scripts.Instances of this class fit into
/// the ``Visual Geometry``, ``Physics Geometry``, and ``Collision Geometry``
/// slots on the model components.
/// </summary>
[AddComponentMenu("iMSTK/GeometryFilter")]
public class GeometryFilter : ImstkBehaviour
{
// GeometryFilter supports either type
public Geometry inputImstkGeom = null;
public Mesh inputUnityGeom = null;
// It can output this type
// Note: Imstk.Geometry cannot transition over editor and runtime
public Imstk.Geometry outputImstkGeom = null;
// Used to denote which should be seated, not what is currently
public GeometryType type = GeometryType.UnityMesh;
// Used to toggle drawing of it in the editor, ideally this would not
// exist in runtime code, but unity's architecture doesn't allow
public bool showHandles = true;
// Use to write the mesh as seen by iMSTK on creation,
// this can help with debugging mesh issues
public bool writeMesh = false;
private bool inGlobalSpace = false;
/// <summary>
/// Moves the geometry to a global transform
/// </summary>
public void MoveToGlobalSpace()
{
// Models in Unity are provided in Mesh pre transformed.
// We move the entire model to world space for simulation. Meaning the transform
// is applied before giving the simulation geometry. Here we store that initial
// transform and reset the local transform
if (inGlobalSpace) return;
var localToWorld = gameObject.transform.localToWorldMatrix.ToMat4d();
var filters = gameObject.GetComponents<GeometryFilter>();
foreach (var filter in filters)
{
if (filter.inGlobalSpace) continue;
// World coordinates
var geometry = filter.GetOutputGeometry();
geometry.transform(localToWorld, Imstk.Geometry.TransformType.ApplyToData);
geometry.setTransform(Imstk.Mat4d.Identity());
filter.inGlobalSpace = true;
}
gameObject.transform.localPosition = Vector3.zero;
gameObject.transform.localScale = Vector3.one;
gameObject.transform.localRotation = Quaternion.identity;
// Re-parent to itself for the period of the simulation run, this avoids having
// to recalculate the local transforms when the object is in a hierarchy
gameObject.transform.SetParent(null, false);
}
public void SetGeometry(Geometry geom)
{
inputImstkGeom = geom;
type = geom.geomType;
}
public void SetGeometry(Mesh geom)
{
inputUnityGeom = geom;
type = GeometryType.UnityMesh;
}
/// <summary>
/// This will convert the input to output, allocating in native code
/// </summary>
public Imstk.Geometry GetOutputGeometry()
{
if (outputImstkGeom == null)
{
if (type == GeometryType.UnityMesh)
outputImstkGeom = inputUnityGeom.ToImstkGeometry();
else
outputImstkGeom = inputImstkGeom.ToImstkGeometry();
}
return outputImstkGeom;
}
/// <summary>
/// Write mesh in this filter to file, useful for debugging
/// </summary>
public void WriteMesh(string filename)
{
var mesh = Imstk.Utils.CastTo<Imstk.SurfaceMesh>(GetOutputGeometry());
if (mesh != null)
{
//mesh.flipNormals();
mesh.correctWindingOrder();
mesh.computeVertexNormals();
mesh.computeTrianglesNormals();
Imstk.MeshIO.write(mesh, filename);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb7fd5ef0ac0aca4aaccabd7990fcfbf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,81 @@
/*=========================================================================
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 System.Collections.Generic;
using UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// Roles all meshes into one class. ie: PointSet, LineMesh, SurfaceMesh,
/// TetMesh, HexMesh
/// </summary>
public class ImstkMesh : Geometry
{
/// <summary>
/// Map of some geometry types to number of cell points
/// </summary>
public static Dictionary<GeometryType, int> typeToNumPts = new Dictionary<GeometryType, int>()
{
{ GeometryType.PointSet, 1 },
{ GeometryType.LineMesh, 2 },
{ GeometryType.SurfaceMesh, 3 },
{ GeometryType.TetrahedralMesh, 4 },
{ GeometryType.HexahedralMesh, 8 }
};
public int[] indices = new int[0];
public Vector3[] vertices = new Vector3[0];
public Vector2[] texCoords = new Vector2[0];
//public void CopyTo(ImstkMesh geometry)
//{
// geometry.type = type;
// geometry.vertices = new Vector3[vertices.Length];
// vertices.CopyTo(geometry.vertices, 0);
// geometry.texCoords = new Vector2[texCoords.Length];
// texCoords.CopyTo(geometry.texCoords, 0);
// geometry.indices = new int[indices.Length];
// indices.CopyTo(geometry.indices, 0);
//}
public void SetVertices(Vector3[] vertices, Matrix4x4 transform)
{
this.vertices = new Vector3[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
this.vertices[i] = transform.MultiplyPoint(vertices[i]);
}
}
public void SetVertices(Vector3[] vertices) { this.vertices = vertices; }
public void SetTexCoords(Vector2[] texCoords) { this.texCoords = texCoords; }
public void SetIndices(int[] indices) { this.indices = indices; }
public void Transform(Matrix4x4 transform)
{
for (int i = 0; i < vertices.Length; i++)
{
vertices[i] = transform.MultiplyPoint(vertices[i]);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9ff06caabe5106e489465ca1ca18add7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
/*=========================================================================
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
{
public class OrientedBox : Geometry
{
public Vector3 center = Vector3.zero;
public Vector3 extents = new Vector3(0.5f, 0.5f, 0.5f);
public Quaternion orientation = Quaternion.identity;
public OrientedBox()
{
geomType = GeometryType.OrientedBox;
}
public Vector3 GetTransformedCenter(Transform transform)
{
return transform.TransformPoint(center);
}
public Vector3 GetTransformedExtent(Transform transform)
{
return Vector3.Scale(extents, transform.localScale);
}
public Quaternion GetTransformedOrientation(Transform transform)
{
return orientation * transform.rotation;
}
public Mesh GetMesh()
{
Imstk.OrientedBox geom = this.ToImstkGeometry() as Imstk.OrientedBox;
Imstk.SurfaceMesh surfMesh = Imstk.Utils.toSurfaceMesh(geom);
return surfMesh.ToMesh();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd37a9e519de4c94e97f0ab4af6c0720
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+46
View File
@@ -0,0 +1,46 @@
/*=========================================================================
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
{
public class Plane : Geometry
{
public Plane()
{
geomType = GeometryType.Plane;
}
public Vector3 GetTransformedCenter(Transform transform)
{
return transform.TransformPoint(center);
}
public Vector3 GetTransformedNormal(Transform transform)
{
return transform.TransformDirection(normal).normalized;
}
public Vector3 center = Vector3.zero;
public Vector3 normal = Vector3.up;
public float visualWidth = 1.0f; ///> Purely used for visualization
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 11ff5901a1e43f54d931c16a488e306e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+54
View File
@@ -0,0 +1,54 @@
/*=========================================================================
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
{
public class Sphere : Geometry
{
public Vector3 center = Vector3.zero;
public float radius = 0.5f;
public Sphere()
{
geomType = GeometryType.Sphere;
}
public Vector3 GetTransformedCenter(Transform transform)
{
return transform.TransformPoint(center);
}
public float GetTransformedRadius(Transform transform)
{
Vector3 localScale = transform.localScale;
float max = Mathf.Max(Mathf.Max(localScale.x, localScale.y), localScale.z);
return radius * max;
}
public Mesh GetMesh()
{
Imstk.Sphere geom = this.ToImstkGeometry() as Imstk.Sphere;
Imstk.SurfaceMesh surfMesh = Imstk.Utils.toUVSphereSurfaceMesh(geom, 7, 7);
return surfMesh.ToMesh();
}
}
}

Some files were not shown because too many files have changed in this diff Show More