BakeMesh.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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 "EmbreeScene.h"
  22. #include <Atomic/Core/WorkQueue.h>
  23. #include <Atomic/IO/Log.h>
  24. #include <Atomic/Graphics/Zone.h>
  25. #include <AtomicGlow/Common/GlowSettings.h>
  26. #include "Raster.h"
  27. #include "LightRay.h"
  28. #include "SceneBaker.h"
  29. #include "RadianceMap.h"
  30. #include "BakeLight.h"
  31. #include "BakeMesh.h"
  32. namespace AtomicGlow
  33. {
  34. BakeMesh::BakeMesh(Context* context, SceneBaker *sceneBaker) : BakeNode(context, sceneBaker),
  35. numVertices_(0),
  36. numTriangles_(0),
  37. radianceHeight_(0),
  38. radianceWidth_(0),
  39. embreeGeomID_(RTC_INVALID_GEOMETRY_ID),
  40. numWorkItems_(0),
  41. ambientColor_(Color::BLACK)
  42. {
  43. }
  44. BakeMesh::~BakeMesh()
  45. {
  46. }
  47. void BakeMesh::Pack(unsigned lightmapIdx, Vector4 tilingOffset)
  48. {
  49. if (radianceMap_.NotNull())
  50. {
  51. radianceMap_->packed_ = true;
  52. }
  53. // modify the in memory scene, which will either become data for the editor
  54. // or in standalone mode, saved out the scene
  55. if (staticModel_)
  56. {
  57. staticModel_->SetLightMask(0);
  58. staticModel_->SetLightmapIndex(lightmapIdx);
  59. staticModel_->SetLightmapTilingOffset(tilingOffset);
  60. }
  61. }
  62. bool BakeMesh::FillLexelsCallback(void* param, int x, int y, const Vector3& barycentric,const Vector3& dx, const Vector3& dy, float coverage)
  63. {
  64. return ((ShaderData*) param)->bakeMesh_->LightPixel((ShaderData*) param, x, y, barycentric, dx, dy, coverage);
  65. }
  66. bool BakeMesh::LightPixel(ShaderData* shaderData, int x, int y, const Vector3& barycentric,const Vector3& dx, const Vector3& dy, float coverage)
  67. {
  68. if (x >= radianceWidth_ || y >= radianceHeight_)
  69. return true;
  70. meshMutex_.Acquire();
  71. bool accept = radiancePassAccept_[y * radianceWidth_ + x];
  72. // check whether we've already lit this pixel
  73. if (accept)
  74. {
  75. meshMutex_.Release();
  76. return true;
  77. }
  78. radiancePassAccept_[y * radianceWidth_ + x] = true;
  79. meshMutex_.Release();
  80. MMTriangle* tri = &triangles_[shaderData->triangleIdx_];
  81. MMVertex* verts[3];
  82. verts[0] = &vertices_[tri->indices_[0]];
  83. verts[1] = &vertices_[tri->indices_[1]];
  84. verts[2] = &vertices_[tri->indices_[2]];
  85. LightRay ray;
  86. LightRay::SamplePoint& sample = ray.samplePoint_;
  87. sample.bakeMesh = this;
  88. sample.triangle = shaderData->triangleIdx_;
  89. sample.barycentric = barycentric;
  90. sample.radianceX = x;
  91. sample.radianceY = y;
  92. sample.position = verts[0]->position_ * barycentric.x_ +
  93. verts[1]->position_ * barycentric.y_ +
  94. verts[2]->position_ * barycentric.z_;
  95. sample.normal = verts[0]->normal_ * barycentric.x_ +
  96. verts[1]->normal_ * barycentric.y_ +
  97. verts[2]->normal_ * barycentric.z_;
  98. sample.uv0 = verts[0]->uv0_ * barycentric.x_ +
  99. verts[1]->uv0_ * barycentric.y_ +
  100. verts[2]->uv0_ * barycentric.z_;
  101. sample.uv1 = verts[0]->uv1_ * barycentric.x_ +
  102. verts[1]->uv1_ * barycentric.y_ +
  103. verts[2]->uv1_ * barycentric.z_;
  104. sceneBaker_->TraceRay(&ray, bakeLights_);
  105. return true;
  106. }
  107. void BakeMesh::LightTrianglesWork(const WorkItem* item, unsigned threadIndex)
  108. {
  109. ShaderData shaderData;
  110. BakeMesh* bakeMesh = shaderData.bakeMesh_ = (BakeMesh*) item->aux_;
  111. shaderData.lightMode_ = bakeMesh->GetSceneBaker()->GetCurrentLightMode();
  112. Vector2 triUV1[3];
  113. Vector2 extents(bakeMesh->radianceWidth_, bakeMesh->radianceHeight_);
  114. MMTriangle* start = reinterpret_cast<MMTriangle*>(item->start_);
  115. MMTriangle* end = reinterpret_cast<MMTriangle*>(item->end_);
  116. while (start <= end)
  117. {
  118. MMTriangle* tri = start;
  119. shaderData.triangleIdx_ = tri - &bakeMesh->triangles_[0];
  120. start++;
  121. for (unsigned j = 0; j < 3; j++)
  122. {
  123. unsigned idx = tri->indices_[j];
  124. triUV1[j] = bakeMesh->vertices_[idx].uv1_;
  125. triUV1[j].x_ *= float(bakeMesh->radianceWidth_);
  126. triUV1[j].y_ *= float(bakeMesh->radianceHeight_);
  127. triUV1[j].x_ = Clamp<float>(triUV1[j].x_, 0.0f, bakeMesh->radianceWidth_);
  128. triUV1[j].y_ = Clamp<float>(triUV1[j].y_, 0.0f, bakeMesh->radianceHeight_);
  129. }
  130. Raster::DrawTriangle(true, extents, false, triUV1, FillLexelsCallback, &shaderData );
  131. }
  132. }
  133. void BakeMesh::ContributeRadiance(const LightRay* lightRay, const Vector3& radiance, GlowLightMode lightMode)
  134. {
  135. MutexLock lock(meshMutex_);
  136. const LightRay::SamplePoint& source = lightRay->samplePoint_;
  137. unsigned radX = source.radianceX;
  138. unsigned radY = source.radianceY;
  139. const Vector3& v = radiance_[radY * radianceWidth_ + radX];
  140. radianceTriIndices_[radY * radianceWidth_ + radX] = source.triangle;
  141. if (v.x_ < 0.0f)
  142. {
  143. radiance_[radY * radianceWidth_ + radX] = radiance;
  144. }
  145. else
  146. {
  147. radiance_[radY * radianceWidth_ + radX] += radiance;
  148. }
  149. }
  150. void BakeMesh::GenerateRadianceMap()
  151. {
  152. if (radianceMap_.NotNull())
  153. return;
  154. radianceMap_ = new RadianceMap(context_, this);
  155. }
  156. void BakeMesh::Light(GlowLightMode mode)
  157. {
  158. if (mode == GLOW_LIGHTMODE_INDIRECT && !GlobalGlowSettings.giEnabled_)
  159. return;
  160. if (!GetLightmap() || !radianceWidth_ || !radianceHeight_ || !numTriangles_)
  161. return;
  162. bakeLights_.Clear();
  163. sceneBaker_->QueryLights(boundingBox_, bakeLights_);
  164. // for all triangles
  165. for (unsigned i = 0; i < radianceWidth_ * radianceHeight_; i++)
  166. {
  167. radiancePassAccept_[i] = false;
  168. }
  169. WorkQueue* queue = GetSubsystem<WorkQueue>();
  170. unsigned numTrianglePerItem = numTriangles_ / 4 ? numTriangles_ / 4 : numTriangles_;
  171. unsigned curIdx = 0;
  172. numWorkItems_ = 0;
  173. while (true)
  174. {
  175. SharedPtr<WorkItem> item = queue->GetFreeItem();
  176. item->priority_ = M_MAX_UNSIGNED;
  177. item->workFunction_ = LightTrianglesWork;
  178. item->aux_ = this;
  179. item->start_ = &triangles_[curIdx];
  180. unsigned endIdx = curIdx + numTrianglePerItem;
  181. if (endIdx < numTriangles_)
  182. {
  183. item->end_ = &triangles_[endIdx];
  184. }
  185. else
  186. {
  187. item->end_ = &triangles_[numTriangles_ - 1];
  188. }
  189. item->sendEvent_ = true;
  190. queue->AddWorkItem(item);
  191. numWorkItems_++;
  192. if (item->end_ == &triangles_[numTriangles_ - 1])
  193. break;
  194. curIdx += numTrianglePerItem + 1;
  195. }
  196. }
  197. static unsigned CalcLightMapSize(unsigned sz)
  198. {
  199. // highest multiple of 8, note rasterizer requires a multiple of 8!
  200. sz = (sz + 8) & ~7;
  201. if (sz > 512 && !IsPowerOfTwo(sz))
  202. {
  203. sz = NextPowerOfTwo(sz)/2;
  204. }
  205. sz = Clamp<unsigned>(sz, 32, GlobalGlowSettings.lightmapSize_);
  206. return sz;
  207. }
  208. void BakeMesh::Preprocess()
  209. {
  210. RTCScene scene = sceneBaker_->GetEmbreeScene()->GetRTCScene();
  211. if (staticModel_ && staticModel_->GetZone())
  212. {
  213. ambientColor_ = staticModel_->GetZone()->GetAmbientColor();
  214. }
  215. if (staticModel_ && staticModel_->GetCastShadows())
  216. {
  217. // Create the embree mesh
  218. embreeGeomID_ = rtcNewTriangleMesh(scene, RTC_GEOMETRY_STATIC, numTriangles_, numVertices_);
  219. rtcSetUserData(scene, embreeGeomID_, this);
  220. rtcSetOcclusionFilterFunction(scene, embreeGeomID_, OcclusionFilter);
  221. rtcSetIntersectionFilterFunction(scene, embreeGeomID_, IntersectFilter);
  222. // Populate vertices
  223. float* vertices = (float*) rtcMapBuffer(scene, embreeGeomID_, RTC_VERTEX_BUFFER);
  224. MMVertex* vIn = &vertices_[0];
  225. for (unsigned i = 0; i < numVertices_; i++, vIn++)
  226. {
  227. *vertices++ = vIn->position_.x_;
  228. *vertices++ = vIn->position_.y_;
  229. *vertices++ = vIn->position_.z_;
  230. // Note that RTC_VERTEX_BUFFER is 16 byte aligned, thus extra component
  231. // which isn't used, though we'll initialize it
  232. *vertices++ = 0.0f;
  233. }
  234. rtcUnmapBuffer(scene, embreeGeomID_, RTC_VERTEX_BUFFER);
  235. uint32_t* triangles = (uint32_t*) rtcMapBuffer(scene, embreeGeomID_, RTC_INDEX_BUFFER);
  236. for (size_t i = 0; i < numTriangles_; i++)
  237. {
  238. MMTriangle* tri = &triangles_[i];
  239. *triangles++ = tri->indices_[0];
  240. *triangles++ = tri->indices_[1];
  241. *triangles++ = tri->indices_[2];
  242. }
  243. rtcUnmapBuffer(scene, embreeGeomID_, RTC_INDEX_BUFFER);
  244. sceneBaker_->GetEmbreeScene()->RegisterBakeMesh(embreeGeomID_, this);
  245. }
  246. float lmScale = staticModel_->GetLightmapScale();
  247. // if we aren't lightmapped, we just contribute to occlusion
  248. if (!GetLightmap() || lmScale <= 0.0f)
  249. return;
  250. unsigned lmSize = staticModel_->GetLightmapSize();
  251. if (!lmSize)
  252. {
  253. float totalarea = 0.0f;
  254. for (unsigned i = 0; i < numTriangles_; i++)
  255. {
  256. MMTriangle* tri = &triangles_[i];
  257. MMVertex* v0 = &vertices_[tri->indices_[0]];
  258. MMVertex* v1 = &vertices_[tri->indices_[1]];
  259. MMVertex* v2 = &vertices_[tri->indices_[2]];
  260. totalarea += AreaOfTriangle(v0->position_,
  261. v1->position_,
  262. v2->position_);
  263. }
  264. totalarea = Clamp<float>(totalarea, 1, 64.0f);
  265. lmSize = CalcLightMapSize(totalarea * 64.0f * lmScale * GlobalGlowSettings.lexelDensity_ * GlobalGlowSettings.sceneLexelDensityScale_);
  266. }
  267. if (lmSize < 32)
  268. lmSize = 32;
  269. if (lmSize > 2048)
  270. lmSize = 2048;
  271. radianceWidth_ = lmSize;
  272. radianceHeight_ = lmSize;
  273. // init radiance
  274. radiance_ = new Vector3[radianceWidth_ * radianceHeight_];
  275. radianceTriIndices_ = new int[radianceWidth_ * radianceHeight_];
  276. radiancePassAccept_ = new bool[radianceWidth_ * radianceHeight_];
  277. Vector3 v(-1, -1, -1);
  278. for (unsigned i = 0; i < radianceWidth_ * radianceHeight_; i++)
  279. {
  280. radiance_[i] = v;
  281. radianceTriIndices_[i] = -1;
  282. radiancePassAccept_[i] = false;
  283. }
  284. // If GI is enabled, setup bounce metrics
  285. if (GlobalGlowSettings.giEnabled_)
  286. {
  287. // granularity setting?
  288. int pwidth = Min<int>(32, radianceWidth_ / 4);
  289. int pheight = Min<int>(32, radianceHeight_ / 4);
  290. photonMap_ = new PhotonMap(this, pwidth, pheight);
  291. }
  292. }
  293. bool BakeMesh::SetStaticModel(StaticModel* staticModel)
  294. {
  295. if (!staticModel || !staticModel->GetNode())
  296. return false;
  297. staticModel_ = staticModel;
  298. node_ = staticModel_->GetNode();
  299. bakeModel_ = GetSubsystem<BakeModelCache>()->GetBakeModel(staticModel_->GetModel());
  300. if (bakeModel_.Null())
  301. {
  302. return false;
  303. }
  304. ModelPacker* modelPacker = bakeModel_->GetModelPacker();
  305. if (modelPacker->lodLevels_.Size() < 1)
  306. {
  307. return false;
  308. }
  309. MPLODLevel* lodLevel = modelPacker->lodLevels_[0];
  310. // LOD must have LM coords
  311. if (!lodLevel->HasElement(TYPE_VECTOR2, SEM_TEXCOORD, 1))
  312. {
  313. return false;
  314. }
  315. // materials
  316. if (staticModel_->GetNumGeometries() != lodLevel->mpGeometry_.Size())
  317. {
  318. ATOMIC_LOGERROR("BakeMesh::Preprocess() - Geometry mismatch");
  319. return false;
  320. }
  321. for (unsigned i = 0; i < staticModel_->GetNumGeometries(); i++)
  322. {
  323. BakeMaterial* bakeMaterial = GetSubsystem<BakeMaterialCache>()->GetBakeMaterial(staticModel_->GetMaterial(i));
  324. bakeMaterials_.Push(bakeMaterial);
  325. }
  326. // allocate
  327. numVertices_ = 0;
  328. unsigned totalIndices = 0;
  329. lodLevel->GetTotalCounts(numVertices_, totalIndices);
  330. if (!numVertices_ || ! totalIndices)
  331. {
  332. return false;
  333. }
  334. numTriangles_ = totalIndices/3;
  335. vertices_ = new MMVertex[numVertices_];
  336. triangles_ = new MMTriangle[numTriangles_];
  337. MMVertex* vOut = &vertices_[0];
  338. MMTriangle* tri = &triangles_[0];
  339. unsigned vertexStart = 0;
  340. unsigned indexStart = 0;
  341. const Matrix3x4& wtransform = node_->GetWorldTransform();
  342. for (unsigned i = 0; i < lodLevel->mpGeometry_.Size(); i++)
  343. {
  344. MPGeometry* mpGeo = lodLevel->mpGeometry_[i];
  345. // Setup Vertices
  346. MPVertex* vIn = &mpGeo->vertices_[0];
  347. for (unsigned j = 0; j < mpGeo->vertices_.Size(); j++)
  348. {
  349. vOut->position_ = wtransform * vIn->position_;
  350. vOut->normal_ = wtransform.Rotation() * vIn->normal_;
  351. vOut->uv0_ = vIn->uv0_;
  352. vOut->uv1_ = vIn->uv1_;
  353. boundingBox_.Merge(vOut->position_);
  354. vOut++;
  355. vIn++;
  356. }
  357. // Setup Triangles
  358. for (unsigned j = 0; j < mpGeo->numIndices_; j+=3, tri++)
  359. {
  360. tri->materialIndex_ = i;
  361. tri->indices_[0] = mpGeo->indices_[j] + vertexStart;
  362. tri->indices_[1] = mpGeo->indices_[j + 1] + vertexStart;
  363. tri->indices_[2] = mpGeo->indices_[j + 2] + vertexStart;
  364. tri->normal_ = vertices_[tri->indices_[0]].normal_;
  365. tri->normal_ += vertices_[tri->indices_[1]].normal_;
  366. tri->normal_ += vertices_[tri->indices_[2]].normal_;
  367. tri->normal_ /= 3.0f;
  368. tri->normal_.Normalize();
  369. }
  370. indexStart += mpGeo->numIndices_;
  371. vertexStart += mpGeo->vertices_.Size();
  372. }
  373. return true;
  374. }
  375. void BakeMesh::GetST(int triIndex, int channel, const Vector3& barycentric, Vector2& st) const
  376. {
  377. if (triIndex < 0 || triIndex >= numTriangles_)
  378. return;
  379. const MMTriangle* tri = &triangles_[triIndex];
  380. const Vector2& st0 = channel == 0 ? vertices_[tri->indices_[0]].uv0_ : vertices_[tri->indices_[0]].uv1_;
  381. const Vector2& st1 = channel == 0 ? vertices_[tri->indices_[1]].uv0_ : vertices_[tri->indices_[1]].uv1_;
  382. const Vector2& st2 = channel == 0 ? vertices_[tri->indices_[2]].uv0_ : vertices_[tri->indices_[2]].uv1_;
  383. st = barycentric.z_*st0 + barycentric.x_*st1 + barycentric.y_*st2;
  384. }
  385. bool BakeMesh::GetUV0Color(int triIndex, const Vector3& barycentric, Color& colorOut) const
  386. {
  387. colorOut = Color::BLACK;
  388. if (triIndex < 0 || triIndex >= numTriangles_)
  389. return false;
  390. const MMTriangle* tri = &triangles_[triIndex];
  391. const BakeMaterial* material = bakeMaterials_[tri->materialIndex_];
  392. const Image* diffuse = material->GetDiffuseTexture();
  393. if (!diffuse)
  394. {
  395. return false;
  396. }
  397. Vector2 st;
  398. GetST(triIndex, 0, barycentric, st);
  399. int x = diffuse->GetWidth() * st.x_;
  400. int y = diffuse->GetHeight() * st.y_;
  401. if (x < 0)
  402. x = diffuse->GetWidth() + x;
  403. if (y < 0)
  404. y = diffuse->GetWidth() + y;
  405. colorOut = diffuse->GetPixel(x, y);
  406. return true;
  407. }
  408. void BakeMesh::IntersectFilter(void* ptr, RTCRay& ray)
  409. {
  410. CommonFilter(static_cast<BakeMesh*>(ptr), ray);
  411. }
  412. void BakeMesh::OcclusionFilter(void* ptr, RTCRay& ray)
  413. {
  414. CommonFilter(static_cast<BakeMesh*>(ptr), ray);
  415. }
  416. bool BakeMesh::CommonFilter(const BakeMesh* bakeMesh, RTCRay& ray)
  417. {
  418. if (ray.primID >= (unsigned) bakeMesh->numTriangles_)
  419. return false;
  420. const MMTriangle* tri = &bakeMesh->triangles_[ray.primID];
  421. const BakeMaterial* material = bakeMesh->bakeMaterials_[tri->materialIndex_];
  422. if (!material)
  423. return false;
  424. if (!material->GetOcclusionMasked())
  425. return false;
  426. Color color;
  427. if (bakeMesh->GetUV0Color(ray.primID, Vector3(ray.u, ray.v, 1.0f-ray.u-ray.v), color))
  428. {
  429. if (color.a_ < 0.5f)
  430. {
  431. ray.geomID = RTC_INVALID_GEOMETRY_ID;
  432. return true;
  433. }
  434. }
  435. return false;
  436. }
  437. }