EditorCubeCapture.as 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /// Settings
  2. String cubeMapGen_Name;
  3. String cubeMapGen_Path;
  4. int cubeMapGen_Size;
  5. Array<EditorCubeCapture@> activeCubeCapture; // Editor capture tasks in progress, Stop() method of EditorCubeCapture moves forward through the queue as captures are finished
  6. Array<Zone@> cloneZones; // Duplicate zones constructed to prevent IBL doubling
  7. Array<Zone@> disabledZones; // Zones that were disabled to prevent IBL doubling
  8. const String cubemapDefaultOutputPath = "Textures/Cubemaps";
  9. void PrepareZonesForCubeRendering()
  10. {
  11. // Only clone zones when we aren't actively processing
  12. if (cloneZones.length > 0)
  13. return;
  14. Array<Component@>@ zones = editorScene.GetComponents("Zone", true);
  15. for (uint i = 0; i < zones.length; ++i)
  16. {
  17. Zone@ srcZone = cast<Zone>(zones[i]);
  18. if (zones[i].enabled)
  19. {
  20. Zone@ cloneZone = srcZone.node.CreateComponent("Zone");
  21. cloneZone.zoneMask = srcZone.zoneMask;
  22. cloneZone.priority = srcZone.priority;
  23. cloneZone.boundingBox = srcZone.boundingBox;
  24. cloneZone.ambientColor = srcZone.ambientColor;
  25. cloneZone.ambientGradient = srcZone.ambientGradient;
  26. cloneZone.fogColor = srcZone.fogColor;
  27. cloneZone.fogStart = srcZone.fogStart;
  28. cloneZone.fogEnd = srcZone.fogEnd;
  29. cloneZone.fogHeight = srcZone.fogHeight;
  30. cloneZone.fogHeightScale = srcZone.fogHeightScale;
  31. cloneZone.heightFog = srcZone.heightFog;
  32. srcZone.enabled = false;
  33. // Add the zones to our temporary lists
  34. cloneZones.Push(cloneZone);
  35. disabledZones.Push(srcZone);
  36. }
  37. }
  38. // Hide grid and debugIcons until bake
  39. if (grid !is null)
  40. grid.viewMask = 0;
  41. if (debugIconsNode !is null)
  42. debugIconsNode.enabled = false;
  43. debugRenderDisabled = true;
  44. }
  45. void UnprepareZonesForCubeRendering()
  46. {
  47. // Clean up the clones
  48. for (uint i = 0; i < cloneZones.length; ++i)
  49. cloneZones[i].Remove();
  50. cloneZones.Clear();
  51. // Reenable anyone we disabled
  52. for (uint i = 0; i < disabledZones.length; ++i)
  53. disabledZones[i].enabled = true;
  54. disabledZones.Clear();
  55. // Show grid and debug icons
  56. if (grid !is null)
  57. grid.viewMask = 0x80000000;
  58. if (debugIconsNode !is null)
  59. debugIconsNode.enabled = true;
  60. debugRenderDisabled = false;
  61. }
  62. class EditorCubeCapture : ScriptObject // script object in order to get events
  63. {
  64. private String name_;
  65. private String path_;
  66. private Node@ camNode_;
  67. private Camera@ camera_;
  68. private Zone@ target_;
  69. private Viewport@ viewport_;
  70. private Texture2D@ renderImage_;
  71. private RenderSurface@ renderSurface_;
  72. int updateCycle_;
  73. String imagePath_;
  74. EditorCubeCapture(Zone@ forZone)
  75. {
  76. PrepareZonesForCubeRendering();
  77. // Store name and path because if we have a lot of zones it could take long enough to queue another go, and it may have different settings
  78. name_ = cubeMapGen_Name;
  79. path_ = sceneResourcePath + cubeMapGen_Path;
  80. updateCycle_ = 0;
  81. target_ = forZone;
  82. camNode_ = scene.CreateChild("RenderCamera");
  83. camera_ = camNode_.GetOrCreateComponent("Camera");
  84. camera_.fov = 90.0f;
  85. camera_.nearClip = 0.0001f;
  86. camera_.aspectRatio = 1.0f;
  87. camNode_.worldPosition = forZone.node.worldPosition;
  88. viewport_ = Viewport(scene, camera_);
  89. viewport_.renderPath = renderer.viewports[0].renderPath;
  90. updateCycle_ = 0;
  91. }
  92. ~EditorCubeCapture()
  93. {
  94. camNode_.Remove();
  95. }
  96. void Start()
  97. {
  98. // Construct render surface
  99. renderImage_ = Texture2D();
  100. renderImage_.SetSize(cubeMapGen_Size, cubeMapGen_Size, Graphics::GetRGBAFormat(), TEXTURE_RENDERTARGET);
  101. renderSurface_ = renderImage_.renderSurface;
  102. renderSurface_.viewports[0] = viewport_;
  103. renderSurface_.updateMode = SURFACE_UPDATEALWAYS;
  104. SubscribeToEvent("BeginFrame", "HandlePreRender");
  105. SubscribeToEvent("EndFrame", "HandlePostRender");
  106. }
  107. private void Stop()
  108. {
  109. camNode_.Remove();
  110. camNode_ = null;
  111. viewport_ = null;
  112. renderSurface_ = null;
  113. UnsubscribeFromEvent("BeginFrame");
  114. UnsubscribeFromEvent("EndFrame");
  115. WriteXML();
  116. // Remove ourselves from the processing list and if necessary clean things up
  117. // If others are pending in the queue then start the next one
  118. activeCubeCapture.Erase(activeCubeCapture.FindByRef(this));
  119. if (activeCubeCapture.length == 0)
  120. UnprepareZonesForCubeRendering();
  121. else
  122. activeCubeCapture[0].Start();
  123. }
  124. // Position camera accordingly
  125. void HandlePreRender(StringHash eventType, VariantMap& eventData)
  126. {
  127. if (camNode_ !is null)
  128. {
  129. ++updateCycle_;
  130. if (updateCycle_ < 7)
  131. camNode_.worldRotation = RotationOf(GetFaceForCycle(updateCycle_));
  132. else
  133. Stop();
  134. }
  135. }
  136. // Save our image
  137. void HandlePostRender(StringHash eventType, VariantMap& eventData)
  138. {
  139. Image@ img = renderImage_.GetImage();
  140. String sceneName = editorScene.name.length > 0 ? editorScene.name + "/" : "";
  141. String path = path_ + "/" + sceneName;
  142. fileSystem.CreateDir(path);
  143. path = path + "/" + String(target_.id) + "_" + GetFaceName(GetFaceForCycle(updateCycle_)) + ".png";
  144. img.SavePNG(path);
  145. }
  146. private void WriteXML()
  147. {
  148. String sceneName = editorScene.name.length > 0 ? "/" + editorScene.name + "/" : "";
  149. String basePath = AddTrailingSlash(path_ + sceneName);
  150. String cubeName = name_.length > 0 ? (name_ + "_") : "";
  151. String xmlPath = basePath + "/" + name_ + String(target_.id) + ".xml";
  152. XMLFile@ file = XMLFile();
  153. XMLElement rootElem = file.CreateRoot("cubemap");
  154. for (int i = 0; i < 6; ++i)
  155. {
  156. XMLElement faceElem = rootElem.CreateChild("face");
  157. faceElem.SetAttribute("name", GetResourceNameFromFullName(basePath + cubeName + String(target_.id) + "_" + GetFaceName(CubeMapFace(i)) + ".png"));
  158. }
  159. file.Save(File(xmlPath, FILE_WRITE), " ");
  160. ResourceRef ref;
  161. ref.type = StringHash("TextureCube");
  162. ref.name = GetResourceNameFromFullName(xmlPath);
  163. target_.SetAttribute("Zone Texture", Variant(ref));
  164. }
  165. private CubeMapFace GetFaceForCycle(int cycle)
  166. {
  167. switch (updateCycle_)
  168. {
  169. case 1:
  170. return FACE_POSITIVE_X;
  171. case 2:
  172. return FACE_POSITIVE_Y;
  173. case 3:
  174. return FACE_POSITIVE_Z;
  175. case 4:
  176. return FACE_NEGATIVE_X;
  177. case 5:
  178. return FACE_NEGATIVE_Y;
  179. case 6:
  180. return FACE_NEGATIVE_Z;
  181. }
  182. return FACE_POSITIVE_X;
  183. }
  184. private String GetFaceName(CubeMapFace face)
  185. {
  186. switch (face)
  187. {
  188. case FACE_POSITIVE_X:
  189. return "PosX";
  190. case FACE_POSITIVE_Y:
  191. return "PosY";
  192. case FACE_POSITIVE_Z:
  193. return "PosZ";
  194. case FACE_NEGATIVE_X:
  195. return "NegX";
  196. case FACE_NEGATIVE_Y:
  197. return "NegY";
  198. case FACE_NEGATIVE_Z:
  199. return "NegZ";
  200. }
  201. return "PosX";
  202. }
  203. private Quaternion RotationOf(CubeMapFace face)
  204. {
  205. Quaternion result;
  206. switch (face)
  207. {
  208. // Rotate camera according to probe rotation
  209. case FACE_POSITIVE_X:
  210. result = Quaternion(0, 90, 0);
  211. break;
  212. case FACE_NEGATIVE_X:
  213. result = Quaternion(0, -90, 0);
  214. break;
  215. case FACE_POSITIVE_Y:
  216. result = Quaternion(-90, 0, 0);
  217. break;
  218. case FACE_NEGATIVE_Y:
  219. result = Quaternion(90, 0, 0);
  220. break;
  221. case FACE_POSITIVE_Z:
  222. result = Quaternion(0, 0, 0);
  223. break;
  224. case FACE_NEGATIVE_Z:
  225. result = Quaternion(0, 180, 0);
  226. break;
  227. }
  228. return result;
  229. }
  230. }