SceneBaker.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // Copyright (c) 2014-2017, THUNDERBEAST GAMES LLC All rights reserved
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. //
  21. #include <xmmintrin.h>
  22. #include <pmmintrin.h>
  23. #include <cmath>
  24. #include <cfloat>
  25. #include <ThirdParty/STB/stb_rect_pack.h>
  26. #include <Atomic/Core/WorkQueue.h>
  27. #include <Atomic/IO/Log.h>
  28. #include <Atomic/IO/FileSystem.h>
  29. #include <Atomic/Resource/ResourceCache.h>
  30. #include <Atomic/Graphics/Zone.h>
  31. #include <Atomic/Graphics/Light.h>
  32. #include <Atomic/Graphics/StaticModel.h>
  33. #include "BakeModel.h"
  34. #include "BakeMesh.h"
  35. #include "BakeLight.h"
  36. #include "EmbreeScene.h"
  37. #include "LightMapPacker.h"
  38. #include "SceneBaker.h"
  39. namespace AtomicGlow
  40. {
  41. SceneBaker::SceneBaker(Context* context, const String &projectPath) : Object(context),
  42. currentLightMode_(GLOW_LIGHTMODE_UNDEFINED),
  43. currentGIPass_(0),
  44. projectPath_(AddTrailingSlash(projectPath)),
  45. standaloneMode_(true)
  46. {
  47. embreeScene_ = new EmbreeScene(context_);
  48. }
  49. SceneBaker::~SceneBaker()
  50. {
  51. }
  52. bool SceneBaker::SaveLitScene()
  53. {
  54. if (!standaloneMode_)
  55. {
  56. ATOMIC_LOGERROR("SceneBaker::SaveLitScene() - only supported in standalone mode");
  57. return false;
  58. }
  59. String sceneFilename = AddTrailingSlash(projectPath_) + "Resources/" + scene_->GetFileName();
  60. File saveFile(context_, sceneFilename, FILE_WRITE);
  61. return scene_->SaveXML(saveFile);
  62. }
  63. bool SceneBaker::WriteBakeData(VectorBuffer& buffer)
  64. {
  65. buffer.Clear();
  66. // protocol is very simple right now, can easily be expanded
  67. buffer.WriteUInt(bakeMeshes_.Size());
  68. for (unsigned i = 0; i < bakeMeshes_.Size(); i++)
  69. {
  70. BakeMesh* bakeMesh = bakeMeshes_[i];
  71. Node* node = bakeMesh->GetNode();
  72. StaticModel* staticModel = bakeMesh->GetStaticModel();
  73. buffer.WriteUInt(node->GetID());
  74. buffer.WriteUInt(staticModel->GetID());
  75. buffer.WriteUInt(staticModel->GetLightMask());
  76. buffer.WriteUInt(staticModel->GetLightmapIndex());
  77. buffer.WriteVector4(staticModel->GetLightmapTilingOffset());
  78. }
  79. return true;
  80. }
  81. bool SceneBaker::GenerateLightmaps()
  82. {
  83. ATOMIC_LOGINFO("Generating Lightmaps");
  84. for (unsigned i = 0; i < bakeMeshes_.Size(); i++)
  85. {
  86. BakeMesh* mesh = bakeMeshes_[i];
  87. mesh->GenerateRadianceMap();
  88. }
  89. SharedPtr<LightMapPacker> packer(new LightMapPacker(context_));
  90. for (unsigned i = 0; i < bakeMeshes_.Size(); i++)
  91. {
  92. BakeMesh* mesh = bakeMeshes_[i];
  93. SharedPtr<RadianceMap> radianceMap = mesh->GetRadianceMap();
  94. if (radianceMap.NotNull())
  95. {
  96. packer->AddRadianceMap(radianceMap);
  97. }
  98. }
  99. packer->Pack();
  100. if (!packer->SaveLightmaps(projectPath_, scene_->GetFileName()))
  101. {
  102. return false;
  103. }
  104. if (standaloneMode_)
  105. {
  106. if (!SaveLitScene())
  107. return false;
  108. }
  109. return WriteBakeData(bakeData_);
  110. }
  111. void SceneBaker::TraceRay(LightRay* lightRay, const PODVector<BakeLight*>& bakeLights_)
  112. {
  113. for (unsigned i = 0; i < bakeLights_.Size(); i++)
  114. {
  115. bakeLights_[i]->Light(lightRay);
  116. }
  117. }
  118. bool SceneBaker::LightDirect()
  119. {
  120. // Direct Lighting
  121. currentLightMode_ = GLOW_LIGHTMODE_DIRECT;
  122. if (!bakeMeshes_.Size())
  123. {
  124. ATOMIC_LOGINFO("SceneBaker::LightDirect() - No bake meshes found");
  125. bakeLights_.Clear();
  126. return false;
  127. }
  128. for (unsigned i = 0; i < bakeMeshes_.Size(); i++)
  129. {
  130. BakeMesh* mesh = bakeMeshes_[i];
  131. mesh->Light(GLOW_LIGHTMODE_DIRECT);
  132. }
  133. return true;
  134. }
  135. void SceneBaker::LightDirectFinish()
  136. {
  137. bakeLights_.Clear();
  138. }
  139. bool SceneBaker::LightGI()
  140. {
  141. // Indirect Lighting
  142. currentLightMode_ = GLOW_LIGHTMODE_INDIRECT;
  143. if (!GlobalGlowSettings.giEnabled_ || currentGIPass_ >= GlobalGlowSettings.giMaxBounces_)
  144. {
  145. return false;
  146. }
  147. ATOMIC_LOGINFOF("GI Pass #%i of %i", currentGIPass_ + 1, GlobalGlowSettings.giMaxBounces_);
  148. BounceBakeLight* blight;
  149. unsigned totalBounceSamples = 0;
  150. for (unsigned i = 0; i < bakeMeshes_.Size(); i++)
  151. {
  152. BakeMesh* mesh = bakeMeshes_[i];
  153. blight = mesh->GenerateBounceBakeLight();
  154. if (blight)
  155. {
  156. bakeLights_.Push(SharedPtr<BakeLight>(blight));
  157. totalBounceSamples += blight->GetNumBounceSamples();
  158. }
  159. }
  160. if (!bakeLights_.Size())
  161. return false;
  162. ATOMIC_LOGINFOF("IMPORTANT: Optimize allocation of samples! Indirect lighting with %u bounce lights and %u samples", bakeLights_.Size(), totalBounceSamples);
  163. for (unsigned i = 0; i < bakeMeshes_.Size(); i++)
  164. {
  165. BakeMesh* mesh = bakeMeshes_[i];
  166. mesh->Light(GLOW_LIGHTMODE_INDIRECT);
  167. }
  168. return true;
  169. }
  170. void SceneBaker::LightGIFinish()
  171. {
  172. bakeLights_.Clear();
  173. currentGIPass_++;
  174. if (currentGIPass_ >= GlobalGlowSettings.giMaxBounces_)
  175. {
  176. }
  177. }
  178. bool SceneBaker::Light(const GlowLightMode lightMode)
  179. {
  180. if (lightMode == GLOW_LIGHTMODE_DIRECT)
  181. {
  182. if (!LightDirect())
  183. {
  184. currentLightMode_ = GLOW_LIGHTMODE_COMPLETE;
  185. ATOMIC_LOGINFO("Cycle: Direct Lighting - no work to be done");
  186. return false;
  187. }
  188. ATOMIC_LOGINFO("Cycle: Direct Lighting");
  189. return true;
  190. }
  191. if (lightMode == GLOW_LIGHTMODE_INDIRECT)
  192. {
  193. if (!LightGI())
  194. {
  195. currentLightMode_ = GLOW_LIGHTMODE_COMPLETE;
  196. ATOMIC_LOGINFO("Cycle: GI - no work to be done");
  197. return false;
  198. }
  199. return true;
  200. }
  201. return true;
  202. }
  203. void SceneBaker::LightFinishCycle()
  204. {
  205. if (currentLightMode_ == GLOW_LIGHTMODE_DIRECT)
  206. {
  207. LightDirectFinish();
  208. }
  209. if (currentLightMode_ == GLOW_LIGHTMODE_INDIRECT)
  210. {
  211. LightGIFinish();
  212. }
  213. }
  214. void SceneBaker::QueryLights(const BoundingBox& bbox, PODVector<BakeLight*>& lights)
  215. {
  216. lights.Clear();
  217. for (unsigned i = 0; i < bakeLights_.Size(); i++)
  218. {
  219. // TODO: filter on zone, range, groups
  220. lights.Push(bakeLights_[i]);
  221. }
  222. }
  223. bool SceneBaker::Preprocess()
  224. {
  225. Vector<SharedPtr<BakeMesh>>::Iterator itr = bakeMeshes_.Begin();
  226. while (itr != bakeMeshes_.End())
  227. {
  228. (*itr)->Preprocess();
  229. itr++;
  230. }
  231. embreeScene_->Commit();
  232. return true;
  233. }
  234. bool SceneBaker::LoadScene(const String& filename)
  235. {
  236. ResourceCache* cache = GetSubsystem<ResourceCache>();
  237. SharedPtr<File> file = cache->GetFile(filename);
  238. if (!file || !file->IsOpen())
  239. {
  240. return false;
  241. }
  242. scene_ = new Scene(context_);
  243. if (!scene_->LoadXML(*file))
  244. {
  245. scene_ = 0;
  246. return false;
  247. }
  248. // IMPORTANT!, if scene updates are enabled
  249. // the Octree component will add work queue items
  250. // and will call WorkQueue->Complete(), see Octree::HandleRenderUpdate
  251. scene_->SetUpdateEnabled(false);
  252. // Zones
  253. PODVector<Node*> zoneNodes;
  254. PODVector<Zone*> zones;
  255. scene_->GetChildrenWithComponent<Zone>(zoneNodes, true);
  256. for (unsigned i = 0; i < zoneNodes.Size(); i++)
  257. {
  258. Zone* zone = zoneNodes[i]->GetComponent<Zone>();
  259. if (!zone->GetNode()->IsEnabled() || !zone->IsEnabled())
  260. continue;
  261. zones.Push(zone);;
  262. SharedPtr<ZoneBakeLight> zlight(new ZoneBakeLight(context_, this));
  263. zlight->SetZone(zone);
  264. bakeLights_.Push(zlight);
  265. }
  266. // Lights
  267. PODVector<Node*> lightNodes;
  268. scene_->GetChildrenWithComponent<Atomic::Light>(lightNodes, true);
  269. for (unsigned i = 0; i < lightNodes.Size(); i++)
  270. {
  271. Atomic::Light* light = lightNodes[i]->GetComponent<Atomic::Light>();
  272. if (!light->GetNode()->IsEnabled()|| !light->IsEnabled())
  273. continue;
  274. if (light->GetLightType() == LIGHT_DIRECTIONAL)
  275. {
  276. SharedPtr<DirectionalBakeLight> dlight(new DirectionalBakeLight(context_, this));
  277. dlight->SetLight(light);
  278. bakeLights_.Push(dlight);
  279. }
  280. else if (light->GetLightType() == LIGHT_POINT)
  281. {
  282. SharedPtr<PointBakeLight> dlight(new PointBakeLight(context_, this));
  283. dlight->SetLight(light);
  284. bakeLights_.Push(dlight);
  285. }
  286. }
  287. // Static Models
  288. PODVector<StaticModel*> staticModels;
  289. scene_->GetComponents<StaticModel>(staticModels, true);
  290. for (unsigned i = 0; i < staticModels.Size(); i++)
  291. {
  292. StaticModel* staticModel = staticModels[i];
  293. if (!staticModel->GetNode()->IsEnabled() || !staticModel->IsEnabled())
  294. continue;
  295. Vector3 center = staticModel->GetWorldBoundingBox().Center();
  296. int bestPriority = M_MIN_INT;
  297. Zone* newZone = 0;
  298. for (PODVector<Zone*>::Iterator i = zones.Begin(); i != zones.End(); ++i)
  299. {
  300. Zone* zone = *i;
  301. int priority = zone->GetPriority();
  302. if (priority > bestPriority && (staticModel->GetZoneMask() & zone->GetZoneMask()) && zone->IsInside(center))
  303. {
  304. newZone = zone;
  305. bestPriority = priority;
  306. }
  307. }
  308. staticModel->SetZone(newZone, false);
  309. if (staticModel->GetModel() && (staticModel->GetLightmap() ||staticModel->GetCastShadows()))
  310. {
  311. Model* model = staticModel->GetModel();
  312. for (unsigned i = 0; i < model->GetNumGeometries(); i++)
  313. {
  314. Geometry* geo = model->GetGeometry(i, 0);
  315. if (!geo)
  316. {
  317. ATOMIC_LOGERRORF("SceneBaker::LoadScene - model without geometry: %s", model->GetName().CString());
  318. return false;
  319. }
  320. const unsigned char* indexData = 0;
  321. unsigned indexSize = 0;
  322. unsigned vertexSize = 0;
  323. const unsigned char* vertexData = 0;
  324. const PODVector<VertexElement>* elements = 0;
  325. geo->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
  326. if (!indexData || !indexSize || !vertexData || !vertexSize || !elements)
  327. {
  328. ATOMIC_LOGERRORF("SceneBaker::LoadScene - Unable to inspect geometry elements: %s", model->GetName().CString());
  329. return false;
  330. }
  331. int texcoords = 0;
  332. for (unsigned i = 0; i < elements->Size(); i++)
  333. {
  334. const VertexElement& element = elements->At(i);
  335. if (element.type_ == TYPE_VECTOR2 && element.semantic_ == SEM_TEXCOORD)
  336. {
  337. texcoords++;
  338. }
  339. }
  340. if (texcoords < 2)
  341. {
  342. ATOMIC_LOGERRORF("SceneBaker::LoadScene - Model without lightmap UV set, skipping: %s", model->GetName().CString());
  343. continue;
  344. }
  345. }
  346. SharedPtr<BakeMesh> meshMap (new BakeMesh(context_, this));
  347. meshMap->SetStaticModel(staticModel);
  348. bakeMeshes_.Push(meshMap);
  349. }
  350. }
  351. return Preprocess();
  352. }
  353. }