diff options
author | Jon Bergli Heier <snakebite@jvnv.net> | 2011-04-02 15:52:24 +0200 |
---|---|---|
committer | Jon Bergli Heier <snakebite@jvnv.net> | 2011-04-02 15:52:24 +0200 |
commit | fe2df4b280ecd8417cc267b8fc05ec050054ec4c (patch) | |
tree | 92500ef700f14c6bd0ca0840c9c98d3b20e72415 | |
parent | e172cde8c082fa3e338b3eb11079b36952874936 (diff) |
Finished terrain lighting.
-rw-r--r-- | main.cpp | 2 | ||||
-rw-r--r-- | quadtree.cpp | 217 | ||||
-rw-r--r-- | quadtree.h | 9 | ||||
-rw-r--r-- | terrain_fragment.glsl | 36 | ||||
-rw-r--r-- | terrain_vertex.glsl | 7 |
5 files changed, 198 insertions, 73 deletions
@@ -213,7 +213,7 @@ int main(int argc, char **argv) { break; case SDLK_KP_MINUS: case SDLK_MINUS: - if(level > 0) { + if(level > 1) { qt->create_nodes(--level); } break; 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 <GL/gl.h> -#include <iostream> #include <cmath> #include <queue> @@ -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<Quadtree::QuadNode*> 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; +} + @@ -1,6 +1,8 @@ #ifndef QUADTREE_H #define QUADTREE_H +#include "vector.h" + class Quadtree { public: struct QuadNode { @@ -21,6 +23,7 @@ class Quadtree { void draw(); void draw_grid(); float get_height(float px, float py); + Vector3 get_normal(int index); }; float *heights; @@ -36,7 +39,11 @@ class Quadtree { void create_nodes(int levels); unsigned int count_nodes(); void make_vbo(); - QuadNode *find(float x, float y, int leve = -1l); + QuadNode *find(float x, float y, int level = -1); + QuadNode *get_left(QuadNode *node); + QuadNode *get_right(QuadNode *node); + QuadNode *get_up(QuadNode *node); + QuadNode *get_down(QuadNode *node); }; #endif diff --git a/terrain_fragment.glsl b/terrain_fragment.glsl index 9c354c5..774bfd3 100644 --- a/terrain_fragment.glsl +++ b/terrain_fragment.glsl @@ -1,43 +1,11 @@ -varying vec3 normal, light_pos, V, N; -varying vec4 diffuse, ambient; +varying vec3 normal, light_pos; uniform sampler2D tex; void main() { - //gl_FragColor = gl_Color * diffuse_value; - //vec4 color = ambient; - //vec3 n = normalize(normal); - /*vec3 n = normal; - vec3 hv; - float dotL = max(dot(n, vec3(0, 1, 0)), 0.0); - color += diffuse * dotL; - hv = normalize(halfvector); - float dotHV = max(dot(n, hv), 0.0);*/ - //color += gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(dotHV, gl_FrontMaterial.shininess); - vec3 n = normalize(normal); - - float NdotL = max(dot(light_pos, n), 0.0); float diffuse = max(dot(n, light_pos), 0.0); - - gl_FragColor = vec4(n, 0.0); - - //gl_FragColor = texture2D(tex, gl_TexCoord[0].st) /* diffuse_value*/ * diffuse; - //gl_FragColor = gl_Color * diffuse; - - //gl_FragColor = NdotL * diffuse + ambient; - - return; - - vec3 L = normalize(light_pos - V); - vec3 E = normalize(-V); - vec3 R = normalize(-reflect(L, N)); - - vec4 Iamb = gl_FrontLightProduct[0].ambient; - vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N, L), 0.0); - vec4 Ispec = gl_FrontLightProduct[0].specular * pow(max(dot(R, E), 0.0), 0.3 * gl_FrontMaterial.shininess); - - gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec; + gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * diffuse; } /* vim: set syn=glsl: */ diff --git a/terrain_vertex.glsl b/terrain_vertex.glsl index 25b0c25..8bb21d0 100644 --- a/terrain_vertex.glsl +++ b/terrain_vertex.glsl @@ -2,16 +2,9 @@ varying vec3 normal, light_pos, V, N; varying vec4 diffuse, ambient; void main() { - V = vec3(gl_ModelViewMatrix * gl_Vertex); - N = normalize(gl_NormalMatrix * gl_Normal); - normal = gl_Normal; light_pos = vec3(0, 1, 0); - diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse; - ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient; - - gl_FrontColor = gl_Color; gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } |