The Swartz-Manning’s first exhibit will provide a detailed history of Aaron Swartz Day. https://www.aaronswartzday.org/vr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CreateShadowObject.cs 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /**
  2. * This script demonstrates how to create a new action that can be accessed from the
  3. * ProBuilder toolbar.
  4. *
  5. * A new menu item is registered under "Geometry" actions called "Gen. Shadows".
  6. *
  7. * To enable, remove the #if PROBUILDER_API_EXAMPLE and #endif directives.
  8. */
  9. // Uncomment this line to enable the menu action.
  10. // #define PROBUILDER_API_EXAMPLE
  11. #if PROBUILDER_API_EXAMPLE
  12. using UnityEngine;
  13. using UnityEditor;
  14. using ProBuilder2.Common;
  15. using ProBuilder2.MeshOperations;
  16. using ProBuilder2.EditorCommon;
  17. using ProBuilder2.Interface;
  18. using System.Linq;
  19. using System.Collections.Generic;
  20. using UnityEngine.Rendering;
  21. /**
  22. * When creating your own actions please use your own namespace.
  23. */
  24. namespace ProBuilder2.Actions
  25. {
  26. /**
  27. * This class is responsible for loading the pb_MenuAction into the toolbar and menu.
  28. */
  29. [InitializeOnLoad]
  30. static class RegisterCustomAction
  31. {
  32. /**
  33. * Static initializer is called when Unity loads the assembly.
  34. */
  35. static RegisterCustomAction()
  36. {
  37. // This registers a new CreateShadowObject menu action with the toolbar.
  38. pb_EditorToolbarLoader.RegisterMenuItem(InitCustomAction);
  39. }
  40. /**
  41. * Helper function to load a new menu action object.
  42. */
  43. static pb_MenuAction InitCustomAction()
  44. {
  45. return new CreateShadowObject();
  46. }
  47. /**
  48. * Usually you'll want to add a menu item entry for your action.
  49. * https://docs.unity3d.com/ScriptReference/MenuItem.html
  50. */
  51. [MenuItem("Tools/ProBuilder/Object/Create Shadow Object", true)]
  52. static bool MenuVerifyDoSomethingWithPbObject()
  53. {
  54. // Using pb_EditorToolbarLoader.GetInstance keeps MakeFacesDoubleSided as a singleton.
  55. CreateShadowObject instance = pb_EditorToolbarLoader.GetInstance<CreateShadowObject>();
  56. return instance != null && instance.IsEnabled();
  57. }
  58. [MenuItem("Tools/ProBuilder/Object/Create Shadow Object", false, pb_Constant.MENU_GEOMETRY + 3)]
  59. static void MenuDoDoSomethingWithPbObject()
  60. {
  61. CreateShadowObject instance = pb_EditorToolbarLoader.GetInstance<CreateShadowObject>();
  62. if(instance != null)
  63. pb_EditorUtility.ShowNotification(instance.DoAction().notification);
  64. }
  65. }
  66. /**
  67. * This is the actual action that will be executed.
  68. */
  69. public class CreateShadowObject : pb_MenuAction
  70. {
  71. public override pb_ToolbarGroup group { get { return pb_ToolbarGroup.Object; } }
  72. public override Texture2D icon { get { return null; } }
  73. public override pb_TooltipContent tooltip { get { return _tooltip; } }
  74. private GUIContent gc_volumeSize = new GUIContent("Volume Size", "How far the shadow volume extends from the base mesh. To visualize, imagine the width of walls.\n\nYou can also select the child ShadowVolume object and turn the Shadow Casting Mode to \"One\" or \"Two\" sided to see the resulting mesh.");
  75. private bool showPreview
  76. {
  77. get { return pb_PreferencesInternal.GetBool("pb_shadowVolumePreview", true); }
  78. set { pb_PreferencesInternal.SetBool("pb_shadowVolumePreview", value); }
  79. }
  80. /**
  81. * What to show in the hover tooltip window. pb_TooltipContent is similar to GUIContent, with the exception that it also
  82. * includes an optional params[] char list in the constructor to define shortcut keys (ex, CMD_CONTROL, K).
  83. */
  84. static readonly pb_TooltipContent _tooltip = new pb_TooltipContent
  85. (
  86. "Gen Shadow Obj",
  87. "Creates a new ProBuilder mesh child with inverted normals that only exists to cast shadows. Use to create lit interior scenes with shadows from directional lights.\n\nNote that this exists largely as a workaround for real-time shadow light leaks. Baked shadows do not require this workaround.",
  88. "" // Some combination of build settings can cause the compiler to not respection optional params in the pb_TooltipContent c'tor?
  89. );
  90. /**
  91. * Determines if the action should be enabled or grayed out.
  92. */
  93. public override bool IsEnabled()
  94. {
  95. // `selection` is a helper property on pb_MenuAction that returns a pb_Object[] array from the current selection.
  96. return pb_Editor.instance != null &&
  97. selection != null &&
  98. selection.Length > 0;
  99. }
  100. /**
  101. * Determines if the action should be loaded in the menu (ex, face actions shouldn't be shown when in vertex editing mode).
  102. */
  103. public override bool IsHidden()
  104. {
  105. return pb_Editor.instance == null;
  106. }
  107. public override MenuActionState AltState()
  108. {
  109. return MenuActionState.VisibleAndEnabled;
  110. }
  111. public override void OnSettingsEnable()
  112. {
  113. if( showPreview )
  114. DoAction();
  115. }
  116. public override void OnSettingsGUI()
  117. {
  118. GUILayout.Label("Create Shadow Volume Options", EditorStyles.boldLabel);
  119. EditorGUI.BeginChangeCheck();
  120. EditorGUI.BeginChangeCheck();
  121. float volumeSize = pb_PreferencesInternal.GetFloat("pb_CreateShadowObject_volumeSize", .07f);
  122. volumeSize = EditorGUILayout.Slider(gc_volumeSize, volumeSize, 0.001f, 1f);
  123. if( EditorGUI.EndChangeCheck() )
  124. pb_PreferencesInternal.SetFloat("pb_CreateShadowObject_volumeSize", volumeSize);
  125. #if !UNITY_4_6 && !UNITY_4_7
  126. EditorGUI.BeginChangeCheck();
  127. ShadowCastingMode shadowMode = (ShadowCastingMode) pb_PreferencesInternal.GetInt("pb_CreateShadowObject_shadowMode", (int) ShadowCastingMode.ShadowsOnly);
  128. shadowMode = (ShadowCastingMode) EditorGUILayout.EnumPopup("Shadow Casting Mode", shadowMode);
  129. if(EditorGUI.EndChangeCheck())
  130. pb_PreferencesInternal.SetInt("pb_CreateShadowObject_shadowMode", (int) shadowMode);
  131. #endif
  132. EditorGUI.BeginChangeCheck();
  133. ExtrudeMethod extrudeMethod = (ExtrudeMethod) pb_PreferencesInternal.GetInt("pb_CreateShadowObject_extrudeMethod", (int) ExtrudeMethod.FaceNormal);
  134. extrudeMethod = (ExtrudeMethod) EditorGUILayout.EnumPopup("Extrude Method", extrudeMethod);
  135. if(EditorGUI.EndChangeCheck())
  136. pb_PreferencesInternal.SetInt("pb_CreateShadowObject_extrudeMethod", (int) extrudeMethod);
  137. if(EditorGUI.EndChangeCheck())
  138. DoAction();
  139. GUILayout.FlexibleSpace();
  140. if(GUILayout.Button("Create Shadow Volume"))
  141. {
  142. DoAction();
  143. SceneView.RepaintAll();
  144. pb_MenuOption.CloseAll();
  145. }
  146. }
  147. /**
  148. * Do the thing. Return a pb_ActionResult indicating the success/failure of action.
  149. */
  150. public override pb_ActionResult DoAction()
  151. {
  152. #if !UNITY_4_6 && !UNITY_4_7
  153. ShadowCastingMode shadowMode = (ShadowCastingMode) pb_PreferencesInternal.GetInt("pb_CreateShadowObject_shadowMode", (int) ShadowCastingMode.ShadowsOnly);
  154. #endif
  155. float extrudeDistance = pb_PreferencesInternal.GetFloat("pb_CreateShadowObject_volumeSize", .08f);
  156. ExtrudeMethod extrudeMethod = (ExtrudeMethod) pb_PreferencesInternal.GetInt("pb_CreateShadowObject_extrudeMethod", (int) ExtrudeMethod.FaceNormal);
  157. foreach(pb_Object pb in selection)
  158. {
  159. pb_Object shadow = GetShadowObject(pb);
  160. if(shadow == null)
  161. continue;
  162. foreach(pb_Face f in shadow.faces) { f.ReverseIndices(); f.manualUV = true; }
  163. shadow.Extrude(shadow.faces, extrudeMethod, extrudeDistance);
  164. shadow.ToMesh();
  165. shadow.Refresh();
  166. shadow.Optimize();
  167. #if !UNITY_4_6 && !UNITY_4_7
  168. MeshRenderer mr = shadow.gameObject.GetComponent<MeshRenderer>();
  169. mr.shadowCastingMode = shadowMode;
  170. if(shadowMode == ShadowCastingMode.ShadowsOnly)
  171. mr.receiveShadows = false;
  172. #endif
  173. Collider collider = shadow.GetComponent<Collider>();
  174. while(collider != null)
  175. {
  176. GameObject.DestroyImmediate(collider);
  177. collider = shadow.GetComponent<Collider>();
  178. }
  179. }
  180. // This is necessary! Otherwise the pb_Editor will be working with caches from
  181. // outdated meshes and throw errors.
  182. pb_Editor.Refresh();
  183. return new pb_ActionResult(Status.Success, "Create Shadow Object");
  184. }
  185. private pb_Object GetShadowObject(pb_Object pb)
  186. {
  187. if(pb == null || pb.name.Contains("-ShadowVolume"))
  188. return null;
  189. for(int i = 0; i < pb.transform.childCount; i++)
  190. {
  191. Transform t = pb.transform.GetChild(i);
  192. if(t.name.Equals(string.Format("{0}-ShadowVolume", pb.name)))
  193. {
  194. pb_Object shadow = t.GetComponent<pb_Object>();
  195. if(shadow != null)
  196. {
  197. pbUndo.RecordObject(shadow, "Update Shadow Object");
  198. pb_Face[] faces = new pb_Face[pb.faces.Length];
  199. for(int nn = 0; nn < pb.faces.Length; nn++)
  200. faces[nn] = new pb_Face(pb.faces[nn]);
  201. shadow.GeometryWithVerticesFaces(pb.vertices, faces);
  202. return shadow;
  203. }
  204. }
  205. }
  206. pb_Object new_shadow = pb_Object.InitWithObject(pb);
  207. new_shadow.name = string.Format("{0}-ShadowVolume", pb.name);
  208. new_shadow.MakeUnique();
  209. new_shadow.transform.SetParent(pb.transform, false);
  210. Undo.RegisterCreatedObjectUndo(new_shadow.gameObject, "Create Shadow Object");
  211. return new_shadow;
  212. }
  213. }
  214. }
  215. #endif