Skip to content

Commit

Permalink
Make normal mapping work for planets
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen M. Cameron <stephenmcameron@gmail.com>
  • Loading branch information
smcameron committed Jan 17, 2016
1 parent fcfd51f commit de28079
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 49 deletions.
102 changes: 86 additions & 16 deletions graph_dev_opengl.c
Expand Up @@ -102,6 +102,8 @@ struct vertex_triangle_buffer_data {
union vec3 tvertex2;
union vec3 wireframe_edge_mask;
union vec2 texture_coord;
union vec3 tangent;
union vec3 bitangent;
};

struct vertex_wireframe_line_buffer_data {
Expand Down Expand Up @@ -209,6 +211,14 @@ void mesh_graph_dev_init(struct mesh *m)
g_vt_buffer_data[v_index].tvertex2.v.y = m->t[i].v[2]->y;
g_vt_buffer_data[v_index].tvertex2.v.z = m->t[i].v[2]->z;

g_vt_buffer_data[v_index].tangent.v.x = m->t[i].vtangent[j].x;
g_vt_buffer_data[v_index].tangent.v.y = m->t[i].vtangent[j].y;
g_vt_buffer_data[v_index].tangent.v.z = m->t[i].vtangent[j].z;

g_vt_buffer_data[v_index].bitangent.v.x = m->t[i].vbitangent[j].x;
g_vt_buffer_data[v_index].bitangent.v.y = m->t[i].vbitangent[j].y;
g_vt_buffer_data[v_index].bitangent.v.z = m->t[i].vbitangent[j].z;

/* bias the edge distance to make the coplanar edges not draw */
if ((j == 1 || j == 2) && (m->t[i].flag & TRIANGLE_1_2_COPLANAR))
g_vt_buffer_data[v_index].wireframe_edge_mask.v.x = 1000;
Expand Down Expand Up @@ -669,11 +679,14 @@ struct graph_dev_gl_textured_shader {
GLint normal_matrix_id;
GLint vertex_position_id;
GLint vertex_normal_id;
GLint vertex_tangent_id;
GLint vertex_bitangent_id;
GLint tint_color_id;
GLint texture_coord_id;
GLint texture_2d_id;
GLint emit_texture_2d_id;
GLint texture_cubemap_id;
GLint normalmap_cubemap_id;
GLint light_pos_id;

GLint shadow_sphere_id;
Expand Down Expand Up @@ -777,8 +790,10 @@ static struct graph_dev_gl_textured_shader textured_with_sphere_shadow_shader;
static struct graph_dev_gl_textured_shader textured_lit_shader;
static struct graph_dev_gl_textured_shader textured_lit_emit_shader;
static struct graph_dev_gl_textured_shader textured_cubemap_lit_shader;
static struct graph_dev_gl_textured_shader textured_cubemap_lit_normal_map_shader;
static struct graph_dev_gl_textured_shader textured_cubemap_shield_shader;
static struct graph_dev_gl_textured_shader textured_cubemap_lit_with_annulus_shadow_shader;
static struct graph_dev_gl_textured_shader textured_cubemap_normal_mapped_lit_with_annulus_shadow_shader;
static struct graph_dev_gl_textured_particle_shader textured_particle_shader;
static struct graph_dev_gl_fs_effect_shader fs_copy_shader;
static struct graph_dev_smaa_effect smaa_effect;
Expand Down Expand Up @@ -1173,7 +1188,7 @@ static void graph_dev_draw_normal_lines(const struct mat44 *mat_mvp, struct mesh
static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader, const struct mat44 *mat_mvp,
const struct mat44 *mat_mv, const struct mat33 *mat_normal, struct mesh *m,
struct sng_color *triangle_color, float alpha, union vec3 *eye_light_pos, GLuint texture_number,
GLuint emit_texture_number, struct shadow_sphere_data *shadow_sphere,
GLuint emit_texture_number, GLuint normalmap_texture_number, struct shadow_sphere_data *shadow_sphere,
struct shadow_annulus_data *shadow_annulus, int do_cullface, int do_blend,
float ring_texture_v, float ring_inner_radius, float ring_outer_radius)
{
Expand Down Expand Up @@ -1205,6 +1220,9 @@ static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader
else if (shader->texture_cubemap_id >= 0)
BIND_TEXTURE(GL_TEXTURE0, GL_TEXTURE_CUBE_MAP, texture_number);

if (shader->normalmap_cubemap_id >= 0)
BIND_TEXTURE(GL_TEXTURE3, GL_TEXTURE_CUBE_MAP, normalmap_texture_number);

if (shader->emit_texture_2d_id >= 0)
BIND_TEXTURE(GL_TEXTURE1, GL_TEXTURE_2D, emit_texture_number);

Expand Down Expand Up @@ -1281,6 +1299,32 @@ static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader
);
}

if (shader->vertex_tangent_id >= 0) {
glEnableVertexAttribArray(shader->vertex_tangent_id);
glBindBuffer(GL_ARRAY_BUFFER, ptr->triangle_vertex_buffer);
glVertexAttribPointer(
shader->vertex_tangent_id, /* The attribute we want to configure */
3, /* size */
GL_FLOAT, /* type */
GL_FALSE, /* normalized? */
sizeof(struct vertex_triangle_buffer_data), /* stride */
(void *)offsetof(struct vertex_triangle_buffer_data, tangent.v.x) /* array buffer offset */
);
}

if (shader->vertex_bitangent_id >= 0) {
glEnableVertexAttribArray(shader->vertex_bitangent_id);
glBindBuffer(GL_ARRAY_BUFFER, ptr->triangle_vertex_buffer);
glVertexAttribPointer(
shader->vertex_bitangent_id, /* The attribute we want to configure */
3, /* size */
GL_FLOAT, /* type */
GL_FALSE, /* normalized? */
sizeof(struct vertex_triangle_buffer_data), /* stride */
(void *)offsetof(struct vertex_triangle_buffer_data, bitangent.v.x) /* array buffer offset */
);
}

if (shader->texture_coord_id >= 0) {
glEnableVertexAttribArray(shader->texture_coord_id);
glBindBuffer(GL_ARRAY_BUFFER, ptr->triangle_vertex_buffer);
Expand All @@ -1294,6 +1338,10 @@ static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader
glDisableVertexAttribArray(shader->vertex_position_id);
if (shader->vertex_normal_id >= 0)
glDisableVertexAttribArray(shader->vertex_normal_id);
if (shader->vertex_tangent_id >= 0)
glDisableVertexAttribArray(shader->vertex_tangent_id);
if (shader->vertex_bitangent_id >= 0)
glDisableVertexAttribArray(shader->vertex_bitangent_id);
if (shader->texture_coord_id >= 0)
glDisableVertexAttribArray(shader->texture_coord_id);
glUseProgram(0);
Expand Down Expand Up @@ -1837,7 +1885,7 @@ static void graph_dev_draw_nebula(const struct mat44 *mat_mvp, const struct mat4
float alpha = fabs(vec3_dot(&camera_normal, &camera_ent_vector)) * mt->alpha;

graph_dev_raster_texture(&textured_shader, &mat_mvp_local_r, &mat_mv_local_r, &mat_normal_local_r,
e->m, &mt->tint, alpha, eye_light_pos, mt->texture_id[i], 0, 0, 0, 0, 1, 0.0f,
e->m, &mt->tint, alpha, eye_light_pos, mt->texture_id[i], 0, -1, 0, 0, 0, 1, 0.0f,
2.0f, 4.0f);

if (draw_billboard_wireframe) {
Expand Down Expand Up @@ -2080,6 +2128,7 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve
float texture_alpha = 1.0;
GLuint texture_id = 0;
GLuint emit_texture_id = 0;
GLuint normalmap_id = -1;

/* for sphere shadows */
struct shadow_sphere_data shadow_sphere;
Expand Down Expand Up @@ -2162,9 +2211,14 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve
case MATERIAL_TEXTURED_PLANET: {
struct material_textured_planet *mt = &e->material_ptr->textured_planet;
texture_id = mt->texture_id;
normalmap_id = mt->normalmap_id;

if (mt->ring_material && mt->ring_material->type == MATERIAL_TEXTURED_PLANET_RING) {
tex_shader = &textured_cubemap_lit_with_annulus_shadow_shader;
if (normalmap_id == (GLuint) -1)
tex_shader = &textured_cubemap_lit_with_annulus_shadow_shader;
else
tex_shader =
&textured_cubemap_normal_mapped_lit_with_annulus_shadow_shader;

struct material_textured_planet_ring *ring_mt =
&mt->ring_material->textured_planet_ring;
Expand All @@ -2187,7 +2241,10 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve
shadow_annulus.r2 = vec3_cwise_max(&e->scale) *
ring_outer_radius;
} else {
tex_shader = &textured_cubemap_lit_shader;
if (normalmap_id != (GLuint) -1)
tex_shader = &textured_cubemap_lit_normal_map_shader;
else
tex_shader = &textured_cubemap_lit_shader;
}
}
break;
Expand Down Expand Up @@ -2245,8 +2302,8 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve
if (tex_shader)
graph_dev_raster_texture(tex_shader, mat_mvp, mat_mv, mat_normal, e->m,
&texture_tint, texture_alpha, eye_light_pos, texture_id,
emit_texture_id, &shadow_sphere, &shadow_annulus, do_cullface,
do_blend, ring_texture_v,
emit_texture_id, normalmap_id, &shadow_sphere, &shadow_annulus,
do_cullface, do_blend, ring_texture_v,
ring_inner_radius, ring_outer_radius);
else if (atmosphere)
graph_dev_raster_atmosphere(mat_mvp, mat_mv, mat_normal,
Expand Down Expand Up @@ -2748,17 +2805,21 @@ static void setup_textured_shader(const char *basename, const char *defines,
shader->shadow_sphere_id = glGetUniformLocation(shader->program_id, "u_Sphere");
}

static void setup_textured_cubemap_shader(const char *basename, struct graph_dev_gl_textured_shader *shader)
static void setup_textured_cubemap_shader(const char *basename, int use_normal_map,
struct graph_dev_gl_textured_shader *shader)
{
/* set all attributes to -1 */
memset(shader, 0xff, sizeof(*shader));

const char *vert_header =
UNIVERSAL_SHADER_HEADER
"#define INCLUDE_VS 1\n";
const char *frag_header =
UNIVERSAL_SHADER_HEADER
"#define INCLUDE_FS 1\n";
char vert_header[1024];
char frag_header[1024];

sprintf(vert_header, "%s\n%s\n%s\n",
UNIVERSAL_SHADER_HEADER, "#define INCLUDE_VS 1\n",
use_normal_map ? "#define USE_NORMAL_MAP 1\n" : "\n");
sprintf(frag_header, "%s\n%s\n%s\n",
UNIVERSAL_SHADER_HEADER, "#define INCLUDE_FS 1\n",
use_normal_map ? "#define USE_NORMAL_MAP 1\n" : "\n");

char shader_filename[PATH_MAX];
snprintf(shader_filename, sizeof(shader_filename), "%s.shader", basename);
Expand All @@ -2776,6 +2837,10 @@ static void setup_textured_cubemap_shader(const char *basename, struct graph_dev
shader->light_pos_id = glGetUniformLocation(shader->program_id, "u_LightPos");
shader->texture_cubemap_id = glGetUniformLocation(shader->program_id, "u_AlbedoTex");
glUniform1i(shader->texture_cubemap_id, 0);
if (use_normal_map) {
shader->normalmap_cubemap_id = glGetUniformLocation(shader->program_id, "u_NormalMapTex");
glUniform1i(shader->normalmap_cubemap_id, 3); /* GL_TEXTURE3 */
}
shader->tint_color_id = glGetUniformLocation(shader->program_id, "u_TintColor");
shader->ring_texture_v_id = glGetUniformLocation(shader->program_id, "u_ring_texture_v");
if (shader->ring_texture_v_id >= 0)
Expand All @@ -2790,6 +2855,8 @@ static void setup_textured_cubemap_shader(const char *basename, struct graph_dev
/* Get a handle for our buffers */
shader->vertex_position_id = glGetAttribLocation(shader->program_id, "a_Position");
shader->vertex_normal_id = glGetAttribLocation(shader->program_id, "a_Normal");
shader->vertex_tangent_id = glGetAttribLocation(shader->program_id, "a_Tangent");
shader->vertex_bitangent_id = glGetAttribLocation(shader->program_id, "a_BiTangent");

shader->shadow_annulus_texture_id = glGetUniformLocation(shader->program_id, "u_AnnulusAlbedoTex");
glUniform1i(shader->shadow_annulus_texture_id, 1);
Expand Down Expand Up @@ -3362,10 +3429,13 @@ int graph_dev_setup(const char *shader_dir)
setup_textured_shader("textured-and-lit-per-pixel", UNIVERSAL_SHADER_HEADER, &textured_lit_shader);
setup_textured_shader("textured-and-lit-per-pixel", UNIVERSAL_SHADER_HEADER "#define USE_EMIT_MAP",
&textured_lit_emit_shader);
setup_textured_cubemap_shader("textured-cubemap-and-lit-per-pixel", &textured_cubemap_lit_shader);
setup_textured_cubemap_shader("textured-cubemap-shield-per-pixel", &textured_cubemap_shield_shader);
setup_textured_cubemap_shader("textured-cubemap-and-lit-with-annulus-shadow-per-pixel",
setup_textured_cubemap_shader("textured-cubemap-and-lit-per-pixel", 0, &textured_cubemap_lit_shader);
setup_textured_cubemap_shader("textured-cubemap-and-lit-per-pixel", 1, &textured_cubemap_lit_normal_map_shader);
setup_textured_cubemap_shader("textured-cubemap-shield-per-pixel", 0, &textured_cubemap_shield_shader);
setup_textured_cubemap_shader("textured-cubemap-and-lit-with-annulus-shadow-per-pixel", 0,
&textured_cubemap_lit_with_annulus_shadow_shader);
setup_textured_cubemap_shader("textured-cubemap-and-lit-with-annulus-shadow-per-pixel", 1,
&textured_cubemap_normal_mapped_lit_with_annulus_shadow_shader);
setup_textured_particle_shader(&textured_particle_shader);
setup_fs_effect_shader("fs-effect-copy", &fs_copy_shader);

Expand Down
1 change: 1 addition & 0 deletions material.h
Expand Up @@ -106,6 +106,7 @@ struct material_textured_planet_ring {

struct material_textured_planet {
int texture_id;
int normalmap_id;
struct material *ring_material;
};

Expand Down
14 changes: 12 additions & 2 deletions mesh_viewer.c
Expand Up @@ -49,6 +49,7 @@ static int frame_counter = 0;
static int periodic_snapshots = 0;
static int snapshot_number = 0;
static char *planetname = NULL;
static char *normalmapname = NULL;
static char *program;
union quat autorotation;
static int icosohedron_subdivision = 4;
Expand Down Expand Up @@ -610,7 +611,8 @@ static void setup_skybox(char *skybox_prefix)
__attribute__((noreturn)) void usage(char *program)
{
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s [ -p <planet-texture> ] [ -i icosohedron-subdivision]\n", program);
fprintf(stderr, " %s -p <planet-texture> [ -i icosohedrion-subdivision] [ -n <normal-map-texture> ]\n",
program);
fprintf(stderr, " %s <mesh-file>\n", program);
exit(-1);
}
Expand All @@ -631,6 +633,7 @@ static struct option long_options[] = {
{ "help", no_argument, NULL, 'h' },
{ "planetmode", required_argument, NULL, 'p' },
{ "icosohedron", required_argument, NULL, 'i' },
{ "normalmap", required_argument, NULL, 'n' },
};

static int process_options(int argc, char *argv[])
Expand All @@ -641,7 +644,7 @@ static int process_options(int argc, char *argv[])
while (1) {
int option_index;

c = getopt_long(argc, argv, "hi:p:", long_options, &option_index);
c = getopt_long(argc, argv, "hi:n:p:", long_options, &option_index);
if (c < 0) {
break;
}
Expand All @@ -660,6 +663,9 @@ static int process_options(int argc, char *argv[])
icosohedron_subdivision = 0;
}
break;
case 'n':
normalmapname = optarg;
break;
case 'h':
usage(program);
default:
Expand Down Expand Up @@ -776,6 +782,10 @@ int main(int argc, char *argv[])
atmosphere_mesh = mesh_unit_icosphere(icosohedron_subdivision);
material_init_textured_planet(&planet_material);
planet_material.textured_planet.texture_id = load_cubemap_textures(0, planetname);
if (normalmapname)
planet_material.textured_planet.normalmap_id = load_cubemap_textures(0, normalmapname);
else
planet_material.textured_planet.normalmap_id = -1;
planet_material.textured_planet.ring_material = 0;
material_init_atmosphere(&atmosphere_material);
} else {
Expand Down
46 changes: 34 additions & 12 deletions share/snis/shader/textured-cubemap-and-lit-per-pixel.shader
@@ -1,5 +1,6 @@
/*
Copyright (C) 2014 Jeremy Van Grinsven
Copyright (C) 2016 Stephen M. Cameron
This file is part of Spacenerds In Space.
Expand All @@ -17,8 +18,8 @@
along with Spacenerds in Space; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author:
Jeremy Van Grinsven
Authors:
Jeremy Van Grinsven, Stephen M. Cameron
*/

#if !defined(AMBIENT)
Expand All @@ -29,22 +30,36 @@ varying vec3 v_Position;
varying vec3 v_Normal;
varying vec3 v_TexCoord;

#if defined(USE_NORMAL_MAP)
varying vec3 v_Tangent;
varying vec3 v_BiTangent;
varying mat3 tbn;
#endif

#if defined(INCLUDE_VS)
uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix.
uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix.
uniform mat3 u_NormalMatrix;

attribute vec4 a_Position; // Per-vertex position information we will pass in.
attribute vec3 a_Normal; // Per-vertex normal information we will pass in.
attribute vec3 a_Normal; // Per-vertex normal, tangent, and bitangent information we will pass in.
#if defined(USE_NORMAL_MAP)
attribute vec3 a_Tangent;
attribute vec3 a_BiTangent;
#endif

void main()
{
/* Transform the vertex into eye space. */
v_Position = vec3(u_MVMatrix * a_Position);

/* Transform the normal's orientation into eye space. */
v_Normal = normalize(u_NormalMatrix * a_Normal);

/* Transform the normal's, Tangent's and BiTangent's orientations into eye space. */
v_Normal = normalize(u_NormalMatrix * a_Normal);
#if defined(USE_NORMAL_MAP)
v_Tangent = normalize(u_NormalMatrix * a_Tangent);
v_BiTangent = normalize(u_NormalMatrix * a_BiTangent);
tbn = mat3(v_Tangent, v_BiTangent, v_Normal);
#endif
v_TexCoord = a_Position.xyz;

/* gl_Position is a special variable used to store the final position.
Expand All @@ -57,21 +72,28 @@ varying vec3 v_TexCoord;
uniform samplerCube u_AlbedoTex;
uniform vec4 u_TintColor;
uniform vec3 u_LightPos; // The position of the light in eye space.
#if defined(USE_NORMAL_MAP)
uniform samplerCube u_NormalMapTex;
#endif

void main()
{
/* Get a lighting direction vector from the light to the vertex. */
vec3 light_dir = normalize(u_LightPos - v_Position);

/* Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
pointing in the same direction then it will get max illumination. */
float direct = dot(normalize(v_Normal), light_dir);
#if defined(USE_NORMAL_MAP)
vec3 pixel_normal = tbn * normalize(textureCube(u_NormalMapTex, v_TexCoord).xyz * 2.0 - 1.0);
float normal_map_shadow = max(0.0, dot(pixel_normal, light_dir));

/* make diffuse light atleast ambient */
float diffuse = max(AMBIENT, direct);

float diffuse = max(AMBIENT, normal_map_shadow);
#else
/* Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
pointing in the same direction then it will get max illumination. */
float diffuse = dot(normalize(v_Normal), light_dir);
diffuse = max(AMBIENT, diffuse);
#endif
gl_FragColor = textureCube(u_AlbedoTex, v_TexCoord);

gl_FragColor.rgb *= diffuse;

/* tint with alpha pre multiply */
Expand Down

0 comments on commit de28079

Please sign in to comment.