MegaCollisionDeform.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. #if true
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. [System.Serializable]
  5. public class MegaColliderMesh
  6. {
  7. public int[] tris;
  8. public Vector3[] verts;
  9. public Vector3[] normals;
  10. public Mesh mesh;
  11. public GameObject obj;
  12. }
  13. public enum MegaDeformType
  14. {
  15. Old,
  16. RayCast,
  17. NearPoint,
  18. }
  19. #if true
  20. [AddComponentMenu("Modifiers/Collision Deform")]
  21. public class MegaCollisionDeform : MegaModifier
  22. {
  23. public GameObject obj;
  24. public float decay = 1.0f;
  25. public bool usedecay = false;
  26. public Vector3 normal = Vector3.up;
  27. List<int> affected = new List<int>();
  28. List<float> distances = new List<float>();
  29. Matrix4x4 mat = new Matrix4x4();
  30. Vector3[] offsets;
  31. Vector3[] normals;
  32. public override string ModName() { return "Deform"; }
  33. public override string GetHelpURL() { return "Deform.htm"; }
  34. public MegaColliderMesh colmesh;
  35. void DeformMeshMine()
  36. {
  37. if ( col == null )
  38. return;
  39. for ( int i = 0; i < verts.Length; i++ )
  40. {
  41. Vector3 p = verts[i] + offsets[i];
  42. Vector3 origin = transform.TransformPoint(p);
  43. if ( col.bounds.Contains(origin) )
  44. {
  45. RaycastHit hit;
  46. // Do ray from a distance away to the point, if hit then inside mesh
  47. Ray ray = new Ray(origin, normals[i]);
  48. if ( col.Raycast(ray, out hit, 10.0f) )
  49. {
  50. if ( hit.distance < 10.0f ) //&& hit.distance > 0.0f )
  51. {
  52. penetration[i] = hit.distance; //pen;
  53. offsets[i] = -(normals[i] * (hit.distance + 0.01f)); //pen); //(10.0f - hit.distance));
  54. }
  55. }
  56. }
  57. }
  58. if ( !usedecay )
  59. {
  60. for ( int i = 0; i < verts.Length; i++ )
  61. {
  62. sverts[i].x = verts[i].x + offsets[i].x;
  63. sverts[i].y = verts[i].y + offsets[i].y;
  64. sverts[i].z = verts[i].z + offsets[i].z;
  65. }
  66. }
  67. else
  68. {
  69. for ( int i = 0; i < verts.Length; i++ )
  70. {
  71. offsets[i].x *= decay;
  72. offsets[i].y *= decay;
  73. offsets[i].z *= decay;
  74. sverts[i].x = verts[i].x + offsets[i].x;
  75. sverts[i].y = verts[i].y + offsets[i].y;
  76. sverts[i].z = verts[i].z + offsets[i].z;
  77. }
  78. }
  79. }
  80. public MegaDeformType method = MegaDeformType.NearPoint;
  81. public float distance = 0.0f;
  82. public float bulgeExtendValue = 0.0f;
  83. public float bulgeValue = 0.0f;
  84. public bool bulge = false;
  85. public AnimationCurve bulgeCrv = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));
  86. // To do falloff we need connected verts to each vert then just need to do recursive check until none effected
  87. void DeformMesh()
  88. {
  89. float dst = distance * 0.001f;
  90. int index = -1;
  91. Vector3 bary = Vector3.zero;
  92. bool collision = false;
  93. for ( int i = 0; i < verts.Length; i++ )
  94. {
  95. Vector3 p = verts[i]; // + offsets[i];
  96. Vector3 origin = transform.TransformPoint(p + (normals[i] * dst));
  97. if ( col.bounds.Contains(origin) )
  98. {
  99. // Point in collider space
  100. Vector3 lp = col.transform.worldToLocalMatrix.MultiplyPoint(origin);
  101. Vector3 np = MegaNearestPointTest.NearestPointOnMesh1(lp, colmesh.verts, colmesh.tris, ref index, ref bary);
  102. Vector3 dir = lp - np;
  103. Vector3 norm = FaceNormal(colmesh.verts, colmesh.tris, index);
  104. if ( Vector3.Dot(norm, dir) < 0.0f )
  105. {
  106. np = col.transform.localToWorldMatrix.MultiplyPoint(np);
  107. sverts[i] = transform.worldToLocalMatrix.MultiplyPoint(np);
  108. sverts[i] = sverts[i] - (normals[i] * dst);
  109. collision = true;
  110. }
  111. else
  112. sverts[i] = verts[i];
  113. //np = col.transform.localToWorldMatrix.MultiplyPoint(np);
  114. //sverts[i] = transform.worldToLocalMatrix.MultiplyPoint(np);
  115. }
  116. else
  117. {
  118. sverts[i] = verts[i];
  119. }
  120. }
  121. if ( collision && bulge )
  122. {
  123. for ( int i = 0; i < verts.Length; i++ )
  124. {
  125. Vector3 p = verts[i]; // + offsets[i];
  126. Vector3 origin = transform.TransformPoint(p + (normals[i] * dst));
  127. Vector3 lp = col.transform.worldToLocalMatrix.MultiplyPoint(origin);
  128. Vector3 np = MegaNearestPointTest.NearestPointOnMesh1(lp, colmesh.verts, colmesh.tris, ref index, ref bary);
  129. float bulgeDist = Vector3.Distance(lp, np);
  130. float relativedistance = bulgeDist / (bulgeExtendValue + 0.00001f);
  131. // get the bulge curve
  132. float bulgeAmount = bulgeCrv.Evaluate(relativedistance);
  133. float delta = bulgeAmount * bulgeValue;
  134. // set the point position for indirect collision deformation
  135. sverts[i].x = sverts[i].x + normals[i].x * delta; //bulgeExtendValue * (bulgeValue / 5.0f) * envelopeValue*bulgeAmount * maxdeformation;
  136. sverts[i].y = sverts[i].y + normals[i].y * delta; //bulgeExtendValue * (bulgeValue / 5.0f) * envelopeValue*bulgeAmount * maxdeformation;
  137. sverts[i].z = sverts[i].z + normals[i].z * delta; //bulgeExtendValue * (bulgeValue / 5.0f) * envelopeValue*bulgeAmount * maxdeformation;
  138. //sverts[i] = verts[i];
  139. }
  140. }
  141. }
  142. float[] vertdist;
  143. Vector3[] vertoffsets;
  144. Vector3[] nearest;
  145. Vector3[] vels;
  146. [ContextMenu("Reset Offsets")]
  147. public void ResetOffsets()
  148. {
  149. vertdist = null;
  150. }
  151. void DeformMeshNew()
  152. {
  153. if ( vertdist == null || vertdist.Length != verts.Length )
  154. {
  155. vertdist = new float[verts.Length];
  156. vertoffsets = new Vector3[verts.Length];
  157. nearest = new Vector3[verts.Length];
  158. vels = new Vector3[verts.Length];
  159. }
  160. float dst = distance * 0.001f;
  161. int index = -1;
  162. Vector3 bary = Vector3.zero;
  163. //bool collision = false;
  164. float totalpen = 0.0f;
  165. int count = 0;
  166. for ( int i = 0; i < verts.Length; i++ )
  167. {
  168. Vector3 p = verts[i]; // + offsets[i];
  169. Vector3 origin = transform.TransformPoint(p + (normals[i] * dst));
  170. if ( col.bounds.Contains(origin) )
  171. {
  172. Vector3 lp = col.transform.worldToLocalMatrix.MultiplyPoint(origin);
  173. Vector3 np = MegaNearestPointTest.NearestPointOnMesh1(lp, colmesh.verts, colmesh.tris, ref index, ref bary);
  174. Vector3 dir = lp - np;
  175. float dist = Vector3.Distance(lp, np);
  176. Vector3 norm = FaceNormal(colmesh.verts, colmesh.tris, index);
  177. if ( Vector3.Dot(norm, dir) < 0.0f )
  178. {
  179. totalpen += dist;
  180. dist = -dist;
  181. //collision = true;
  182. }
  183. np = col.transform.localToWorldMatrix.MultiplyPoint(np);
  184. nearest[i] = transform.worldToLocalMatrix.MultiplyPoint(np);
  185. //if ( dist < vertdist[i] )
  186. {
  187. vertdist[i] = dist;
  188. //vertoffsets[i] = nearest[i] - verts[i];
  189. }
  190. }
  191. else
  192. {
  193. Vector3 lp = col.transform.worldToLocalMatrix.MultiplyPoint(origin);
  194. // Distance is calculated in here
  195. Vector3 np = MegaNearestPointTest.NearestPointOnMesh1(lp, colmesh.verts, colmesh.tris, ref index, ref bary);
  196. float dist = Vector3.Distance(lp, np);
  197. //if ( dist < vertdist[i] )
  198. {
  199. vertdist[i] = dist;
  200. }
  201. //vertdist[i] = Vector3.Distance(lp, np); // out of range
  202. np = col.transform.localToWorldMatrix.MultiplyPoint(np);
  203. nearest[i] = transform.worldToLocalMatrix.MultiplyPoint(np);
  204. count++;
  205. }
  206. }
  207. if ( totalpen == 0.0f )
  208. {
  209. for ( int i = 0; i < verts.Length; i++ )
  210. {
  211. //sverts[i] = verts[i];
  212. sverts[i] = verts[i] + vertoffsets[i];
  213. vertoffsets[i] *= retspd;
  214. }
  215. }
  216. else
  217. {
  218. for ( int i = 0; i < verts.Length; i++ )
  219. {
  220. if ( vertdist[i] < 0.0f )
  221. vertoffsets[i] = nearest[i] - verts[i];
  222. else
  223. {
  224. Vector3 newpos = normals[i] * ((totalpen / (float)count) * bulgeValue);
  225. vertoffsets[i] = Vector3.SmoothDamp(vertoffsets[i], newpos, ref vels[i], btime); //normals[i] * ((totalpen / (float)count) * bulgeValue);
  226. //vertoffsets[i] = Vector3.zero;
  227. }
  228. sverts[i] = verts[i] + vertoffsets[i];
  229. vertoffsets[i] *= retspd;
  230. }
  231. }
  232. }
  233. public float btime = 1.0f;
  234. public float retspd = 1.0f;
  235. // So per point see if inside colliding mesh
  236. Vector3 FaceNormal(Vector3[] verts, int[] tris, int f)
  237. {
  238. Vector3 v30 = verts[tris[f]];
  239. Vector3 v31 = verts[tris[f + 1]];
  240. Vector3 v32 = verts[tris[f + 2]];
  241. float vax = v31.x - v30.x;
  242. float vay = v31.y - v30.y;
  243. float vaz = v31.z - v30.z;
  244. float vbx = v32.x - v31.x;
  245. float vby = v32.y - v31.y;
  246. float vbz = v32.z - v31.z;
  247. v30.x = vay * vbz - vaz * vby;
  248. v30.y = vaz * vbx - vax * vbz;
  249. v30.z = vax * vby - vay * vbx;
  250. // Uncomment this if you dont want normals weighted by poly size
  251. //float l = v30.x * v30.x + v30.y * v30.y + v30.z * v30.z;
  252. //l = 1.0f / Mathf.Sqrt(l);
  253. //v30.x *= l;
  254. //v30.y *= l;
  255. //v30.z *= l;
  256. return v30;
  257. }
  258. public override void Modify(MegaModifiers mc)
  259. {
  260. switch ( method )
  261. {
  262. case MegaDeformType.Old:
  263. DeformMesh();
  264. break;
  265. case MegaDeformType.RayCast:
  266. DeformMeshMine();
  267. break;
  268. case MegaDeformType.NearPoint:
  269. DeformMeshNew();
  270. break;
  271. default:
  272. break;
  273. }
  274. }
  275. // How to do this, (a) ray from each p along its normal and check for hit mesh, only need to do if point in
  276. // collider.bounds, need in local space
  277. // maybe best to use a sphere for first test
  278. public override bool ModLateUpdate(MegaModContext mc)
  279. {
  280. return Prepare(mc);
  281. }
  282. Collider col;
  283. float[] penetration;
  284. // Need to support multiple objects
  285. public GameObject hitObject;
  286. public override bool Prepare(MegaModContext mc)
  287. {
  288. if ( colmesh == null )
  289. colmesh = new MegaColliderMesh();
  290. if ( colmesh.obj != hitObject && hitObject != null )
  291. {
  292. colmesh = new MegaColliderMesh();
  293. // This is colldier mesh not this mesh
  294. colmesh.mesh = MegaUtils.GetMesh(hitObject);
  295. colmesh.verts = colmesh.mesh.vertices;
  296. colmesh.tris = colmesh.mesh.triangles;
  297. colmesh.normals = colmesh.mesh.normals;
  298. colmesh.obj = hitObject;
  299. }
  300. if ( hitObject )
  301. {
  302. //localPos = transform.worldToLocalMatrix.MultiplyPoint(hitObject.transform.position);
  303. col = hitObject.GetComponent<Collider>();
  304. }
  305. if ( hitObject == null )
  306. return false;
  307. affected.Clear();
  308. distances.Clear();
  309. if ( offsets == null || offsets.Length != mc.mod.verts.Length )
  310. offsets = new Vector3[mc.mod.verts.Length];
  311. if ( normals == null || normals.Length != verts.Length )
  312. normals = mc.mod.mesh.normals; // get current normals
  313. if ( penetration == null || penetration.Length != mc.mod.verts.Length )
  314. penetration = new float[mc.mod.verts.Length];
  315. mat = Matrix4x4.identity;
  316. SetAxis(mat);
  317. return true;
  318. }
  319. public override void PrepareMT(MegaModifiers mc, int cores)
  320. {
  321. }
  322. public override void DoWork(MegaModifiers mc, int index, int start, int end, int cores)
  323. {
  324. if ( index == 0 )
  325. Modify(mc);
  326. }
  327. // Collision
  328. const float EPSILON = 0.000001f;
  329. int intersect_triangle(Vector3 orig, Vector3 dir, Vector3 vert0, Vector3 vert1, Vector3 vert2, out float t, out float u, out float v)
  330. {
  331. Vector3 edge1,edge2,tvec,pvec,qvec;
  332. float det,inv_det;
  333. // find vectors for two edges sharing vert0
  334. edge1 = vert1 - vert0;
  335. edge2 = vert2 - vert0;
  336. /* begin calculating determinant - also used to calculate U parameter */
  337. pvec = Vector3.Cross(dir, edge2);
  338. /* if determinant is near zero, ray lies in plane of triangle */
  339. det = Vector3.Dot(edge1, pvec);
  340. t = u = v = 0.0f; // or use ref
  341. #if TEST_CULL // define TEST_CULL if culling is desired
  342. if ( det < EPSILON )
  343. return 0;
  344. // calculate distance from vert0 to ray origin
  345. //SUB(tvec, orig, vert0);
  346. tvec = orig - vert0;
  347. /* calculate U parameter and test bounds */
  348. //*u = DOT(tvec, pvec);
  349. u = Vector3.Dot(tvec, pvec);
  350. if ( u < 0.0f || u > det )
  351. return 0;
  352. /* prepare to test V parameter */
  353. //CROSS(qvec, tvec, edge1);
  354. qvec = Vector3.Cross(tvec, edge1);
  355. /* calculate V parameter and test bounds */
  356. //*v = DOT(dir, qvec);
  357. v = Vector3.Dot(dir, qvec);
  358. if ( v < 0.0f || u + v > det )
  359. return 0;
  360. /* calculate t, scale parameters, ray intersects triangle */
  361. //*t = DOT(edge2, qvec);
  362. t = Vector3.Dot(edge2, qvec);
  363. inv_det = 1.0f / det;
  364. t *= inv_det;
  365. u *= inv_det;
  366. v *= inv_det;
  367. #else // the non-culling branch
  368. if ( det > -EPSILON && det < EPSILON )
  369. return 0;
  370. inv_det = 1.0f / det;
  371. /* calculate distance from vert0 to ray origin */
  372. tvec = orig - vert0;
  373. /* calculate U parameter and test bounds */
  374. u = Vector3.Dot(tvec, pvec) * inv_det;
  375. if ( u < 0.0f || u > 1.0f )
  376. return 0;
  377. /* prepare to test V parameter */
  378. qvec = Vector3.Cross(tvec, edge1);
  379. /* calculate V parameter and test bounds */
  380. v = Vector3.Dot(dir, qvec) * inv_det;
  381. if ( v < 0.0f || u + v > 1.0f )
  382. return 0;
  383. /* calculate t, ray intersects triangle */
  384. t = Vector3.Dot(edge2, qvec) * inv_det;
  385. #endif
  386. return 1;
  387. }
  388. }
  389. #endif
  390. #endif