From e172cde8c082fa3e338b3eb11079b36952874936 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Fri, 1 Apr 2011 23:07:56 +0200 Subject: Terrain shader lighting - work in progress. --- main.cpp | 48 ++++++++++++++++---------- quadtree.cpp | 4 +++ shader.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ shader.h | 47 ++++++++++++++++++++++++++ terrain_fragment.glsl | 43 +++++++++++++++++++++++ terrain_vertex.glsl | 19 +++++++++++ 6 files changed, 238 insertions(+), 17 deletions(-) create mode 100644 shader.cpp create mode 100644 shader.h create mode 100644 terrain_fragment.glsl create mode 100644 terrain_vertex.glsl diff --git a/main.cpp b/main.cpp index 9f3bf15..cf7c3b9 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,7 @@ #include "scene.h" #include "vector.h" #include "quadtree.h" +#include "shader.h" #include #include @@ -123,6 +124,12 @@ int main(int argc, char **argv) { video::width = 1280; video::height = 720; video::init(); + GLShaderProgram program; + GLVertexShader terrain_vertex("terrain_vertex.glsl"); + GLFragmentShader terrain_fragment("terrain_fragment.glsl"); + program.attach(terrain_vertex); + program.attach(terrain_fragment); + program.link(); font = new FTTextureFont("font.ttf"); font->FaceSize(10); @@ -139,6 +146,7 @@ int main(int argc, char **argv) { Quadtree *qt = new Quadtree(hm->w, hm->h, heightmap, level); //Quadtree qt(qt_size, qt_size, (int)ceil(sqrt(qt_size))); + GLuint grass_texture; { SDL_Surface *surface = IMG_Load("Grass0073_3_S.jpg"); @@ -153,7 +161,7 @@ int main(int argc, char **argv) { glGenTextures(1, &grass_texture); glBindTexture(GL_TEXTURE_2D, grass_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if(image->format->Amask) { //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, image->w, image->h, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); @@ -170,6 +178,7 @@ int main(int argc, char **argv) { SDL_Event event; bool running = true; bool grid = false; + bool gravity = true; SDL_WarpMouse(video::width/2, video::height/2); unsigned int last_time = SDL_GetTicks(); /*boost::timer t; @@ -211,6 +220,9 @@ int main(int argc, char **argv) { case SDLK_SPACE: scene.yvel = .05; break; + case SDLK_h: + gravity = !gravity; + break; default: break; } @@ -271,7 +283,7 @@ int main(int argc, char **argv) { right++; } if(keystate[SDLK_q]) - scene.pos.y -= 0.002*steps; + scene.pos.y -= 0.002*steps*(keystate[SDLK_LSHIFT]?10:1); if(keystate[SDLK_e]) scene.pos.y += 0.002*steps*(keystate[SDLK_LSHIFT]?10:1); if(moved && (forward || right)) @@ -280,27 +292,30 @@ int main(int argc, char **argv) { std::string move_str; Quadtree::QuadNode *node = qt->find(scene.pos.x, scene.pos.z); if(node) { - float y = node->get_height(scene.pos.x, scene.pos.z); - if(scene.pos.y > y && !keystate[SDLK_e]) - scene.yvel -= 9.81 * steps / 85000; - if(scene.yvel < -.5) - scene.yvel = -.5; - scene.pos.y += scene.yvel * steps; - if(scene.pos.y < y) { - scene.pos.y = y; - scene.yvel = 0; + if(gravity) { + float y = node->get_height(scene.pos.x, scene.pos.z); + if(scene.pos.y > y && !keystate[SDLK_e]) + scene.yvel -= 9.81 * steps / 85000; + if(scene.yvel < -.5) + scene.yvel = -.5; + scene.pos.y += scene.yvel * steps; + if(scene.pos.y < y) { + scene.pos.y = y; + scene.yvel = 0; + } } - move_str = (boost::format("%s %.2f,%.2f %dx%d %d") % scene.pos.str() % node->x % node->y % node->width % node->height % node->level).str(); + move_str = (boost::format("%s %.2f,%.2f %.2fx%.2f %d") % scene.pos.str() % node->x % node->y % node->width % node->height % node->level).str(); } scene.lookat(); glEnable(GL_LIGHTING); - //const float light_pos[4] = {50, 20, 50, 1}; - const float light_pos[4] = {0, 1, 0, 0}; + const float light_pos[4] = {50, 100, 50, 1}; + //const float light_pos[4] = {0, 1, 0, 0}; glLightfv(GL_LIGHT0, GL_POSITION, light_pos); if(!grid) { + program.use(); glBindTexture(GL_TEXTURE_2D, grass_texture); glEnable(GL_TEXTURE_2D); glBindBuffer(GL_ARRAY_BUFFER, qt->vbo_object); @@ -314,11 +329,11 @@ int main(int argc, char **argv) { glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisable(GL_TEXTURE_2D); + glUseProgram(0); } else { std::queue q; q.push(qt->root); - glBindTexture(GL_TEXTURE_2D, grass_texture); - glEnable(GL_TEXTURE_2D); while(!q.empty()) { Quadtree::QuadNode *node = q.front(); q.pop(); @@ -330,7 +345,6 @@ int main(int argc, char **argv) { } } - glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); float px, py, pz; diff --git a/quadtree.cpp b/quadtree.cpp index 4b7eb52..581f92e 100644 --- a/quadtree.cpp +++ b/quadtree.cpp @@ -255,6 +255,10 @@ 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; diff --git a/shader.cpp b/shader.cpp new file mode 100644 index 0000000..8d3493e --- /dev/null +++ b/shader.cpp @@ -0,0 +1,94 @@ +#include +#include + +#include + +#include "shader.h" + +inline void gl_check_error(const char *msg) { + GLenum error = glGetError(); + if(error != GL_NO_ERROR) { + throw(std::runtime_error((boost::format("%s:\n%s") % msg % gluErrorString(error)).str())); + } +} + +void GLBaseShader::shader_source(const char *filename) { + std::ifstream inf(filename, std::ios_base::in); + if(!inf.is_open()) { + throw(std::runtime_error((boost::format("Failed to load shader from file %s") % filename).str())); + } + inf.seekg(0, std::ios_base::end); + int length = inf.tellg(); + inf.seekg(0, std::ios_base::beg); + char *buffer = new char[length]; + inf.read(buffer, length); + inf.close(); + + glShaderSource(shader, 1, (const GLchar**)&buffer, &length); + gl_check_error("Failed to set shader source"); + delete[] buffer; + glCompileShader(shader); + int p; + glGetShaderiv(shader, GL_COMPILE_STATUS, &p); + if(p == 0) { + char log[0xffff]; + int size; + glGetShaderInfoLog(shader, 0xffff, &size, (GLchar*)&log); + throw(std::runtime_error((boost::format("Failed to compile shader:\n%s") % log).str())); + } +} + +void GLBaseShader::shader_source(std::string& filename) { + shader_source(filename.c_str()); +} + +GLBaseShader::GLBaseShader(GLenum type) { + shader = glCreateShader(type); +} + +GLBaseShader::~GLBaseShader() { + glDeleteShader(shader); +} + +/** + * GLShaderProgram + */ +GLShaderProgram::GLShaderProgram() { + program = glCreateProgram(); +} + +GLShaderProgram::~GLShaderProgram() { + glDeleteProgram(program); +} + +void GLShaderProgram::attach(GLBaseShader& shader) { + glAttachShader(program, shader.shader); + + gl_check_error("Failed to attach shader to program"); +} + +void GLShaderProgram::detach(GLBaseShader& shader) { + glDetachShader(program, shader.shader); + + gl_check_error("Failed to detach shader from program"); +} + +void GLShaderProgram::link() { + glLinkProgram(program); + gl_check_error("linkage"); + + int p; + glGetProgramiv(program, GL_LINK_STATUS, &p); + if(p == 0) { + char log[0xffff]; + int size; + glGetProgramInfoLog(program, 0xffff, &size, (GLchar*)&log); + throw(std::runtime_error((boost::format("Failed to link program:\n%s") % log).str())); + } +} + +void GLShaderProgram::use() { + glUseProgram(program); + + gl_check_error("Failed to use program"); +} diff --git a/shader.h b/shader.h new file mode 100644 index 0000000..70f2361 --- /dev/null +++ b/shader.h @@ -0,0 +1,47 @@ +#ifndef SHADER_H +#define SHADER_H + +#define GL_GLEXT_PROTOTYPES +#include +#include + +class GLBaseShader { + friend class GLShaderProgram; + + protected: + void shader_source(const char *filename); + void shader_source(std::string& filename); + unsigned int shader; + public: + GLBaseShader(GLenum); + ~GLBaseShader(); +}; + +class GLVertexShader : public GLBaseShader { + public: + GLVertexShader() : GLBaseShader(GL_VERTEX_SHADER) {}; + GLVertexShader(const char *s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); }; + GLVertexShader(std::string& s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); }; +}; + +class GLFragmentShader : public GLBaseShader { + public: + GLFragmentShader() : GLBaseShader(GL_FRAGMENT_SHADER) {}; + GLFragmentShader(const char *s) : GLBaseShader(GL_FRAGMENT_SHADER) { shader_source(s); }; + GLFragmentShader(std::string& s) : GLBaseShader(GL_FRAGMENT_SHADER) { shader_source(s); }; +}; + +class GLShaderProgram { + protected: + unsigned int program; + public: + GLShaderProgram(); + ~GLShaderProgram(); + + void attach(GLBaseShader&); + void detach(GLBaseShader&); + void link(); + void use(); +}; + +#endif diff --git a/terrain_fragment.glsl b/terrain_fragment.glsl new file mode 100644 index 0000000..9c354c5 --- /dev/null +++ b/terrain_fragment.glsl @@ -0,0 +1,43 @@ +varying vec3 normal, light_pos, V, N; +varying vec4 diffuse, ambient; + +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; +} + +/* vim: set syn=glsl: */ diff --git a/terrain_vertex.glsl b/terrain_vertex.glsl new file mode 100644 index 0000000..25b0c25 --- /dev/null +++ b/terrain_vertex.glsl @@ -0,0 +1,19 @@ +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; +} + +/* vim: set syn=glsl: */ -- cgit v1.2.3