RadianceMap.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #include "LightMap.h"
  2. #include "BakeMesh.h"
  3. #include "RadianceMap.h"
  4. namespace AtomicGlow
  5. {
  6. RadianceMap::RadianceMap(Context* context, BakeMesh* bakeMesh) : Object(context),
  7. bakeMesh_(bakeMesh),
  8. packed_(false)
  9. {
  10. int width = bakeMesh->GetRadianceWidth();
  11. int height = bakeMesh->GetRadianceHeight();
  12. image_ = new Image(context_);
  13. image_->SetSize(width, height, 2, 3);
  14. Vector3 rad;
  15. int triIndex;
  16. Color c;
  17. for (unsigned y = 0; y <height; y++)
  18. {
  19. for (unsigned x = 0; x < width; x++)
  20. {
  21. if (!bakeMesh->GetRadiance(x, y, rad, triIndex))
  22. {
  23. image_->SetPixel(x, y, 0, Color::MAGENTA);
  24. image_->SetPixel(x, y, 1, Color::BLACK);
  25. continue;
  26. }
  27. if (rad.Length() > 3.0f)
  28. {
  29. rad.Normalize();
  30. rad *= 3.0f;
  31. }
  32. c.r_ = rad.x_;
  33. c.g_ = rad.y_;
  34. c.b_ = rad.z_;
  35. image_->SetPixel(x, y, c);
  36. // mark as a valid pixel
  37. image_->SetPixel(x, y, 1, Color::RED);
  38. }
  39. }
  40. // blur before fill
  41. Blur();
  42. const int maxDist = 7;
  43. int d = 1;
  44. while (FillInvalidPixels(d) && d <= maxDist)
  45. {
  46. d++;
  47. }
  48. //Downsample();
  49. }
  50. bool RadianceMap::CheckValidPixel(int x, int y, Color &color)
  51. {
  52. if (x < 0 || x >= image_->GetWidth())
  53. return false;
  54. if (y < 0 || y >= image_->GetHeight())
  55. return false;
  56. color = image_->GetPixel(x, y, 1);
  57. if (color == Color::BLACK)
  58. return false;
  59. color = image_->GetPixel(x, y, 0);
  60. return true;
  61. }
  62. bool RadianceMap::FillInvalidPixels(int searchDistance)
  63. {
  64. bool result = false;
  65. PODVector<Vector2> coords;
  66. // left
  67. coords.Push(Vector2(-searchDistance, 0));
  68. // right
  69. coords.Push(Vector2(searchDistance, 0));
  70. // down
  71. coords.Push(Vector2(0, searchDistance));
  72. // up
  73. coords.Push(Vector2(0, -searchDistance));
  74. coords.Push(Vector2(-searchDistance, -searchDistance));
  75. coords.Push(Vector2(searchDistance, searchDistance));
  76. coords.Push(Vector2(-searchDistance, searchDistance));
  77. coords.Push(Vector2(searchDistance, -searchDistance));
  78. int width = image_->GetWidth();
  79. int height = image_->GetHeight();
  80. for (int x = 0; x < width; x++)
  81. {
  82. for (int y = 0; y < height; y++)
  83. {
  84. Color c;
  85. HashMap<int, PODVector<Color>> colors;
  86. if (!CheckValidPixel(x, y , c))
  87. {
  88. // we have an unitialized pixel, search for an initialized neighbor
  89. for (unsigned i = 0; i< coords.Size(); i++)
  90. {
  91. const Vector2& coord = coords[i];
  92. if (CheckValidPixel(x + coord.x_, y + coord.y_, c))
  93. {
  94. Vector3 rad;
  95. int triIndex;
  96. bakeMesh_->GetRadiance(x + coord.x_, y + coord.y_, rad, triIndex);
  97. // triIndex can be -1, for a previously filled pixel
  98. colors[triIndex].Push(c);
  99. }
  100. }
  101. if (colors.Size())
  102. {
  103. result = true;
  104. HashMap<int, PODVector<Color>>::ConstIterator itr = colors.Begin();
  105. int bestTri = -2;
  106. int bestCount = 0;
  107. while (itr != colors.End())
  108. {
  109. // only consider the previous fill colors, if we don't have any
  110. // valid tri colors
  111. if (itr->first_ < 0)
  112. {
  113. itr++;
  114. continue;
  115. }
  116. if (itr->second_.Size() > bestCount)
  117. {
  118. bestCount = itr->second_.Size();
  119. bestTri = itr->first_;
  120. }
  121. itr++;
  122. }
  123. if (bestTri < 0)
  124. {
  125. if (!colors.Contains(-1))
  126. {
  127. // shouldn't happen
  128. continue;
  129. }
  130. // use the previous fill as we don't have a valid tri
  131. bestTri = -1;
  132. }
  133. const PODVector<Color>& triColors = colors[bestTri];
  134. c = Color::BLACK;
  135. for (unsigned i = 0; i < triColors.Size(); i++)
  136. {
  137. c += triColors[i];
  138. }
  139. c.r_ /= triColors.Size();
  140. c.g_ /= triColors.Size();
  141. c.b_ /= triColors.Size();
  142. image_->SetPixel(x, y, c);
  143. image_->SetPixel(x, y, 1, Color::RED);
  144. }
  145. }
  146. }
  147. }
  148. return result;
  149. }
  150. void RadianceMap::Blur()
  151. {
  152. int width = image_->GetWidth();
  153. int height = image_->GetHeight();
  154. SharedPtr<Image> target(new Image(context_));
  155. target->SetSize(width, height, 2, 3);
  156. target->SetData(image_->GetData());
  157. Color color;
  158. float validPixels;
  159. int minK, maxK, minL, maxL;
  160. for (int i = 0; i < width; ++i)
  161. {
  162. for (int j = 0; j < height; ++j)
  163. {
  164. Vector3 rad;
  165. int destTriIndex;
  166. if (!bakeMesh_->GetRadiance(i, j, rad, destTriIndex))
  167. continue;
  168. color = Color::BLACK;
  169. validPixels = 0;
  170. minK = i - 1;
  171. if (minK < 0)
  172. minK = 0;
  173. maxK = i + 1;
  174. if (maxK >= width)
  175. maxK = width - 1;
  176. minL = j - 1;
  177. if (minL < 0)
  178. minL = 0;
  179. maxL = j + 1;
  180. if (maxL >= height)
  181. maxL = height - 1;
  182. for (int k = minK; k <= maxK; ++k)
  183. {
  184. for (int l = minL - 1; l < maxL; ++l)
  185. {
  186. int tindex;
  187. if (!bakeMesh_->GetRadiance(i, j, rad, tindex))
  188. continue;
  189. if (tindex != destTriIndex)
  190. continue;
  191. Color c;
  192. if (!CheckValidPixel(k, l, c))
  193. continue;
  194. color += c;
  195. ++validPixels;
  196. }
  197. }
  198. if (validPixels)
  199. {
  200. color.r_ /= validPixels;
  201. color.g_ /= validPixels;
  202. color.b_ /= validPixels;
  203. target->SetPixel(i, j, color);
  204. }
  205. }
  206. }
  207. image_->SetData(target->GetData());
  208. }
  209. bool RadianceMap::Downsample()
  210. {
  211. // Simple average downsample gives nice results
  212. SharedPtr<Image> tmp(new Image(context_));
  213. tmp->SetSize(image_->GetWidth()/2, image_->GetHeight()/2, 3);
  214. tmp->Clear(Color::BLACK);
  215. for (int y = 0; y < tmp->GetHeight(); y++)
  216. {
  217. for (int x = 0; x < tmp->GetWidth(); x++)
  218. {
  219. int validColors = 0;
  220. Color c = Color::BLACK;
  221. Color tc = image_->GetPixel(x * 2, y * 2);
  222. if (tc != Color::BLACK)
  223. {
  224. c += tc;
  225. validColors++;
  226. }
  227. tc = image_->GetPixel(x * 2 + 1, y * 2);
  228. if (tc != Color::BLACK)
  229. {
  230. c += tc;
  231. validColors++;
  232. }
  233. tc = image_->GetPixel(x * 2, y * 2 + 1);
  234. if (tc != Color::BLACK)
  235. {
  236. c += tc;
  237. validColors++;
  238. }
  239. tc = image_->GetPixel(x * 2 + 1, y * 2 + 1);
  240. if (tc != Color::BLACK)
  241. {
  242. c += tc;
  243. validColors++;
  244. }
  245. if (!validColors)
  246. continue;
  247. c.r_ /= validColors;
  248. c.g_ /= validColors;
  249. c.b_ /= validColors;
  250. c.a_ = 1.0f;
  251. tmp->SetPixel(x, y, c);
  252. }
  253. }
  254. image_->SetSize(tmp->GetWidth(), tmp->GetHeight(), 3);
  255. image_->SetData(tmp->GetData());
  256. return true;
  257. }
  258. RadianceMap::~RadianceMap()
  259. {
  260. }
  261. }