diff options
author | Eric Anholt <eric@anholt.net> | 2009-07-21 13:56:12 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-07-28 13:53:48 -0700 |
commit | bc6d901d45839c5ab1a689c5e3efc44500ce3fb5 (patch) | |
tree | 2d49574fd73b170464438dbb5606a24bc8c1fdca | |
parent | a9c85b079846cb92929c1acbc8577551953aa1e4 (diff) |
Add a bright red ground plane.
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | glass.c | 69 | ||||
-rw-r--r-- | glass.h | 21 | ||||
-rw-r--r-- | ground.c | 154 | ||||
-rw-r--r-- | ground.frag | 125 | ||||
-rw-r--r-- | ground.vert | 28 |
6 files changed, 377 insertions, 21 deletions
diff --git a/Makefile.am b/Makefile.am index 67483dd..e297c3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,5 +9,6 @@ bin_PROGRAMS = glass glass_SOURCES = \ glass.c \ glass.h \ + ground.c \ matrix.c \ load_texture.c @@ -39,8 +39,6 @@ #include "glass.h" -#include <glu3.h> - #include <SDL.h> #define DEFAULT_WIDTH 600 @@ -67,10 +65,7 @@ enum uniform_list { UNIFORM_F0, }; -struct uniform_desc { - const char *name; - GLint location; -} uniforms[] = { +struct uniform_desc uniforms[] = { [UNIFORM_MV] = { "mv" }, [UNIFORM_MVP] = { "mvp" }, [UNIFORM_LIGHT_EYE] = { "light_eye" }, @@ -80,7 +75,14 @@ struct uniform_desc { [UNIFORM_F0] = { "F0" }, }; +struct uniform_desc ground_uniforms[GROUND_UNIFORM_MAX] = { + [GROUND_UNIFORM_MV] = { "mv" }, + [GROUND_UNIFORM_MVP] = { "mvp" }, +}; + + static GLuint glass_prog = 0; +GLuint ground_prog = 0; struct revolved_object ring; GLuint normalmap_tex, heightmap_tex; @@ -89,15 +91,15 @@ static const GLUvec4 x_axis = {{1.0, 0.0, 0.0, 1.0}}; static const GLUvec4 y_axis = {{0.0, 1.0, 0.0, 1.0}}; static const GLUvec4 z_axis = {{0.0, 0.0, 1.0, 1.0}}; -static GLUvec4 eye_world = {{0.0, 0.0, 2.0, 1.0}}; +GLUvec4 eye_world = {{0.0, 0.0, 2.0, 1.0}}; static GLUvec4 eye_center_world = {{0.0, 1.0, 2.0, 1.0}}; static GLUvec4 light_eye; -static GLUmat4 projection; -static GLUmat4 world_to_eye; +GLUmat4 projection; +GLUmat4 world_to_eye; static time_t start_tv_sec = 0; static float start_time, cur_time, last_fps_time = 0; -static int no_multi_draw_arrays; +int no_multi_draw_arrays; static int frames = 0, last_fps_frames = 0; static SDL_Surface *sdl_surf = NULL; static GLboolean done = GL_FALSE; @@ -152,8 +154,6 @@ update_light_position(void) light_eye.values[1] /= light_eye.values[3]; light_eye.values[2] /= light_eye.values[3]; light_eye.values[3] = 1.0; - - glUniform3fv(uniforms[UNIFORM_LIGHT_EYE].location, 1, light_eye.values); } static void @@ -239,7 +239,11 @@ draw_rings(void) if (glass_prog != 0) { glUseProgram(glass_prog); + glUniform3fv(uniforms[UNIFORM_LIGHT_EYE].location, 1, + light_eye.values); + glBindVertexArray(ring.array_obj); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ring.vbo); for (instance = 0; instance < 27; instance++) { install_transform(instance); do_ring_drawelements(); @@ -261,6 +265,7 @@ draw(void) glViewport(0, 0, win_width, win_height); draw_rings(); + draw_ground(); SDL_GL_SwapBuffers(); frames++; @@ -422,9 +427,6 @@ revolve(const float *verts, unsigned int num_verts, } } - glGenVertexArrays(1, &ring.array_obj); - glBindVertexArray(ring.array_obj); - glBindBuffer(GL_ARRAY_BUFFER_ARB, ring.vbo); glVertexPointer(3, GL_FLOAT, 0, (void *)(uintptr_t)ring.pos_offset); glEnable(GL_VERTEX_ARRAY); @@ -439,11 +441,8 @@ revolve(const float *verts, unsigned int num_verts, glTexCoordPointer(3, GL_FLOAT, 0, (void *)(uintptr_t)ring.tangent_offset); glEnable(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER_ARB, ring.vbo); glNormalPointer(GL_FLOAT, 0, (void *)(uintptr_t)ring.norm_offset); glEnable(GL_NORMAL_ARRAY); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ring.vbo); } static void @@ -674,13 +673,12 @@ load_program(char *base_filename) } static void -load_programs(void) +load_glass_program(void) { int i; - if (glass_prog != 0) { + if (glass_prog != 0) glDeleteProgram(glass_prog); - } glass_prog = load_program("glass"); @@ -696,6 +694,30 @@ load_programs(void) } static void +load_ground_program(void) +{ + int i; + + if (ground_prog != 0) + glDeleteProgram(ground_prog); + + ground_prog = load_program("ground"); + + for (i = 0; i < ARRAY_SIZE(ground_uniforms); i++) { + ground_uniforms[i].location = + glGetUniformLocation(ground_prog, + ground_uniforms[i].name); + } +} + +static void +load_programs(void) +{ + load_glass_program(); + load_ground_program(); +} + +static void init(void) { int size; @@ -722,6 +744,8 @@ init(void) */ world_to_eye = gluLookAt4v(&eye_world, &eye_center_world, &z_axis); + setup_ground(); + generate_rounded_rect_verts(0.2, 1.0, .02, 0.9, corner_steps, &verts, &num_verts); @@ -745,6 +769,9 @@ init(void) size = ring.elements_offset + ring.elements_vert_stride * ring.num_verts; + glGenVertexArrays(1, &ring.array_obj); + glBindVertexArray(ring.array_obj); + glGenBuffers(1, &vbo); ring.vbo = vbo; glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo); @@ -27,6 +27,23 @@ #define GL_GLEXT_PROTOTYPES #include <GL/glew.h> +#include <glu3.h> + +enum ground_uniform_list { + GROUND_UNIFORM_MV, + GROUND_UNIFORM_MVP, + GROUND_UNIFORM_MAX +}; + +struct uniform_desc { + const char *name; + GLint location; +}; + +extern struct uniform_desc ground_uniforms[GROUND_UNIFORM_MAX]; +extern GLuint ground_prog; +extern GLUmat4 projection; +extern GLUmat4 world_to_eye; /* matrix.c */ void mult_m4_p4(float *result, const float *mat4, const float *point4); @@ -41,3 +58,7 @@ void print_m4(const float *mat4, const char *name); /* load_texture.c */ GLuint load_texture_rgb(const char *filename); + +/* ground.c */ +void draw_ground(void); +void setup_ground(void); diff --git a/ground.c b/ground.c new file mode 100644 index 0000000..feff32f --- /dev/null +++ b/ground.c @@ -0,0 +1,154 @@ +/* + * Copyright © 2009 Eric Anholt + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <err.h> +#include <errno.h> +#include <assert.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <getopt.h> + +#include "glass.h" + +static const int ground_size = 256; +static GLuint ground_obj; +static int elements_offset; +extern int no_multi_draw_arrays; +extern GLUvec4 eye_world; + +static GLuint ground_vbo; + +/* The ground plane is located in world coordinates, so no need to do any + * object_to_world transformation. + */ +static void +install_ground_transform(void) +{ + GLUmat4 mvp; + + mvp = gluMult4m_4m(&projection, &world_to_eye); + + glUniformMatrix4fv(ground_uniforms[GROUND_UNIFORM_MV].location, 1, 0, + (float *)&world_to_eye); + glUniformMatrix4fv(ground_uniforms[GROUND_UNIFORM_MVP].location, 1, 0, + (float *)&mvp); +} + +void +draw_ground(void) +{ + GLvoid *indices[ground_size]; + GLsizei count[ground_size]; + int v; + + if (ground_prog == 0) + return; + + glUseProgram(ground_prog); + install_ground_transform(); + + glBindVertexArray(ground_obj); + + for (v = 0; v < ground_size - 1; v++) { + indices[v] = (void *)(uintptr_t)(elements_offset + + v * sizeof(uint32_t) * 2 * + ground_size); + count[v] = 2 * ground_size; + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ground_vbo); + if (GLEW_EXT_multi_draw_arrays && !no_multi_draw_arrays) { + glMultiDrawElements(GL_TRIANGLE_STRIP, + count, + GL_UNSIGNED_INT, + (const GLvoid **)indices, + ground_size - 1); + } else { + for (v = 0; v < ground_size - 1; v++) { + glDrawElements(GL_TRIANGLE_STRIP, + ground_size * 2, + GL_UNSIGNED_INT, + indices[v]); + } + } +} + +void +setup_ground(void) +{ + int ground_size = 256; + int vbo_size, x, y; + int pos_offset; + char *base; + float *pos; + uint32_t *elements; + + glGenVertexArrays(1, &ground_obj); + glBindVertexArray(ground_obj); + + pos_offset = 0; + elements_offset = pos_offset + + sizeof(float) * ground_size * ground_size * 3; + + vbo_size = elements_offset + + 2 * sizeof(uint32_t) * (ground_size - 1) * ground_size; + + glGenBuffers(1, &ground_vbo); + glBindBuffer(GL_ARRAY_BUFFER_ARB, ground_vbo); + glBufferData(GL_ARRAY_BUFFER_ARB, vbo_size, NULL, GL_STATIC_DRAW_ARB); + base = glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + pos = (float *)(base + pos_offset); + elements = (uint32_t *)(base + elements_offset); + + /* position generation */ + for (y = 0; y < ground_size; y++) { + for (x = 0; x < ground_size; x++) { + float *element = &pos[(y * ground_size + x) * 3]; + + element[0] = x - ground_size / 2; + element[1] = y - ground_size / 2; + element[2] = 0.0; + } + } + + uint32_t *next_element = elements; + for (y = 0; y < ground_size - 1; y++) { + for (x = 0; x < ground_size; x++) { + *next_element++ = (y + 1) * ground_size + x; + *next_element++ = y * ground_size + x; + } + } + + glUnmapBuffer(GL_ARRAY_BUFFER_ARB); + + glVertexPointer(3, GL_FLOAT, 0, (void *)(uintptr_t)pos_offset); + glEnable(GL_VERTEX_ARRAY); +} diff --git a/ground.frag b/ground.frag new file mode 100644 index 0000000..1938364 --- /dev/null +++ b/ground.frag @@ -0,0 +1,125 @@ +void main() +{ + gl_FragColor = vec4(1,0,0,0); +} + +#if 0 +varying vec3 light_surf; +varying vec3 eye_surf; +varying vec3 tangent_surf; +varying vec2 texcoord; +uniform sampler2D normal_sampler; +uniform sampler2D heightmap_sampler; +uniform float F0, ni; + +float schlick_fresnel(float n_dot_l) +{ + return F0 + (1 - F0) * pow(1 - n_dot_l, 5); +} + +/* This returns garbage compared to Schlick. */ +float fresnel(float v_dot_h) +{ + float c = v_dot_h; /* cos theta, v . h or l . h */ + float g = sqrt(ni * ni + c * c - 1); + float gmc = g - c; + float gpc = g + c; + float c_gpc_m_1_squared = (c * gpc - 1) * (c * gpc - 1); + float c_gmc_p_1_squared = (c * gmc + 1) * (c * gmc + 1); + + return gmc*gmc / (2 * gpc*gpc) * (1 + c_gmc_p_1_squared / + c_gpc_m_1_squared); +} + +void main() +{ + const vec4 material_color = vec4(0.7, 0.5, 0.3, 0.0); + vec3 l = normalize(light_surf); + vec3 v = normalize(eye_surf); + vec3 h = normalize(l + v); + vec3 t = normalize(tangent_surf); + vec3 n = texture2D(normal_sampler, texcoord).xyz * 2 - 1; + /* Hack: Reduce the significance of our normal map, which otherwise + * looks incongruous with the straight edges. + */ + n = normalize(n + vec3(0,0,1)); + float n_dot_l = dot(n, l); + float n_dot_v = dot(n, v); + float n_dot_h = dot(n, h); + float v_dot_h = dot(v, h); + float s = .7; + float d = 1 - s; + float Ii = 0.9; /*intensity of incoming light */ + float Iia = .1 * Ii; /*intensity of ambient light */ + + float cos2_alpha = n_dot_h * n_dot_h; + float tan2_alpha = (1 - cos2_alpha) / cos2_alpha; + float Rs; + float D; + + /* Aniso BRDF from Ward's "Measuring and Modeling + * Anisotropic Reflection". + */ + + /* brushed metal */ + float ward_n = .037; + float ward_m = .063; + + /* Make phi be the angle between the projections of + * the tangent and half-angle vectors onto the + * surface plane (z=0). Doing it right would involve + * projecting onto the plane defined by n. + */ + float cos_phi = dot(normalize(t.xy), normalize(h.xy)); + + float cos2_phi_over_m2 = ((cos_phi * cos_phi) / (ward_m * ward_m)); + float sin2_phi_over_n2 = ((1 - cos_phi * cos_phi) / (ward_n * ward_n)); +#if 1 + D = exp(-tan2_alpha * (cos2_phi_over_m2 + sin2_phi_over_n2)); +#else + /* Ward's "computationally convenient" equation. + * Doesn't work. + */ + D = exp(-2 * (cos2_phi_over_m2 + + sin2_phi_over_n2) / + (1 + n_dot_h)); +#endif + Rs = 2 * schlick_fresnel(n_dot_l) * D / + sqrt(n_dot_l * n_dot_v) / (ward_m * ward_n); + + Rs *= step(0, n_dot_l); + Rs *= step(0, n_dot_v); + + float Rd = (1 - F0) * 2; + /* Ambient occlusion factor -- sample the height map we + * used to generate the normal map, and reduce intensity in + * the valleys. + */ + float heightmap = texture2D(heightmap_sampler, texcoord).x; + float Ra = Rd * (.8 + .2 * heightmap); + + gl_FragColor = n_dot_l * step(0, n_dot_l) * + vec4(material_color.xyz * + (Rd * d + Rs * s), + material_color.w) + + Iia * Ra * material_color.xyzw; + + /* Debugging scalars -- Map [0,1] to [0.5,1] to catch negative + * values. Multiply by the step function to catch when + * the scalar won't come into play because Rs == 0. + */ +#if 0 + gl_FragColor = vec4(vec3(F0 / 2 + .5), 1); +#endif +/* Normal visualization */ +/* +vec3 temp = vec3((normal.x + 1) / 2, + (normal.y + 1) / 2, + (normal.z + 1) / 2); +gl_FragColor = vec4(temp.xyz, 0); +*/ +/* + gl_FragColor = texture2D(normal_sampler, texcoord); +*/ +} +#endif
\ No newline at end of file diff --git a/ground.vert b/ground.vert new file mode 100644 index 0000000..a1e3dd9 --- /dev/null +++ b/ground.vert @@ -0,0 +1,28 @@ +/*uniform vec3 light_eye; +varying vec2 texcoord; +varying vec3 light_surf; +varying vec3 eye_surf; +varying vec3 tangent_surf; +*/ +uniform mat4 mvp, mv; + +void main() +{ +/* vec3 t = (mv * vec4(1.0,, 0.0)).xyz; + vec3 n = (mv * vec4(gl_Normal, 0.0)).xyz; +*/ + gl_Position = mvp * gl_Vertex; +/* + mat3 tbn = mat3(t, + cross(n, t), + n + ); + + vec3 vertex_eye = vec3(mv * gl_Vertex); + + texcoord = vec2(gl_MultiTexCoord0.x * 4, gl_MultiTexCoord0.y); + light_surf = normalize((light_eye - vertex_eye) * tbn); + eye_surf = normalize((-vertex_eye) * tbn); + tangent_surf = gl_MultiTexCoord1.xyz * tbn; +*/ +} |