void Terrain::RenewNodes(const vec3& viewpoint, const QuadTree<TerrainNode>::Iterator& node) { //Check if this node must be enabled using morph-factor float sz = static_cast<float>(node.LayerSize()); float l = node.Offset().x / sz, r = (node.Offset().x + 1) / sz; float u = node.Offset().y / sz, d = (node.Offset().y + 1) / sz; vec3 rel_pos = vec3(inverse(GetModelMatrix()) * vec4(viewpoint, 1.0f)); rel_pos.x = ClosestSegmentPoint(rel_pos.x, l, r); rel_pos.y = ClosestSegmentPoint(rel_pos.y, node->heights.x, node->heights.y); rel_pos.z = ClosestSegmentPoint(rel_pos.z, u, d); if (length(rel_pos)*length(rel_pos) / (1.0f + node->heights.y - node->heights.x) / (r - l) / (d - u) > 5.0f || node.Level() == maxLOD) { //This node is probably enabled } else { //This node is not enabled //continue checking its children DisableNodes(node); RenewNodes(viewpoint, node.Child(1)); RenewNodes(viewpoint, node.Child(0)); RenewNodes(viewpoint, node.Child(3)); RenewNodes(viewpoint, node.Child(2)); } }
vec2 Terrain::LoadVertices( const QuadTree<TerrainNode>::Iterator& node, const Image& hmap ) { //Setup vertex data vec2 res = vec2(1.0f, 0.0f); int verticesCount = (lodResolution + 1) * (lodResolution + 1); vector<vec3> vertices(verticesCount), colors(verticesCount); float deltaX = 1.0f / node.LayerSize() / lodResolution; float deltaY = 1.0f / node.LayerSize() / lodResolution; float x = node.OffsetFloat().x; for (int i = 0; i <= lodResolution; i++, x += deltaX) { float y = node.OffsetFloat().y; for (int j = 0; j <= lodResolution; j++, y += deltaY) { float h = hmap[vec2(x, y)].x; res = UniteSegments(res, vec2(h)); vertices[i*lodResolution + i + j] = vec3(x, h, y); colors[i*lodResolution + i + j] = vec3(0.2f, 0.2f + h, 0.4f - h); } } // VAO allocation glGenVertexArrays(1, &node->vaoID); // VAO setup glBindVertexArray(node->vaoID); // VBOs allocation glGenBuffers(2, node->vboID); // VBOs setup // vertices buffer glBindBuffer(GL_ARRAY_BUFFER, node->vboID[0]); glBufferData(GL_ARRAY_BUFFER, vertices.size() * 3 * sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0); glEnableVertexAttribArray(0); // colors buffer glBindBuffer(GL_ARRAY_BUFFER, node->vboID[1]); glBufferData(GL_ARRAY_BUFFER, colors.size() * 3 * sizeof(GLfloat), colors.data(), GL_STATIC_DRAW); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0); glEnableVertexAttribArray(1); // indices buffer glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GetIndicesBufferID()); OPENGL_CHECK_FOR_ERRORS(); // release vertex data vertices.clear(); colors.clear(); if (node.Level() < maxLOD) { for (int i : {0, 1, 2, 3}) res = UniteSegments(res, LoadVertices(node.Add(i), hmap)); } node->heights = res; return res; }