GarbageMatte.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. //======= Copyright (c) Stereolabs Corporation, All rights reserved. ===============
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Rendering;
  5. #if UNITY_EDITOR
  6. using UnityEditor;
  7. #endif
  8. /// <summary>
  9. /// Creates a garbage matte mask from its position and apply it on the pipeline.
  10. /// It's created by GreenScreenManager as a 3D object, that you can create from the Inspector by placing the bounds of the mesh.
  11. /// The garbage matte represents a region of the screen where no real pixels will be rendered, regardless of depth.
  12. /// This can be used to extend the bounds of a greenscreen when the physical screen isn't large enough to fill the background.
  13. /// </summary>
  14. [RequireComponent(typeof(GreenScreenManager))]
  15. [RequireComponent(typeof(Camera))]
  16. public class GarbageMatte
  17. {
  18. /// <summary>
  19. /// Reference to the ZEDCamera.
  20. /// </summary>
  21. private sl.ZEDCamera zed;
  22. /// <summary>
  23. /// Position in the render queue used by Unity's renderer to render a mesh transparent. This gets appled to the shader.
  24. /// </summary>
  25. private const int QUEUE_TRANSPARENT_VALUE = 3000;
  26. /// <summary>
  27. /// List of 3D points used to make the matte mesh, eg the "corners".
  28. /// </summary>
  29. private List<Vector3> points = new List<Vector3>();
  30. /// <summary>
  31. /// The current camera looking at the scene, used to transform ScreenPosition to worldPosition when placing the boundary points.
  32. /// </summary>
  33. private Camera cam;
  34. /// <summary>
  35. /// List of the gameObjects used by the mesh.
  36. /// </summary>
  37. private List<GameObject> go = null;
  38. /// <summary>
  39. /// List of the meshes.
  40. /// </summary>
  41. private List<MeshFilter> meshFilters;
  42. /// <summary>
  43. /// Triangles of the current mesh.
  44. /// </summary>
  45. private List<int> triangles = new List<int>();
  46. /// <summary>
  47. /// The sphere objects the user places via GreenScreenManager to define the bounds of the matte object.
  48. /// </summary>
  49. private List<GameObject> borderspheres = new List<GameObject>();
  50. /// <summary>
  51. /// The ZED greenscreen material. Usually Mat_ZED_GreenScreen.
  52. /// </summary>
  53. private Material shader_greenScreen;
  54. /// <summary>
  55. /// The material used on the spheres that the user places via GreenScreenManager to define the bounds of the matte object.
  56. /// Usually Mat_ZED_Outlined.
  57. /// </summary>
  58. private Material outlineMaterial;
  59. /// <summary>
  60. /// Whether or not the maatte is currently being edited.
  61. /// </summary>
  62. private bool isClosed = false;
  63. /// <summary>
  64. /// The index of meshFilters that refers to the plane mesh we're currently editing, if applicable.
  65. /// </summary>
  66. private int currentPlaneIndex;
  67. /// <summary>
  68. /// The Unity layer where spheres exist, for visibility reasons.
  69. /// </summary>
  70. private int sphereLayer = 21;
  71. /// <summary>
  72. /// The Unity CommandBuffer that gets applied to the camera, which results in the matte getting rendered.
  73. /// </summary>
  74. private CommandBuffer commandBuffer;
  75. [SerializeField]
  76. [HideInInspector]
  77. public string garbageMattePath = "garbageMatte.cfg";
  78. [SerializeField]
  79. [HideInInspector]
  80. public bool editMode = true;
  81. [SerializeField]
  82. [HideInInspector]
  83. public bool loadAtStart = false;
  84. private Transform target;
  85. private bool isInit = false;
  86. public bool IsInit
  87. {
  88. get { return isInit; }
  89. }
  90. /// <summary>
  91. /// Constructor that sets up the garbage matte for the desired camera in the desired place.
  92. /// </summary>
  93. /// <param name="cam">Camera in which to apply the matte effect</param>
  94. /// <param name="greenScreenMaterial">Material reference, usually Mat_ZED_Greenscreen</param>
  95. /// <param name="target">Center location of the matte effect</param>
  96. /// <param name="matte">Optional reference to another garbage matte, used to copy its current edit mode. </param>
  97. public GarbageMatte(ZEDManager camManager, Material greenScreenMaterial, Transform target, GarbageMatte matte)
  98. {
  99. this.target = target;
  100. currentPlaneIndex = 0;
  101. zed = camManager.zedCamera;
  102. this.cam = camManager.GetComponentInChildren<Camera>();
  103. points.Clear();
  104. outlineMaterial = Resources.Load("Materials/Mat_ZED_Outlined") as Material;
  105. go = new List<GameObject>();
  106. meshFilters = new List<MeshFilter>();
  107. shader_greenScreen = greenScreenMaterial;
  108. ResetPoints(false);
  109. if (matte != null)
  110. {
  111. editMode = matte.editMode;
  112. }
  113. if (commandBuffer == null)
  114. {
  115. //Create a command buffer to clear the depth and stencil
  116. commandBuffer = new CommandBuffer();
  117. commandBuffer.name = "GarbageMatte";
  118. commandBuffer.SetRenderTarget(BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.Depth);
  119. //Remove the previous command buffer to set the garbage matte first
  120. CommandBuffer[] cmd = cam.GetCommandBuffers(CameraEvent.BeforeDepthTexture);
  121. cam.RemoveCommandBuffers(CameraEvent.BeforeDepthTexture);
  122. if(cmd.Length > 0)
  123. {
  124. cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, commandBuffer);
  125. for(int i = 0; i < cmd.Length; ++i)
  126. {
  127. cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, cmd[i]);
  128. }
  129. }
  130. }
  131. if (loadAtStart && Load())
  132. {
  133. Debug.Log("Config garbage matte found, and loaded ( " + garbageMattePath + " )");
  134. ApplyGarbageMatte();
  135. editMode = false;
  136. }
  137. isInit = true;
  138. }
  139. /// <summary>
  140. /// Constructor to create a dummy garbage matte that does nothing. Should be used only as a cache in memory
  141. /// </summary>
  142. public GarbageMatte()
  143. {
  144. isInit = false;
  145. }
  146. private List<int> indexSelected = new List<int>();
  147. private List<GameObject> currentGOSelected = new List<GameObject>();
  148. private List<MeshFilter> meshFilterSelected = new List<MeshFilter>();
  149. private List<int> planeSelectedIndex = new List<int>();
  150. private int numberSpheresSelected = -1;
  151. /// <summary>
  152. /// Update the garbage matte and manage the movement of the spheres.
  153. /// </summary>
  154. public void Update()
  155. {
  156. if (editMode)
  157. {
  158. // if at least a sphere is selected
  159. if (numberSpheresSelected != -1)
  160. {
  161. if (zed.IsCameraReady)
  162. {
  163. Vector3 vec = cam.ScreenToWorldPoint(new Vector4(Input.mousePosition.x, Input.mousePosition.y, zed.GetDepthValue(Input.mousePosition)));
  164. // For each sphere selected move their position with the mouse
  165. for (int i = 0; i < currentGOSelected.Count; ++i)
  166. {
  167. currentGOSelected[i].transform.position = vec;
  168. }
  169. }
  170. }
  171. if (zed != null && zed.IsCameraReady)
  172. {
  173. //If left mouse is clicked, add a sphere
  174. if (Input.GetMouseButtonDown(0))
  175. {
  176. //Add a new plane if needed
  177. if (go.Count - 1 < currentPlaneIndex)
  178. {
  179. go.Add(CreateGameObject());
  180. go[currentPlaneIndex].GetComponent<MeshRenderer>().material.renderQueue = QUEUE_TRANSPARENT_VALUE + 5;
  181. meshFilters[currentPlaneIndex] = go[currentPlaneIndex].GetComponent<MeshFilter>();
  182. meshFilters[currentPlaneIndex].sharedMesh = CreateMesh();
  183. meshFilters[currentPlaneIndex].sharedMesh.MarkDynamic();
  184. }
  185. if (numberSpheresSelected != -1)
  186. {
  187. //Remove outline from the sphere cause a sphere was selected
  188. //Clear the meshes and spheres selected
  189. for (int i = 0; i < currentGOSelected.Count; ++i)
  190. {
  191. currentGOSelected[i].GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.00f);
  192. currentGOSelected[i] = null;
  193. }
  194. currentGOSelected.Clear();
  195. for (int i = 0; i < meshFilterSelected.Count; ++i)
  196. {
  197. meshFilterSelected[i].mesh.Clear();
  198. }
  199. meshFilterSelected.Clear();
  200. //Create the planes if needed
  201. for (int i = 0; i < planeSelectedIndex.Count; ++i)
  202. {
  203. if ((borderspheres.Count - planeSelectedIndex[i] * 4) < 4)
  204. {
  205. numberSpheresSelected = -1;
  206. planeSelectedIndex.Clear();
  207. return;
  208. }
  209. List<int> triangles = new List<int>();
  210. points = new List<Vector3>();
  211. for (int j = planeSelectedIndex[i] * 4; j < (planeSelectedIndex[i] + 1) * 4; j++)
  212. {
  213. points.Add(borderspheres[j].transform.position);
  214. }
  215. CloseShape(triangles, points, planeSelectedIndex[i]);
  216. }
  217. numberSpheresSelected = -1;
  218. return;
  219. }
  220. // Add a sphere
  221. else if (points.Count < 100 && !isClosed)
  222. {
  223. Vector3 vec = cam.ScreenToWorldPoint(new Vector4(Input.mousePosition.x, Input.mousePosition.y, zed.GetDepthValue(Input.mousePosition)));
  224. RaycastHit hit;
  225. if (Physics.Raycast(target.position, (vec - target.position), out hit, 10, (1 << sphereLayer)))
  226. {
  227. int hitIndex = borderspheres.IndexOf(hit.transform.gameObject);
  228. vec = borderspheres[hitIndex].transform.position;
  229. }
  230. points.Add(vec);
  231. GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  232. sphere.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
  233. sphere.hideFlags = HideFlags.HideInHierarchy;
  234. sphere.tag = "HelpObject";
  235. sphere.GetComponent<MeshRenderer>().material = outlineMaterial;
  236. sphere.GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.02f);
  237. sphere.transform.position = points[points.Count - 1];
  238. sphere.layer = sphereLayer;
  239. borderspheres.Add(sphere);
  240. if (borderspheres.Count >= 2)
  241. {
  242. borderspheres[borderspheres.Count - 2].GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.00f);
  243. }
  244. if (borderspheres.Count % 4 == 0)
  245. {
  246. points = new List<Vector3>();
  247. for (int i = currentPlaneIndex * 4; i < (currentPlaneIndex + 1) * 4; i++)
  248. {
  249. points.Add(borderspheres[i].transform.position);
  250. }
  251. CloseShape(triangles, points, currentPlaneIndex);
  252. EndPlane();
  253. }
  254. }
  255. }
  256. //Select the sphere, to move them
  257. if (Input.GetMouseButtonDown(1))
  258. {
  259. if (numberSpheresSelected != -1) return;
  260. Vector3 vec = cam.ScreenToWorldPoint(new Vector4(Input.mousePosition.x, Input.mousePosition.y, zed.GetDepthValue(Input.mousePosition)));
  261. RaycastHit[] hits;
  262. hits = Physics.RaycastAll(target.position, (vec - target.position), 10, (1 << sphereLayer));
  263. if (hits.Length > 0)
  264. {
  265. indexSelected.Clear();
  266. currentGOSelected.Clear();
  267. planeSelectedIndex.Clear();
  268. meshFilterSelected.Clear();
  269. for (int i = 0; i < hits.Length; ++i)
  270. {
  271. int hitIndex = borderspheres.IndexOf(hits[i].transform.gameObject);
  272. indexSelected.Add(hitIndex);
  273. currentGOSelected.Add(borderspheres[hitIndex]);
  274. planeSelectedIndex.Add(hitIndex / 4);
  275. meshFilterSelected.Add(meshFilters[planeSelectedIndex[planeSelectedIndex.Count - 1]]);
  276. borderspheres[hitIndex].GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.02f);
  277. }
  278. numberSpheresSelected = hits.Length;
  279. borderspheres[borderspheres.Count - 1].GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.00f);
  280. }
  281. else
  282. {
  283. numberSpheresSelected = -1;
  284. }
  285. }
  286. }
  287. }
  288. }
  289. /// <summary>
  290. /// Finishes the current plane and increases the index of the plane
  291. /// </summary>
  292. private void EndPlane()
  293. {
  294. currentPlaneIndex++;
  295. ResetDataCurrentPlane();
  296. }
  297. /// <summary>
  298. /// Enables editing the matte.
  299. /// </summary>
  300. public void EnterEditMode()
  301. {
  302. if (isClosed)
  303. {
  304. foreach (GameObject s in borderspheres)
  305. {
  306. s.SetActive(true);
  307. }
  308. if (shader_greenScreen != null)
  309. {
  310. Shader.SetGlobalInt("_ZEDStencilComp", 0);
  311. }
  312. for (int i = 0; i < go.Count; i++)
  313. {
  314. if (go[i] == null) continue;
  315. go[i].GetComponent<MeshRenderer>().sharedMaterial.SetFloat("alpha", 0.5f);
  316. go[i].GetComponent<MeshRenderer>().sharedMaterial.renderQueue = QUEUE_TRANSPARENT_VALUE + 5;
  317. }
  318. isClosed = false;
  319. }
  320. }
  321. /// <summary>
  322. /// Removes the last sphere the user placed while defining the matte object's boundaries.
  323. /// </summary>
  324. public void RemoveLastPoint()
  325. {
  326. //Prevent to remove and move a sphere at the same time
  327. if (numberSpheresSelected != -1) return;
  328. if (isClosed)
  329. {
  330. foreach (GameObject s in borderspheres)
  331. {
  332. s.SetActive(true);
  333. }
  334. if (shader_greenScreen != null)
  335. {
  336. Shader.SetGlobalInt("_ZEDStencilComp", 0);
  337. }
  338. for (int i = 0; i < go.Count; i++)
  339. {
  340. if (go[i] == null) continue;
  341. go[i].GetComponent<MeshRenderer>().sharedMaterial.SetFloat("alpha", 0.5f);
  342. go[i].GetComponent<MeshRenderer>().sharedMaterial.renderQueue = QUEUE_TRANSPARENT_VALUE + 5;
  343. }
  344. isClosed = false;
  345. }
  346. if (borderspheres.Count % 4 == 0 && currentPlaneIndex > 0)
  347. {
  348. GameObject.Destroy(go[currentPlaneIndex - 1]);
  349. go.RemoveAll(item => item == null);
  350. meshFilters.RemoveAll(item => item == null);
  351. meshFilters[currentPlaneIndex - 1].sharedMesh.Clear();
  352. currentPlaneIndex--;
  353. }
  354. if (borderspheres != null && borderspheres.Count > 0)
  355. {
  356. GameObject.DestroyImmediate(borderspheres[borderspheres.Count - 1]);
  357. borderspheres.RemoveAt(borderspheres.Count - 1);
  358. if (borderspheres.Count % 4 == 0 && borderspheres.Count > 0)
  359. {
  360. borderspheres[borderspheres.Count - 1].GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.02f);
  361. }
  362. }
  363. }
  364. /// <summary>
  365. /// Clears the boundary points and triangles. Used before making a new plane, or when resetting all data.
  366. /// </summary>
  367. private void ResetDataCurrentPlane()
  368. {
  369. points.Clear();
  370. triangles.Clear();
  371. }
  372. /// <summary>
  373. /// Removes existing sphere objects used to define bounds.
  374. /// Used to ensure they're properly cleaned up when not being used to edit the garbage matte.
  375. /// </summary>
  376. public void CleanSpheres()
  377. {
  378. GameObject[] remain_sphere2 = GameObject.FindGameObjectsWithTag ("HelpObject");
  379. if (remain_sphere2.Length > 0) {
  380. foreach (GameObject sph in remain_sphere2)
  381. GameObject.DestroyImmediate (sph);
  382. }
  383. }
  384. /// <summary>
  385. /// Destroys all planes and spheres used to edit the matte to start from scratch.
  386. /// </summary>
  387. /// <param name="cleansphere"></param>
  388. public void ResetPoints(bool cleansphere)
  389. {
  390. if (cleansphere) {
  391. GameObject[] remain_sphere2 = GameObject.FindGameObjectsWithTag ("HelpObject");
  392. if (remain_sphere2.Length > 0) {
  393. foreach (GameObject sph in remain_sphere2)
  394. GameObject.Destroy (sph);
  395. }
  396. }
  397. Shader.SetGlobalInt("_ZEDStencilComp", 0);
  398. if (go == null) return;
  399. isClosed = false;
  400. currentPlaneIndex = 0;
  401. for (int i = 0; i < go.Count; i++)
  402. {
  403. GameObject.DestroyImmediate(go[i]);
  404. }
  405. go.Clear();
  406. meshFilters.Clear();
  407. ResetDataCurrentPlane();
  408. if (borderspheres != null)
  409. {
  410. foreach (GameObject s in borderspheres)
  411. {
  412. GameObject.DestroyImmediate(s);
  413. }
  414. }
  415. borderspheres.Clear();
  416. if (commandBuffer != null)
  417. {
  418. commandBuffer.Clear();
  419. }
  420. points.Clear ();
  421. }
  422. /// <summary>
  423. /// Helper function to determine a point's orientation along the plane.
  424. /// Used by OrderPoints to sort vertices.
  425. /// </summary>
  426. /// <param name="p1"></param>
  427. /// <param name="p2"></param>
  428. /// <param name="p"></param>
  429. /// <param name="X"></param>
  430. /// <param name="Y"></param>
  431. /// <returns>1 if it should be higher on the list, 0 if it should be lower. </returns>
  432. private static int Orientation(Vector3 p1, Vector3 p2, Vector3 p, Vector3 X, Vector3 Y)
  433. {
  434. return (Vector3.Dot(p2, X) - Vector3.Dot(p1, X)) * (Vector3.Dot(p, Y) - Vector3.Dot(p1, Y)) - (Vector3.Dot(p, X) - Vector3.Dot(p1, X)) * (Vector3.Dot(p2, Y) - Vector3.Dot(p1, Y)) > 0 ? 1 : 0;
  435. }
  436. /// <summary>
  437. /// Orders the points in the points list in an order proper for drawing a mesh.
  438. /// Points need to appear in the list in clockwise order within a triangle being drawn with them, around the plane's normal.
  439. /// </summary>
  440. /// <returns></returns>
  441. private List<int> OrderPoints(List<Vector3> points)
  442. {
  443. Vector3 normal = Vector3.Cross((points[1] - points[0]), (points[2] - points[0]));
  444. normal.Normalize();
  445. Vector3 X = new Vector3(-normal.y, normal.x, 0);
  446. X.Normalize();
  447. Vector3 Y = Vector3.Cross(X, normal);
  448. Y.Normalize();
  449. List<int> orderedIndex = new List<int>();
  450. List<Vector3> convexHull = new List<Vector3>();
  451. float minX = Vector3.Dot(points[0], X);
  452. Vector3 p = points[0];
  453. for (int i = 0; i < points.Count; i++)
  454. {
  455. if (Vector3.Dot(points[i], X) < minX)
  456. {
  457. minX = Vector3.Dot(points[i], X);
  458. p = points[i];
  459. }
  460. }
  461. Vector3 currentTestPoint;
  462. for (int i = 0; i < 4; i++)
  463. {
  464. convexHull.Add(p);
  465. orderedIndex.Add(points.IndexOf(p));
  466. currentTestPoint = points[0];
  467. for (int j = 0; j < points.Count; j++)
  468. {
  469. if ((currentTestPoint == p) || (Orientation(p, currentTestPoint, points[j], X, Y) == 1))
  470. {
  471. currentTestPoint = points[j];
  472. }
  473. }
  474. p = currentTestPoint;
  475. }
  476. return orderedIndex;
  477. }
  478. /// <summary>
  479. /// Finish off the last quad mesh.
  480. /// </summary>
  481. public void CloseShape(List<int> triangles, List<Vector3> points, int currentPlaneIndex)
  482. {
  483. triangles.Clear();
  484. List<int> indexOrder = OrderPoints(points);
  485. triangles.Add(indexOrder[0]);
  486. triangles.Add(indexOrder[1]);
  487. triangles.Add(indexOrder[2]);
  488. triangles.Add(indexOrder[0]);
  489. triangles.Add(indexOrder[2]);
  490. triangles.Add(indexOrder[3]);
  491. if (go[currentPlaneIndex] == null)
  492. {
  493. go[currentPlaneIndex] = CreateGameObject();
  494. meshFilters[currentPlaneIndex] = go[currentPlaneIndex].GetComponent<MeshFilter>();
  495. meshFilters[currentPlaneIndex].sharedMesh = CreateMesh();
  496. meshFilters[currentPlaneIndex].sharedMesh.MarkDynamic();
  497. }
  498. go[currentPlaneIndex].GetComponent<MeshFilter>().sharedMesh.Clear();
  499. go[currentPlaneIndex].GetComponent<MeshFilter>().sharedMesh.vertices = points.ToArray();
  500. go[currentPlaneIndex].GetComponent<MeshFilter>().sharedMesh.triangles = triangles.ToArray();
  501. borderspheres[borderspheres.Count - 1].GetComponent<MeshRenderer>().material.SetFloat("_Outline", 0.00f);
  502. }
  503. /// <summary>
  504. /// Apply the garbage matte by rendering into the stencil buffer.
  505. /// </summary>
  506. public void ApplyGarbageMatte()
  507. {
  508. if (currentPlaneIndex <= 0)
  509. {
  510. editMode = false;
  511. ResetPoints(false);
  512. return;
  513. }
  514. if (shader_greenScreen != null)
  515. {
  516. isClosed = true;
  517. foreach (GameObject s in borderspheres)
  518. {
  519. s.SetActive(false);
  520. }
  521. Shader.SetGlobalInt("_ZEDStencilComp", 3);
  522. for (int i = 0; i < go.Count; i++)
  523. {
  524. if (go[i] == null) continue;
  525. go[i].GetComponent<MeshRenderer>().sharedMaterial.SetFloat("alpha", 0.0f);
  526. go[i].GetComponent<MeshRenderer>().sharedMaterial.renderQueue = QUEUE_TRANSPARENT_VALUE - 5;
  527. }
  528. }
  529. commandBuffer.Clear();
  530. for (int i = 0; i < go.Count; ++i)
  531. {
  532. if (go[i] != null)
  533. {
  534. commandBuffer.DrawMesh(go[i].GetComponent<MeshFilter>().mesh, go[i].transform.localToWorldMatrix, go[i].GetComponent<Renderer>().material);
  535. }
  536. }
  537. editMode = false;
  538. }
  539. private void OnApplicationQuit()
  540. {
  541. ResetPoints(true);
  542. }
  543. /// <summary>
  544. /// Create a hidden GameObject used to hold the editing components.
  545. /// </summary>
  546. /// <returns></returns>
  547. private GameObject CreateGameObject()
  548. {
  549. GameObject plane = new GameObject("PlaneTest");
  550. plane.hideFlags = HideFlags.HideInHierarchy;
  551. meshFilters.Add((MeshFilter)plane.AddComponent(typeof(MeshFilter)));
  552. MeshRenderer renderer = plane.AddComponent(typeof(MeshRenderer)) as MeshRenderer;
  553. renderer.sharedMaterial = new Material(Resources.Load("Materials/Mat_ZED_Mask_Quad") as Material);
  554. renderer.sharedMaterial.SetFloat("alpha", 0.5f);
  555. return plane;
  556. }
  557. private Mesh CreateMesh()
  558. {
  559. Mesh m = new Mesh();
  560. m.name = "ScriptedMesh";
  561. triangles.Add(0);
  562. triangles.Add(1);
  563. triangles.Add(2);
  564. return m;
  565. }
  566. /// <summary>
  567. /// Represents a single plane to be made into a mesh, then a matte.
  568. /// </summary>
  569. [System.Serializable]
  570. public struct Plane
  571. {
  572. public int numberVertices;
  573. public List<Vector3> vertices;
  574. }
  575. /// <summary>
  576. /// Holds all planes to be turned into mattes and the total number of meshes.
  577. /// </summary>
  578. [System.Serializable]
  579. public struct GarbageMatteData
  580. {
  581. public int numberMeshes;
  582. public List<Plane> planes;
  583. }
  584. /// <summary>
  585. /// Packages the current garbage matte into GarbageMatteData, which can be serialized/saved by GreenScreenEditor.
  586. /// </summary>
  587. /// <returns>Data ready to be serialized. </returns>
  588. public GarbageMatteData RegisterData()
  589. {
  590. GarbageMatteData garbageMatteData = new GarbageMatteData();
  591. if (meshFilters == null) return garbageMatteData;
  592. garbageMatteData.numberMeshes = meshFilters.Count;
  593. garbageMatteData.planes = new List<Plane>();
  594. for (int i = 0; i < meshFilters.Count ; i++)
  595. {
  596. Vector3[] vertices = meshFilters[i].mesh.vertices;
  597. Plane p = new Plane();
  598. p.numberVertices = vertices.Length;
  599. p.vertices = new List<Vector3>(vertices);
  600. garbageMatteData.planes.Add(p);
  601. //garbageMatteData.plane.ad
  602. }
  603. return garbageMatteData;
  604. }
  605. /// <summary>
  606. /// Loads a serialized GarbageMatteData instance to be used/viewed/edited.
  607. /// </summary>
  608. /// <param name="garbageMatteData"></param>
  609. /// <returns>True if there was actual data to load (at least one plane).</returns>
  610. public bool LoadData(GarbageMatteData garbageMatteData)
  611. {
  612. int nbMesh = garbageMatteData.numberMeshes;
  613. if (nbMesh < 0) return false;
  614. currentPlaneIndex = 0;
  615. ResetPoints(false);
  616. for (int i = 0; i < nbMesh; i++)
  617. {
  618. points.Clear();
  619. triangles.Clear();
  620. go.Add(CreateGameObject());
  621. go[currentPlaneIndex].GetComponent<MeshRenderer>().material.renderQueue = QUEUE_TRANSPARENT_VALUE + 5;
  622. meshFilters[currentPlaneIndex] = go[currentPlaneIndex].GetComponent<MeshFilter>();
  623. meshFilters[currentPlaneIndex].sharedMesh = CreateMesh();
  624. meshFilters[currentPlaneIndex].sharedMesh.MarkDynamic();
  625. Plane p = garbageMatteData.planes[i];
  626. for (int j = 0; j < p.numberVertices; j++)
  627. {
  628. points.Add(p.vertices[j]);
  629. GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  630. sphere.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
  631. sphere.tag = "HelpObject";
  632. sphere.hideFlags = HideFlags.HideInHierarchy;
  633. outlineMaterial.SetFloat("_Outline", 0.00f);
  634. sphere.GetComponent<MeshRenderer>().material = outlineMaterial;
  635. sphere.transform.position = points[points.Count - 1];
  636. sphere.layer = sphereLayer;
  637. borderspheres.Add(sphere);
  638. }
  639. if (go.Count == 0) return false;
  640. CloseShape(triangles, points, currentPlaneIndex);
  641. EndPlane();
  642. }
  643. return true;
  644. }
  645. /// <summary>
  646. /// Save the points into a file.
  647. /// </summary>
  648. public void Save()
  649. {
  650. List<string> meshes = new List<string>();
  651. meshes.Add((meshFilters.Count - 1).ToString());
  652. for (int i = 0; i < meshFilters.Count - 1; i++)
  653. {
  654. Vector3[] vertices = meshFilters[i].mesh.vertices;
  655. int[] tri = meshFilters[i].mesh.triangles;
  656. meshes.Add("v#" + vertices.Length);
  657. for (int j = 0; j < vertices.Length; j++)
  658. {
  659. meshes.Add(vertices[j].x + " " + vertices[j].y + " " + vertices[j].z);
  660. }
  661. }
  662. System.IO.File.WriteAllLines(garbageMattePath, meshes.ToArray());
  663. }
  664. /// <summary>
  665. /// Load the current shape
  666. /// </summary>
  667. public bool Load()
  668. {
  669. if (!System.IO.File.Exists(garbageMattePath)) return false;
  670. string[] meshes = System.IO.File.ReadAllLines(garbageMattePath);
  671. if (meshes == null) return false;
  672. int nbMesh = int.Parse(meshes[0]);
  673. if (nbMesh < 0) return false;
  674. currentPlaneIndex = 0;
  675. ResetPoints(false);
  676. int lineCount = 1;
  677. string[] splittedLine;
  678. for (int i = 0; i < nbMesh; i++)
  679. {
  680. points.Clear();
  681. triangles.Clear();
  682. go.Add(CreateGameObject());
  683. go[currentPlaneIndex].GetComponent<MeshRenderer>().material.renderQueue = QUEUE_TRANSPARENT_VALUE + 5;
  684. meshFilters[currentPlaneIndex] = go[currentPlaneIndex].GetComponent<MeshFilter>();
  685. meshFilters[currentPlaneIndex].sharedMesh = CreateMesh();
  686. meshFilters[currentPlaneIndex].sharedMesh.MarkDynamic();
  687. splittedLine = meshes[lineCount].Split('#');
  688. lineCount++;
  689. int nbVertices = int.Parse(splittedLine[1]);
  690. for (int j = 0; j < nbVertices; j++)
  691. {
  692. splittedLine = meshes[lineCount].Split(' ');
  693. lineCount++;
  694. float x = float.Parse(splittedLine[0]), y = float.Parse(splittedLine[1]), z = float.Parse(splittedLine[2]);
  695. points.Add(new Vector3(x, y, z));
  696. GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  697. sphere.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
  698. sphere.hideFlags = HideFlags.HideInHierarchy;
  699. sphere.tag = "HelpObject";
  700. sphere.transform.position = points[points.Count - 1];
  701. sphere.layer = sphereLayer;
  702. borderspheres.Add(sphere);
  703. }
  704. if (go.Count == 0) return false;
  705. CloseShape(triangles, points, currentPlaneIndex);
  706. EndPlane();
  707. }
  708. return true;
  709. }
  710. }