From fe2df4b280ecd8417cc267b8fc05ec050054ec4c Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Sat, 2 Apr 2011 15:52:24 +0200 Subject: Finished terrain lighting. --- quadtree.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 187 insertions(+), 30 deletions(-) (limited to 'quadtree.cpp') diff --git a/quadtree.cpp b/quadtree.cpp index 581f92e..f109f63 100644 --- a/quadtree.cpp +++ b/quadtree.cpp @@ -7,7 +7,6 @@ #define GL_GLEXT_PROTOTYPES #include -#include #include #include @@ -77,6 +76,11 @@ void Quadtree::QuadNode::fill() { vertex_array[12] = x + width; vertex_array[13] = tree->heights[(int)floorf((x + width)*tree->height + y)]; vertex_array[14] = y; + + /* midpoint is average of corner heights when width == 1 */ + if(width == 1) { + vertex_array[1] = (vertex_array[4] + vertex_array[7] + vertex_array[10] + vertex_array[13])/4; + } } void Quadtree::QuadNode::subdivide(bool leaf) { @@ -193,6 +197,39 @@ float Quadtree::QuadNode::get_height(float px, float py) { return l1 * a.y + l2 * b.y + l3 * c.y; } +Vector3 Quadtree::QuadNode::get_normal(int index) { + Vector3 a(vertex_array[0], vertex_array[1], vertex_array[2]); + int bi, ci; + switch(index) { + // right + case 0: + bi = 1*3; + ci = 2*3; + break; + // up + case 1: + bi = 2*3; + ci = 3*3; + break; + // left + case 2: + bi = 3*3; + ci = 4*3; + break; + // down + case 3: + bi = 4*3; + ci = 1*3; + break; + } + Vector3 b = Vector3(vertex_array[bi], vertex_array[bi+1], vertex_array[bi+2]); + Vector3 c = Vector3(vertex_array[ci], vertex_array[ci+1], vertex_array[ci+2]); + Vector3 U = c - a; + Vector3 V = b - a; + Vector3 N(V.cross(U)); + return N /= N.length(); +} + void Quadtree::create_nodes(int levels) { if(root) delete root; @@ -255,30 +292,25 @@ void Quadtree::make_vbo() { const size_t tex_coord_chunk_size = sizeof(float)*2*12; const size_t tex_coords_size = tex_coord_chunk_size*nodes; - if(vertices_size + normals_size + tex_coords_size > 100*1024*1024) { - std::cerr << ">100 MB" << std::endl; - } - glBufferData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coords_size, NULL, GL_DYNAMIC_DRAW); std::queue q; q.push(root); - unsigned int offset = 0; vertices = nodes*12; unsigned int index = 0; while(!q.empty()) { - Quadtree::QuadNode* n = q.front(); + Quadtree::QuadNode* node = q.front(); q.pop(); - if(!n->vertex_array) { + if(!node->vertex_array) { for(int j = 0; j < 4; j++) - q.push(n->children[j]); + q.push(node->children[j]); continue; } - int size = 12*3*sizeof(float); float v[3*12]; - v[0] = n->vertex_array[0]; - v[1] = n->vertex_array[1]; - v[2] = n->vertex_array[2]; + float n[3*12]; + v[0] = node->vertex_array[0]; + v[1] = node->vertex_array[1]; + v[2] = node->vertex_array[2]; float tex_coords[4][3][2] = { {{.5, .5}, {0, 0}, {0, 1}}, {{.5, .5}, {0, 1}, {1, 1}}, @@ -287,32 +319,128 @@ void Quadtree::make_vbo() { }; for(int i = 0; i < 4; i++) { for(int j = 0; j < 3; j++) { - tex_coords[i][j][0] *= n->width; - tex_coords[i][j][1] *= n->height; + tex_coords[i][j][0] *= node->width; + tex_coords[i][j][1] *= node->height; } - v[3] = n->vertex_array[i*3+3]; - v[4] = n->vertex_array[i*3+4]; - v[5] = n->vertex_array[i*3+5]; + v[3] = node->vertex_array[i*3+3]; + v[4] = node->vertex_array[i*3+4]; + v[5] = node->vertex_array[i*3+5]; - v[6] = n->vertex_array[i == 3 ? 3 : (i*3+6)]; - v[7] = n->vertex_array[i == 3 ? 4 : (i*3+7)]; - v[8] = n->vertex_array[i == 3 ? 5 : (i*3+8)]; + v[6] = node->vertex_array[i == 3 ? 3 : (i*3+6)]; + v[7] = node->vertex_array[i == 3 ? 4 : (i*3+7)]; + v[8] = node->vertex_array[i == 3 ? 5 : (i*3+8)]; glBufferSubData(GL_ARRAY_BUFFER, vertex_chunk_size*index + sizeof(float)*3*3*i, sizeof(float)*3*3, v); + } + + /* interpolate normals per vertex between nodes */ - Vector3 U(v[6]-v[0], v[7]-v[1], v[8]-v[2]); - Vector3 V(v[3]-v[0], v[4]-v[1], v[5]-v[2]); - Vector3 N(V.cross(U)); - float n[3*3]; - n[0] = n[3] = n[6] = N.x; - n[1] = n[4] = n[7] = N.y; - n[2] = n[5] = n[8] = N.z; + QuadNode *left = get_left(node); + QuadNode *right = get_right(node); + QuadNode *up = get_up(node); + QuadNode *down = get_down(node); - glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normal_chunk_size*index + sizeof(float)*3*3*i, sizeof(float)*3*3, n); + // midpoint + { + Vector3 v(node->get_normal(0) + node->get_normal(1) + node->get_normal(2) + node->get_normal(3)); + v /= v.length(); + n[0] = n[9] = n[18] = n[27] = v.x; + n[1] = n[10] = n[19] = n[28] = v.y; + n[2] = n[11] = n[20] = n[29] = v.z; } + + // bottom-left + { + Vector3 v(node->get_normal(3) + node->get_normal(2)); + if(left) { + v += left->get_normal(0); + v += left->get_normal(3); + } + if(down) { + v += down->get_normal(1); + v += down->get_normal(2); + } + if(left && down) { + QuadNode *n = get_left(down); + v += n->get_normal(0); + v += n->get_normal(1); + } + v /= v.length(); + n[24] = n[30] = v.x; + n[25] = n[31] = v.y; + n[26] = n[32] = v.z; + } + + // bottom-right + { + Vector3 v(node->get_normal(0) + node->get_normal(3)); + if(right) { + v += right->get_normal(2); + v += right->get_normal(3); + } + if(down) { + v += down->get_normal(1); + v += down->get_normal(0); + } + if(down && right) { + QuadNode *n = get_down(right); + v += n->get_normal(1); + v += n->get_normal(2); + } + v /= v.length(); + n[3] = n[33] = v.x; + n[4] = n[34] = v.y; + n[5] = n[35] = v.z; + } + + // top-right + { + Vector3 v(node->get_normal(0) + node->get_normal(1)); + if(right) { + v += right->get_normal(1); + v += right->get_normal(2); + } + if(up) { + v += up->get_normal(0); + v += up->get_normal(3); + } + if(up && right) { + QuadNode *n = get_right(up); + v += n->get_normal(2); + v += n->get_normal(3); + } + v /= v.length(); + n[6] = n[12] = v.x; + n[7] = n[13] = v.y; + n[8] = n[14] = v.z; + } + + // top-left + { + Vector3 v(node->get_normal(1) + node->get_normal(2)); + if(up) { + v += up->get_normal(3); + v += up->get_normal(2); + } + if(left) { + v += left->get_normal(0); + v += left->get_normal(1); + } + if(left && up) { + QuadNode *n = get_left(up); + v += n->get_normal(0); + v += n->get_normal(3); + } + v /= v.length(); + n[15] = n[21] = v.x; + n[16] = n[22] = v.y; + n[17] = n[23] = v.z; + } + + glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normal_chunk_size*index, normal_chunk_size, n); + glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coord_chunk_size*index, tex_coord_chunk_size, tex_coords); index++; - offset += size; } } @@ -333,3 +461,32 @@ Quadtree::QuadNode* Quadtree::find(float x, float y, int level) { return node; } + +Quadtree::QuadNode *Quadtree::get_left(Quadtree::QuadNode *node) { + QuadNode *n = find(node->x + node->width*1.5, node->y + node->height / 2); + if(n == node) + return NULL; + return n; +} + +Quadtree::QuadNode *Quadtree::get_right(Quadtree::QuadNode *node) { + QuadNode *n = find(node->x - node->width/2, node->y + node->height / 2); + if(n == node) + return NULL; + return n; +} + +Quadtree::QuadNode *Quadtree::get_up(Quadtree::QuadNode *node) { + QuadNode *n = find(node->x + node->width/2, node->y + node->height*1.5); + if(n == node) + return NULL; + return n; +} + +Quadtree::QuadNode *Quadtree::get_down(Quadtree::QuadNode *node) { + QuadNode *n = find(node->x + node->width/2, node->y); + if(n == node) + return NULL; + return n; +} + -- cgit v1.2.3