summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2011-04-02 15:52:24 +0200
committerJon Bergli Heier <snakebite@jvnv.net>2011-04-02 15:52:24 +0200
commitfe2df4b280ecd8417cc267b8fc05ec050054ec4c (patch)
tree92500ef700f14c6bd0ca0840c9c98d3b20e72415
parente172cde8c082fa3e338b3eb11079b36952874936 (diff)
Finished terrain lighting.
-rw-r--r--main.cpp2
-rw-r--r--quadtree.cpp217
-rw-r--r--quadtree.h9
-rw-r--r--terrain_fragment.glsl36
-rw-r--r--terrain_vertex.glsl7
5 files changed, 198 insertions, 73 deletions
diff --git a/main.cpp b/main.cpp
index cf7c3b9..1d634c2 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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;
+}
+
diff --git a/quadtree.h b/quadtree.h
index 923a49f..a0e5254 100644
--- a/quadtree.h
+++ b/quadtree.h
@@ -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;
}