BakeLight.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. // Copyright (c) 2014-2017, THUNDERBEAST GAMES LLC All rights reserved
  2. // Copyright 2009-2017 Intel Corporation
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Atomic/IO/Log.h>
  23. #include <Atomic/Graphics/Zone.h>
  24. #include <AtomicGlow/Common/GlowSettings.h>
  25. #include "EmbreeScene.h"
  26. #include "LightRay.h"
  27. #include "BakeLight.h"
  28. #include "BakeMesh.h"
  29. #include "SceneBaker.h"
  30. namespace AtomicGlow
  31. {
  32. const float LIGHT_ANGLE_EPSILON = 0.001f;
  33. // http://www.altdevblogaday.com/2012/05/03/generating-uniformly-distributed-points-on-sphere/
  34. static inline void GetRandomDirection(Vector3& result)
  35. {
  36. float z = 2.0f * rand() / RAND_MAX - 1.0f;
  37. float t = 2.0f * rand() / RAND_MAX * 3.14f;
  38. float r = sqrt(1.0f - z * z);
  39. result.x_ = r * (float) cos(t);
  40. result.y_ = r * (float) sin(t);
  41. result.z_ = z;
  42. }
  43. BakeLight::BakeLight(Context* context, SceneBaker* sceneBaker) : BakeNode(context, sceneBaker),
  44. range_(0.0f)
  45. {
  46. }
  47. BakeLight::~BakeLight()
  48. {
  49. }
  50. // Zone Lights
  51. ZoneBakeLight::ZoneBakeLight(Context* context, SceneBaker* sceneBaker) : BakeLight(context, sceneBaker)
  52. {
  53. }
  54. ZoneBakeLight::~ZoneBakeLight()
  55. {
  56. }
  57. void ZoneBakeLight::Light(LightRay* lightRay)
  58. {
  59. LightRay::SamplePoint& source = lightRay->samplePoint_;
  60. if (source.normal == Vector3::ZERO)
  61. return;
  62. RTCScene scene = sceneBaker_->GetEmbreeScene()->GetRTCScene();
  63. const Color& color = zone_->GetAmbientColor();
  64. Vector3 rad(color.r_, color.g_, color.b_);
  65. if (!GlobalGlowSettings.aoEnabled_)
  66. {
  67. source.bakeMesh->ContributeRadiance(lightRay, rad, GLOW_LIGHTMODE_AMBIENT);
  68. return;
  69. }
  70. // TODO: AO using ray packets/streams
  71. RTCRay& ray = lightRay->rtcRay_;
  72. unsigned nsamples = GlobalGlowSettings.nsamples_;
  73. // this needs to be based on model/scale likely?
  74. float aoDepth = GlobalGlowSettings.aoDepth_;
  75. // smallest percent of ao value to use
  76. float aoMin = GlobalGlowSettings.aoMin_;
  77. // brightness control
  78. float multiply = GlobalGlowSettings.aoMultiply_;
  79. // Shoot rays through the differential hemisphere.
  80. int nhits = 0;
  81. float avgDepth = 0.0f;
  82. for (unsigned nsamp = 0; nsamp < nsamples; nsamp++)
  83. {
  84. Vector3 rayDir;
  85. GetRandomDirection(rayDir);
  86. float dotp = source.normal.x_ * rayDir.x_ +
  87. source.normal.y_ * rayDir.y_ +
  88. source.normal.z_ * rayDir.z_;
  89. if (dotp < 0.1f)
  90. {
  91. continue;
  92. }
  93. float variance = 0.0f;//nsamples <= 32 ? 0.0f : aoDepth * ((float) rand() / (float) RAND_MAX) * 0.25f;
  94. float depth = aoDepth + variance;
  95. lightRay->SetupRay(source.position, rayDir, .001f, depth);
  96. rtcOccluded(scene, ray);
  97. if (ray.geomID != RTC_INVALID_GEOMETRY_ID)
  98. {
  99. avgDepth += Min<float>(ray.tfar, aoDepth);
  100. nhits++;
  101. }
  102. }
  103. if (nhits)// && (nsamples <= 32 ? true : nhits > 4))
  104. {
  105. avgDepth /= float(nhits);
  106. avgDepth /= aoDepth;
  107. avgDepth = Clamp<float>(avgDepth, 0.1f, 1.0f) * 100.0f;
  108. avgDepth *= avgDepth;
  109. float ao = avgDepth / 10000.0f;
  110. ao = aoMin + ao/2.0f;
  111. ao *= multiply;
  112. ao = Clamp<float>(ao, aoMin, 1.0f);
  113. rad *= ao;
  114. }
  115. source.bakeMesh->ContributeRadiance(lightRay, rad, GLOW_LIGHTMODE_AMBIENT);
  116. }
  117. void ZoneBakeLight::SetZone(Zone* zone)
  118. {
  119. node_ = zone->GetNode();
  120. zone_ = zone;
  121. }
  122. // Directional Lights
  123. DirectionalBakeLight::DirectionalBakeLight(Context* context, SceneBaker* sceneBaker) : BakeLight(context, sceneBaker)
  124. {
  125. }
  126. DirectionalBakeLight::~DirectionalBakeLight()
  127. {
  128. }
  129. void DirectionalBakeLight::Light(LightRay* lightRay)
  130. {
  131. RTCScene scene = sceneBaker_->GetEmbreeScene()->GetRTCScene();
  132. LightRay::SamplePoint& source = lightRay->samplePoint_;
  133. RTCRay& ray = lightRay->rtcRay_;
  134. float angle = direction_.DotProduct(source.normal);
  135. if (angle < 0.0f)
  136. return;
  137. lightRay->SetupRay(source.position, direction_);
  138. rtcOccluded(scene, ray);
  139. // obstructed? TODO: glass, etc
  140. if (ray.geomID != RTC_INVALID_GEOMETRY_ID)
  141. return;
  142. Vector3 rad(color_.r_, color_.g_, color_.b_);
  143. rad*=angle;
  144. source.bakeMesh->ContributeRadiance(lightRay, rad);
  145. }
  146. void DirectionalBakeLight::SetLight(Atomic::Light* light)
  147. {
  148. node_ = light->GetNode();
  149. color_ = light->GetColor();
  150. direction_ = -node_->GetWorldDirection();
  151. direction_.Normalize();
  152. }
  153. // Point Lights
  154. PointBakeLight::PointBakeLight(Context* context, SceneBaker* sceneBaker) : BakeLight(context, sceneBaker)
  155. {
  156. }
  157. PointBakeLight::~PointBakeLight()
  158. {
  159. }
  160. void PointBakeLight::Light(LightRay* lightRay)
  161. {
  162. RTCScene scene = sceneBaker_->GetEmbreeScene()->GetRTCScene();
  163. LightRay::SamplePoint& source = lightRay->samplePoint_;
  164. RTCRay& ray = lightRay->rtcRay_;
  165. Vector3 dir = position_ - source.position;
  166. float dist = dir.Length();
  167. if (range_ <= 0.0f || dist >= range_)
  168. return;
  169. dir.Normalize();
  170. float dot = dir.DotProduct(source.normal);
  171. if (dot < 0.0f)
  172. return;
  173. lightRay->SetupRay(source.position, dir, .001f, dist);
  174. rtcOccluded(scene, ray);
  175. // obstructed? TODO: glass, etc
  176. if (ray.geomID != RTC_INVALID_GEOMETRY_ID)
  177. return;
  178. Vector3 rad(color_.r_, color_.g_, color_.b_);
  179. // lightOverBright 1.2 for example will pop light,
  180. // needs to be configurable per light, maybe with brightness modifer
  181. float lightOverBright = 1.0f;
  182. rad *= Max<float> (1.0f - ( dist * lightOverBright / range_), 0.0f);
  183. rad *= dot;
  184. // EXPERIMENTAL: if GI is enabled, dim point light a bit
  185. if (GlobalGlowSettings.giEnabled_)
  186. {
  187. rad *= 0.75f;
  188. }
  189. if (rad.Length() > M_EPSILON)
  190. source.bakeMesh->ContributeRadiance(lightRay, rad);
  191. }
  192. void PointBakeLight::SetLight(Atomic::Light* light)
  193. {
  194. node_ = light->GetNode();
  195. color_ = light->GetColor();
  196. position_ = node_->GetWorldPosition();
  197. range_ = light->GetRange();
  198. }
  199. // Bounce Lights
  200. Mutex BounceBakeLight::sortMutex_;
  201. BounceBakeLight::BounceBakeLight(Context* context, SceneBaker* sceneBaker) : BakeLight(context, sceneBaker)
  202. {
  203. }
  204. BounceBakeLight::~BounceBakeLight()
  205. {
  206. }
  207. static Vector3 compareBouncePoint;
  208. static inline bool CompareBounceSamples(const BounceSample* lhs, const BounceSample* rhs)
  209. {
  210. Vector3 v1 = lhs->position_ - compareBouncePoint;
  211. Vector3 v2 = rhs->position_ - compareBouncePoint;
  212. return v1.LengthSquared() < v2.LengthSquared();
  213. }
  214. void BounceBakeLight::Light(LightRay* lightRay)
  215. {
  216. RTCScene scene = sceneBaker_->GetEmbreeScene()->GetRTCScene();
  217. LightRay::SamplePoint& source = lightRay->samplePoint_;
  218. RTCRay& ray = lightRay->rtcRay_;
  219. const float maxDist = 5.0f;
  220. const float maxDistSq = maxDist * maxDist;
  221. const BounceSample* b;
  222. PODVector<const BounceSample*> samples;
  223. for (int i = 0; i < bounceSamples_.Size(); i++)
  224. {
  225. b = &bounceSamples_[i];
  226. // don't light self
  227. if (source.bakeMesh == bakeMesh_)
  228. {
  229. for (int j = 0; j < GLOW_MAX_BOUNCE_SAMPLE_TRIANGLES; j++)
  230. {
  231. if (b->triIndex_[j] == -1)
  232. break;
  233. if (b->triIndex_[j] == source.triangle)
  234. return;
  235. }
  236. }
  237. Vector3 dir = b->position_ - source.position;
  238. if (dir.LengthSquared() > maxDistSq)
  239. {
  240. continue;
  241. }
  242. dir.Normalize();
  243. if (dir.DotProduct(source.normal) < M_EPSILON)
  244. {
  245. continue;
  246. }
  247. samples.Push(b);
  248. }
  249. if (!samples.Size())
  250. return;
  251. sortMutex_.Acquire();
  252. compareBouncePoint = source.position;
  253. Sort(samples.Begin(), samples.End(), CompareBounceSamples);
  254. sortMutex_.Release();
  255. int bestIndex = -1;
  256. float bestDist = M_INFINITY;
  257. for (unsigned i = 0; i < samples.Size(); i++)
  258. {
  259. b = samples[i];
  260. Vector3 dir = b->position_ - source.position;
  261. float dist = dir.Length();
  262. if (dist < bestDist)
  263. {
  264. dir.Normalize();
  265. lightRay->SetupRay(source.position, dir, 0.01f, dist * 1.01f);
  266. rtcIntersect(scene, ray);
  267. if (ray.geomID != bakeMesh_->GetGeomID())
  268. {
  269. continue;
  270. }
  271. // backface
  272. if ( (ray.Ng[0] * ray.dir[0]) +
  273. (ray.Ng[1] * ray.dir[1]) +
  274. (ray.Ng[2] * ray.dir[2]) < 0.0f)
  275. {
  276. continue;
  277. }
  278. bool found = false;
  279. for (int j = 0; j < GLOW_MAX_BOUNCE_SAMPLE_TRIANGLES; j++)
  280. {
  281. if (b->triIndex_[j] == -1)
  282. break;
  283. if (b->triIndex_[j] == ray.primID)
  284. {
  285. found = true;
  286. break;
  287. }
  288. }
  289. if (!found)
  290. continue;
  291. bestIndex = i;
  292. bestDist = dist;
  293. break;
  294. }
  295. }
  296. if (bestIndex == -1)
  297. return;
  298. b = samples[bestIndex];
  299. // weighted average of src color and radiance for bounce sample
  300. Vector3 rad = b->srcColor_ + (b->radiance_/b->hits_);
  301. rad /= 2.0f;
  302. float d = 1.0f - Clamp<float>(bestDist / maxDist, 0.01f, 1.0f);
  303. rad *= d;
  304. rad *= 0.15f;
  305. if (rad.x_ < 0.0f || rad.y_ < 0.0f || rad.z_ < 0.0f)
  306. {
  307. ATOMIC_LOGWARNING("BounceBakeLight::Light - negative rad factor");
  308. return;
  309. }
  310. source.bakeMesh->ContributeRadiance(lightRay, rad, GLOW_LIGHTMODE_INDIRECT);
  311. }
  312. void BounceBakeLight::SetBounceSamples(const PODVector<BounceSample>& bounceSamples)
  313. {
  314. bounceSamples_ = bounceSamples;
  315. }
  316. void BounceBakeLight::SetBakeMesh(BakeMesh* bakeMesh)
  317. {
  318. bakeMesh_ = bakeMesh;
  319. node_ = bakeMesh->GetNode();
  320. color_ = Color::MAGENTA;
  321. range_ = -1.0f;
  322. position_ = Vector3::ZERO;
  323. }
  324. void BounceBakeLight::SetLight(Atomic::Light* light)
  325. {
  326. node_ = light->GetNode();
  327. color_ = light->GetColor();
  328. position_ = node_->GetWorldPosition();
  329. range_ = light->GetRange();
  330. }
  331. }