treegen.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #include "treegen.h"
  2. #include <iostream>
  3. #include <vector>
  4. #include <fstream>
  5. #include <string>
  6. #include <glm/glm.hpp>
  7. #include <glm/gtx/rotate_vector.hpp>
  8. #include "vertices.h"
  9. float zeroToOne(bool normalDist = true) {
  10. if (!normalDist) {
  11. return (rand() / static_cast<float>(RAND_MAX));
  12. }
  13. return ( (rand() / static_cast<float>(RAND_MAX))
  14. + (rand() / static_cast<float>(RAND_MAX)) / 2.f);
  15. }
  16. void outputTree(std::string filename) {
  17. //qDebug() << ">>" << filename.c_str();
  18. std::vector<glm::vec3> vertices = {};
  19. fractalTree3d(vertices, glm::vec3(0, 0, 0), glm::vec3(0, 5.f, 0), .2f, 1, 7, 1.5f, 45.f, {}, 6);
  20. outputVertices(vertices, filename);
  21. }
  22. void outputGrass(std::string filename) {
  23. std::vector<glm::vec3> vertices = {};
  24. fractalTree3d(vertices, glm::vec3(0, 0, 0), glm::vec3(0, 5.f, 0), .2f, 1, 7, 1.5f, 45.f, {}, 6);
  25. for (int i = 0; i < 10000; i++) {
  26. glm::vec3 pos = glm::vec3((zeroToOne(false) - .5f) * 10.f, 0, (zeroToOne(false) - .5f) * 10.f);
  27. std::vector<glm::vec3> blade = {};
  28. grassBlade(blade, pos);
  29. appendVertices(vertices, blade);
  30. }
  31. outputVertices(vertices, filename, "grass");
  32. }
  33. void outputForest(std::string filename) {
  34. std::vector<glm::vec3> vertices = {};
  35. float distance = 15.f;
  36. int rows = 3;
  37. float emptyRadius = 30.f;
  38. for (int row = 0; row < rows; row++) {
  39. int cols = (2 * (emptyRadius + distance * (row + 1)) * M_PI) / distance;
  40. for (int col = 0; col < cols; col++) {
  41. //qDebug() << "tree:" << row << col;
  42. float distOffset = zeroToOne() * distance - distance / 2.f;
  43. float rotOffset = zeroToOne() - 1;
  44. glm::vec3 location = rotateVertex(
  45. glm::vec3(emptyRadius + distance * (row + 1) + distOffset, 0, 0),
  46. (rotOffset + col) * 360.f / cols,
  47. glm::vec3(0, 1.f, 0),
  48. glm::vec3(0, 0, 0)
  49. );
  50. fractalTree3d(
  51. vertices,
  52. location,
  53. glm::vec3(0, zeroToOne() * 10.f, 0),
  54. .25f + .15f * (zeroToOne() - .5f),
  55. 1,
  56. 5,
  57. 1.5f * row,
  58. 45.f + (zeroToOne() - 1.f) * 15.f, {}, 4
  59. );
  60. }
  61. }
  62. outputVertices(vertices, filename);
  63. }
  64. void outputVertices(std::vector<glm::vec3> vertices, std::string fileName, std::string color) {
  65. if (fileName.size() == 0) {
  66. std::cout << "mtllib tree.mtl\nusemtl brown\n";
  67. for (int i = 0; i < vertices.size(); i++) {
  68. glm::vec3 vertex = vertices.at(i);
  69. std::cout << "v " << vertex.x << " " << vertex.y << " " << vertex.z << "\n";
  70. if ((i + 1) % 3 == 0) {
  71. std::cout << "f " << (i - 1) << " " << i << " " << (i + 1) << "\n";
  72. }
  73. }
  74. } else {
  75. //qDebug() << "Writing to" << fileName.c_str();
  76. std::ofstream file;
  77. file.open(fileName);
  78. file << "mtllib tree.mtl\nusemtl " << color << "\n";
  79. for (int i = 0; i < vertices.size(); i++) {
  80. glm::vec3 vertex = vertices.at(i);
  81. file << "v " << vertex.x << " " << vertex.y << " " << vertex.z << "\n";
  82. if ((i + 1) % 3 == 0) {
  83. file << "f " << (i - 1) << " " << i << " " << (i + 1) << "\n";
  84. }
  85. }
  86. file.close();
  87. }
  88. }
  89. void connect(std::vector<glm::vec3> &vertices,
  90. std::vector<glm::vec3> &bottomCircle,
  91. std::vector<glm::vec3> &topCircle) {
  92. int edges = bottomCircle.size();
  93. for (int i = 0; i < edges; i++) {
  94. vertices.push_back(topCircle.at(i));
  95. vertices.push_back(bottomCircle.at(i));
  96. vertices.push_back(topCircle.at((i + 1) % (edges)));
  97. vertices.push_back(topCircle.at( (i + 1) % (edges) ));
  98. vertices.push_back(bottomCircle.at(i));
  99. vertices.push_back(bottomCircle.at((i + 1) % (edges) ));
  100. }
  101. }
  102. void grassBlade(std::vector<glm::vec3> &vertices, glm::vec3 origin) {
  103. float rad = .005f;
  104. float height = zeroToOne() * .1f;
  105. std::vector<glm::vec3> base = {
  106. origin + glm::vec3(-rad, 0, rad),
  107. origin + glm::vec3(-rad, 0, -rad),
  108. origin + glm::vec3(rad, 0, -rad),
  109. origin + glm::vec3(rad, 0, rad)
  110. };
  111. std::vector<glm::vec3> top = {
  112. origin + glm::vec3(-rad, height, rad),
  113. origin + glm::vec3(-rad, height, -rad),
  114. origin + glm::vec3(rad, height, -rad),
  115. origin + glm::vec3(rad, height, rad)
  116. };
  117. glm::vec3 pointPoint = origin + glm::vec3(zeroToOne() * height / 2.f, 2 * height, zeroToOne() * height / 2.f);
  118. std::vector<glm::vec3> point = { pointPoint, pointPoint, pointPoint, pointPoint };
  119. connect(vertices, base, top);
  120. connect(vertices, top, point);
  121. }
  122. void fractalTree3d(std::vector<glm::vec3> &vertices, glm::vec3 origin,
  123. glm::vec3 direction, float rad, int n, int max,
  124. float distancePerDiv, float baseAngle,
  125. std::vector<glm::vec3> base, int maxBranches)
  126. {
  127. if (n > max) return;
  128. // Draw the branch
  129. float distance = glm::length(direction);
  130. glm::vec3 a = origin;
  131. glm::vec3 b = origin + direction;
  132. glm::vec3 ab = glm::normalize(direction);
  133. glm::vec3 perp = glm::cross(ab, glm::vec3(0, 0, 1));
  134. glm::vec3 perp2 = glm::cross(perp, ab);
  135. glm::vec3 radX = rad * perp; //glm::vec3(rad, 0, 0);
  136. std::vector<std::vector<glm::vec3>> circles;
  137. float length = glm::length(b - a);
  138. float lengthCount = 0;
  139. int divs = std::max(2, static_cast<int>(length / distancePerDiv));
  140. int edges = 5;
  141. // Split the branch into fragments to draw edges between
  142. for (int div = 0; div < divs + 1; div++) {
  143. if (div == 0 && base.size() == edges) {
  144. circles.push_back(base);
  145. continue;
  146. }
  147. glm::vec3 center = a + div * (length / divs) * ab;
  148. lengthCount += div * (length / divs);
  149. std::vector<glm::vec3> circle = std::vector<glm::vec3>(edges);
  150. for (int i = 0; i < edges; i++) {
  151. float distance;
  152. float degrees;
  153. distance = rad * (2.f - (div / divs) ) * zeroToOne();
  154. if (div > divs - 1) {
  155. if (n == max) {
  156. distance = 0;
  157. } else if (n == 1) {
  158. distance = rad;
  159. }
  160. }
  161. degrees = i * (360.f / edges);
  162. circle.at(i) = (rotateVertex(center + (glm::normalize(radX) * distance), degrees, glm::normalize(a - b), center));
  163. }
  164. circles.push_back(circle);
  165. }
  166. for (int div = 0; div < divs; div++) {
  167. connect(vertices, circles.at(div), circles.at(div + 1));
  168. }
  169. // Recurse
  170. int branches = 2 + (rand() % (maxBranches - 2));
  171. if (maxBranches == 1) branches = 1;
  172. for (int branch = 0; branch < branches; branch++) {
  173. glm::vec3 childDirection = glm::normalize(direction);
  174. childDirection = glm::rotate(childDirection, glm::radians(baseAngle / n), perp);
  175. childDirection = glm::rotate(childDirection, glm::radians(branch * 360.f / branches), ab);
  176. float childDistance = (.5f + .75f*zeroToOne() * distance) / glm::sqrt(n);
  177. fractalTree3d(vertices, b, childDistance * childDirection, rad / n, n + 1, max, distancePerDiv, baseAngle, circles.back());
  178. }
  179. }