NormalMapGenerator.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include "NormalMapGenerator.h"
  2. #include "Image.h"
  3. #include "Base.h"
  4. namespace gameplay
  5. {
  6. NormalMapGenerator::NormalMapGenerator(const char* inputFile, const char* outputFile, int resolutionX, int resolutionY, const Vector3& worldSize)
  7. : _inputFile(inputFile), _outputFile(outputFile), _resolutionX(resolutionX), _resolutionY(resolutionY), _worldSize(worldSize)
  8. {
  9. }
  10. NormalMapGenerator::~NormalMapGenerator()
  11. {
  12. }
  13. bool equalsIgnoreCase(const std::string& s1, const std::string& s2)
  14. {
  15. size_t l1 = s1.size();
  16. size_t l2 = s2.size();
  17. if (l1 != l2)
  18. return false;
  19. for (size_t i = 0; i < l1; ++i)
  20. {
  21. if (tolower(s1[i]) != tolower(s2[i]))
  22. return false;
  23. }
  24. return true;
  25. }
  26. float getHeight(float* heights, int width, int height, int x, int y)
  27. {
  28. if (x < 0)
  29. x = 0;
  30. else if (x >= width)
  31. x = width-1;
  32. if (y < 0)
  33. y = 0;
  34. else if (y >= height)
  35. y = height-1;
  36. return heights[y*width+x];
  37. }
  38. void calculateNormal(
  39. float x1, float y1, float z1,
  40. float x2, float y2, float z2,
  41. float x3, float y3, float z3,
  42. Vector3* normal)
  43. {
  44. Vector3 E(x1, y1, z1);
  45. Vector3 F(x2, y2, z2);
  46. Vector3 G(x3, y3, z3);
  47. Vector3 P, Q;
  48. Vector3::subtract(F, E, &P);
  49. Vector3::subtract(G, E, &Q);
  50. Vector3::cross(Q, P, normal);
  51. }
  52. float normalizedHeightPacked(float r, float g, float b)
  53. {
  54. // This formula is intended for 24-bit packed heightmap images (that are generated
  55. // with gameplay-encoder. However, it is also compatible with normal grayscale
  56. // heightmap images, with an error of approximately 0.4%. This can be seen by
  57. // setting r=g=b=x and comparing the grayscale height expression to the packed
  58. // height expression: the error is 2^-8 + 2^-16 which is just under 0.4%.
  59. return (256.0f*r + g + 0.00390625f*b) / 65536.0f;
  60. }
  61. void NormalMapGenerator::generate()
  62. {
  63. // Load the input heightmap
  64. float* heights = NULL;
  65. size_t pos = _inputFile.find_last_of('.');
  66. std::string ext = pos == std::string::npos ? "" : _inputFile.substr(pos, _inputFile.size()-pos);
  67. if (equalsIgnoreCase(ext, ".png"))
  68. {
  69. // Load heights from PNG image
  70. Image* image = Image::create(_inputFile.c_str());
  71. if (image == NULL)
  72. {
  73. LOG(1, "Failed to load input heightmap PNG: %s.\n", _inputFile.c_str());
  74. return;
  75. }
  76. _resolutionX = image->getWidth();
  77. _resolutionY = image->getHeight();
  78. int size = _resolutionX * _resolutionY;
  79. heights = new float[size];
  80. unsigned char* data = (unsigned char*)image->getData();
  81. for (int i = 0; i < size; ++i)
  82. {
  83. switch (image->getFormat())
  84. {
  85. case Image::LUMINANCE:
  86. heights[i] = data[i] / 255.0f;
  87. break;
  88. case Image::RGB:
  89. case Image::RGBA:
  90. {
  91. int pos = i * image->getBpp();
  92. heights[i] = normalizedHeightPacked(data[pos], data[pos+1], data[pos+2]);
  93. }
  94. break;
  95. default:
  96. heights[i] = 0.0f;
  97. break;
  98. }
  99. heights[i] = heights[i] * _worldSize.y;
  100. }
  101. SAFE_DELETE(image);
  102. }
  103. else if (equalsIgnoreCase(ext, ".raw"))
  104. {
  105. // Load heights from RAW 8 or 16-bit file
  106. if (_resolutionX <= 0 || _resolutionY <= 0)
  107. {
  108. LOG(1, "Missing resolution argument - must be explicitly specified for RAW heightmap files: %s.\n", _inputFile.c_str());
  109. return;
  110. }
  111. // Read all data from file
  112. FILE* fp = fopen(_inputFile.c_str(), "rb");
  113. if (fp == NULL)
  114. {
  115. LOG(1, "Failed to open input file: %s.\n", _inputFile.c_str());
  116. return;
  117. }
  118. fseek(fp, 0, SEEK_END);
  119. long fileSize = ftell(fp);
  120. fseek(fp, 0, SEEK_SET);
  121. unsigned char* data = new unsigned char[fileSize];
  122. if (fread(data, 1, fileSize, fp) != (size_t)fileSize)
  123. {
  124. fclose(fp);
  125. delete[] data;
  126. LOG(1, "Failed to read bytes from input file: %s.\n", _inputFile.c_str());
  127. return;
  128. }
  129. fclose(fp);
  130. // Determine if the RAW file is 8-bit or 16-bit based on file size.
  131. int bits = (fileSize / (_resolutionX * _resolutionY)) * 8;
  132. if (bits != 8 && bits != 16)
  133. {
  134. LOG(1, "Invalid RAW file - must be 8-bit or 16-bit, but found neither: %s.", _inputFile.c_str());
  135. delete[] data;
  136. return;
  137. }
  138. int size = _resolutionX * _resolutionY;
  139. heights = new float[size];
  140. if (bits == 16)
  141. {
  142. // 16-bit (0-65535)
  143. int idx;
  144. for (unsigned int y = 0, i = 0; y < (unsigned int)_resolutionY; ++y)
  145. {
  146. for (unsigned int x = 0; x < (unsigned int)_resolutionX; ++x, ++i)
  147. {
  148. idx = (y * _resolutionX + x) << 1;
  149. heights[i] = ((data[idx] | (int)data[idx+1] << 8) / 65535.0f) * _worldSize.y;
  150. }
  151. }
  152. }
  153. else
  154. {
  155. // 8-bit (0-255)
  156. for (unsigned int y = 0, i = 0; y < (unsigned int)_resolutionY; ++y)
  157. {
  158. for (unsigned int x = 0; x < (unsigned int)_resolutionX; ++x, ++i)
  159. {
  160. heights[i] = (data[y * _resolutionX + x] / 255.0f) * _worldSize.y;
  161. }
  162. }
  163. }
  164. delete[] data;
  165. }
  166. else
  167. {
  168. LOG(1, "Unsupported input heightmap file (must be a valid PNG or RAW file: %s.\n", _inputFile.c_str());
  169. return;
  170. }
  171. ///////////////////////////////////////////////////////////////////////////////////////////////
  172. //
  173. // NOTE: This method assumes the heightmap geometry is generated as follows.
  174. //
  175. // -----------
  176. // | / | / | / |
  177. // |-----------|
  178. // | / | / | / |
  179. // |-----------|
  180. // | / | / | / |
  181. // -----------
  182. //
  183. ///////////////////////////////////////////////////////////////////////////////////////////////
  184. struct NormalPixel
  185. {
  186. unsigned char r, g, b;
  187. };
  188. NormalPixel* normalPixels = new NormalPixel[_resolutionX * _resolutionY];
  189. struct Face
  190. {
  191. Vector3 normal1;
  192. Vector3 normal2;
  193. };
  194. int progressMax = (_resolutionX-1) * (_resolutionY-1) + _resolutionX * _resolutionY;
  195. int progress = 0;
  196. Vector2 scale(_worldSize.x / (_resolutionX-1), _worldSize.z / (_resolutionY-1));
  197. // First calculate all face normals for the heightmap
  198. LOG(1, "Calculating normals... 0%%");
  199. Face* faceNormals = new Face[(_resolutionX - 1) * (_resolutionY - 1)];
  200. Vector3 v1, v2;
  201. for (int z = 0; z < _resolutionY-1; z++)
  202. {
  203. for (int x = 0; x < _resolutionX-1; x++)
  204. {
  205. float topLeftHeight = getHeight(heights, _resolutionX, _resolutionY, x, z);
  206. float bottomLeftHeight = getHeight(heights, _resolutionX, _resolutionY, x, z + 1);
  207. float bottomRightHeight = getHeight(heights, _resolutionX, _resolutionY, x + 1, z + 1);
  208. float topRightHeight = getHeight(heights, _resolutionX, _resolutionY, x + 1, z);
  209. // Triangle 1
  210. calculateNormal(
  211. (float)x*scale.x, bottomLeftHeight, (float)(z + 1)*scale.y,
  212. (float)x*scale.x, topLeftHeight, (float)z*scale.y,
  213. (float)(x + 1)*scale.x, topRightHeight, (float)z*scale.y,
  214. &faceNormals[z*(_resolutionX-1)+x].normal1);
  215. // Triangle 2
  216. calculateNormal(
  217. (float)x*scale.x, bottomLeftHeight, (float)(z + 1)*scale.y,
  218. (float)(x + 1)*scale.x, topRightHeight, (float)z*scale.y,
  219. (float)(x + 1)*scale.x, bottomRightHeight, (float)(z + 1)*scale.y,
  220. &faceNormals[z*(_resolutionX-1)+x].normal2);
  221. ++progress;
  222. LOG(1, "\rCalculating normals... %d%%", (int)(((float)progress / progressMax) * 100));
  223. }
  224. }
  225. // Free height array
  226. delete[] heights;
  227. heights = NULL;
  228. // Smooth normals by taking an average for each vertex
  229. Vector3 normal;
  230. for (int z = 0; z < _resolutionY; z++)
  231. {
  232. for (int x = 0; x < _resolutionX; x++)
  233. {
  234. // Reset normal sum
  235. normal.set(0, 0, 0);
  236. if (x > 0)
  237. {
  238. if (z > 0)
  239. {
  240. // Top left
  241. normal.add(faceNormals[(z-1)*(_resolutionX-1) + (x-1)].normal2);
  242. }
  243. if (z < (_resolutionY - 1))
  244. {
  245. // Bottom left
  246. normal.add(faceNormals[z*(_resolutionX-1) + (x - 1)].normal1);
  247. normal.add(faceNormals[z*(_resolutionX-1) + (x - 1)].normal2);
  248. }
  249. }
  250. if (x < (_resolutionX - 1))
  251. {
  252. if (z > 0)
  253. {
  254. // Top right
  255. normal.add(faceNormals[(z-1)*(_resolutionX-1) + x].normal1);
  256. normal.add(faceNormals[(z-1)*(_resolutionX-1) + x].normal2);
  257. }
  258. if (z < (_resolutionY - 1))
  259. {
  260. // Bottom right
  261. normal.add(faceNormals[z*(_resolutionX-1) + x].normal1);
  262. }
  263. }
  264. // We don't have to worry about weighting the normals by
  265. // the surface area of the triangles since a heightmap
  266. // guarantees that all triangles have the same surface area.
  267. normal.normalize();
  268. // Store this vertex normal
  269. NormalPixel& pixel = normalPixels[z*_resolutionX + x];
  270. pixel.r = (unsigned char)((normal.x + 1.0f) * 0.5f * 255.0f);
  271. pixel.g = (unsigned char)((normal.y + 1.0f) * 0.5f * 255.0f);
  272. pixel.b = (unsigned char)((normal.z + 1.0f) * 0.5f * 255.0f);
  273. ++progress;
  274. LOG(1, "\rCalculating normals... %d%%", (int)(((float)progress / progressMax) * 100));
  275. }
  276. }
  277. LOG(1, "\rCalculating normals... Done.\n");
  278. // Create and save an image for the normal map
  279. Image* normalMap = Image::create(Image::RGB, _resolutionX, _resolutionY);
  280. normalMap->setData(normalPixels);
  281. normalMap->save(_outputFile.c_str());
  282. LOG(1, "Normal map saved to '%s'.\n", _outputFile.c_str());
  283. // Free temp data
  284. delete[] normalPixels;
  285. normalPixels = NULL;
  286. }
  287. }