Draw our teapot with the techniques of texture mapping, shadow-maps and normal mapping.
Step 1:
load OBJ file.
void readFile(char *filename, struct point *vertex, struct point *normal, struct coord *vt,
struct point *vx, struct point *vy, struct match **face) {
FILE *fptr;
char buf[100];
fptr = fopen(filename, "r");
do{
fgets(buf,100,fptr);
} while(buf[0]=='#');
int i = 0; int j = 0; int k = 0; int p = 0; int q = 0; int r = 0;
while(fscanf(fptr, "%s", buf) != EOF) {
if (strcmp(buf, "v") == 0) {
fscanf(fptr, "%lf %lf %lf",
&vertex[i].x, &vertex[i].y, &vertex[i].z);
i++;
} else if (strcmp(buf, "vn") == 0) {
fscanf(fptr, "%lf %lf %lf",
&normal[j].x, &normal[j].y, &normal[j].z);
j++;
} else if (strcmp(buf, "f") == 0) {
fscanf(fptr, "%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d",
&face[k][0].v, &face[k][0].t, &face[k][0].n, &face[k][1].v, &face[k][1].t, &face[k][1].n,
&face[k][2].v, &face[k][2].t, &face[k][2].n, &face[k][3].v, &face[k][3].t, &face[k][3].n);
k++;
} else if (strcmp(buf, "vt") == 0 ) {
fscanf(fptr, "%lf %lf",
&vt[p].x, &vt[p].y);
p++;
} else if (strcmp(buf, "vx") == 0 ) {
fscanf(fptr, "%lf %lf %lf",
&vx[q].x, &vx[q].y, &vx[q].z);
q++;
} else if (strcmp(buf, "vy") == 0 ) {
fscanf(fptr, "%lf %lf %lf",
&vy[r].x, &vy[r].y, &vy[r].z);
r++;
}
}
fclose(fptr);
}
Step 2.
load texture,we use three textures for ground,back and teapot respectively
void load_texture(char *filename,unsigned int tid)
{
FILE *fopen(), *fptr;
char buf[512];
int im_size, im_width, im_height, max_color;
unsigned char *texture_bytes, *parse;
fptr=fopen(filename,"r");
fgets(buf,512,fptr);
do{
fgets(buf,512,fptr);
} while(buf[0]=='#');
parse = strtok(buf," \t");
im_width = atoi(parse);
parse = strtok(NULL," \n");
im_height = atoi(parse);
fgets(buf,512,fptr);
parse = strtok(buf," \n");
max_color = atoi(parse);
im_size = im_width*im_height;
texture_bytes = (unsigned char *)calloc(3,im_size);
fread(texture_bytes,3,im_size,fptr);
fclose(fptr);
glBindTexture(GL_TEXTURE_2D,tid);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,im_width,im_height,0,GL_RGB,
GL_UNSIGNED_BYTE,texture_bytes);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
free(texture_bytes);
}
Step 4.
draw the shadow of the teapot!
void build_shadowmap()
{
glBindTexture(GL_TEXTURE_2D,1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, XRES, YRES, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER,1);
glDrawBuffer(GL_NONE);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,1,0);
glBindFramebufferEXT(GL_FRAMEBUFFER,0);
}
Step 4.
set shaders
.frag
uniform sampler2D mytexture;
uniform sampler2D groundtexture;
uniform sampler2D mynormalmap;
uniform int times;
varying vec3 ec_vnormal, ec_vposition, ec_vtangent, ec_vbitangent;
varying vec4 tcoords;
void main()
{
float pi = 3.14159;
vec3 P, N, L, V, H, mapN, tcolor;
vec4 pccoords;
vec4 diffuse_color;
vec4 specular_color;
float shininess = gl_FrontMaterial.shininess;
float depthsample, clarity;
P = ec_vposition;
N = normalize(ec_vnormal);
L = normalize(gl_LightSource[0].position.xyz - P);
V = normalize(-P);
H = normalize(L+V);
pccoords = tcoords/tcoords.w ;
depthsample = texture2D(mytexture,pccoords.st).z;
clarity = 1.0;
if (times == 1) {
if(depthsample < pccoords.z) clarity = 0.8;
diffuse_color *= clarity*max(dot(N,L),0.0);
specular_color *= clarity*pow(max(dot(H,N),0.0),shininess);
gl_FragColor = 0.5*(diffuse_color + specular_color);
} else if(times == 2 || times == 3) {
if (times == 2) {
tcolor = vec3(texture2D(groundtexture,gl_TexCoord[0].st));
} else if (times == 3) {
mat3 tform;
tform = mat3(ec_vtangent,ec_vbitangent,ec_vnormal);
mapN = vec3(texture2D(mynormalmap,gl_TexCoord[0].st));
mapN.xy = 2.0*mapN.xy - vec2(1.0,1.0);
N = normalize(tform*normalize(mapN));
tcolor = vec3(texture2D(mytexture,gl_TexCoord[0].st));
}
diffuse_color = vec4(tcolor,1.0)*max(dot(N,L),0.0);
specular_color = gl_FrontMaterial.specular*pow(max(dot(H,N),0.0),shininess);
specular_color *= (shininess+2.0)/(8.0*pi);
gl_FragColor = diffuse_color + specular_color;
if (times == 2) {
if(depthsample < pccoords.z) {
clarity = 0.8;
diffuse_color *= clarity*max(dot(N,L),0.0);
specular_color *= clarity*pow(max(dot(H,N),0.0),shininess);
gl_FragColor = 0.5*(diffuse_color + specular_color);
}
}
}
}
.vert
varying vec3 ec_vnormal, ec_vposition, ec_vtangent, ec_vbitangent;
varying vec4 tcoords;
attribute vec3 tangent, bitangent;
void main()
{
ec_vnormal = (gl_NormalMatrix*gl_Normal).xyz;
ec_vposition = (gl_ModelViewMatrix*gl_Vertex).xyz;
gl_Position = gl_ProjectionMatrix*gl_ModelViewMatrix*gl_Vertex;
tcoords = gl_TextureMatrix[7]*gl_Vertex;
ec_vtangent = gl_NormalMatrix*tangent;
ec_vbitangent = gl_NormalMatrix*bitangent;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
Step 4.
draw the stuff!
glutDisplayFunc(do_stuff);
void do_stuff() {
struct point eyepoint, viewpoint;
glBindFramebufferEXT(GL_FRAMEBUFFER,1);
glUseProgram(0);
eyepoint.x = light0_position[0];
eyepoint.y = light0_position[1];
eyepoint.z = light0_position[2];
viewpoint.x = light0_direction[0]+light0_position[0];
viewpoint.y = light0_direction[1]+light0_position[1];
viewpoint.z = light0_direction[2]+light0_position[2];
view_volume(eyepoint,viewpoint);
glClearColor(0.8,0.6,0.62,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
lights();
drawpot();
glBindFramebufferEXT(GL_FRAMEBUFFER,0);
save_matrix(eyepoint,viewpoint);
glUseProgram(sprogram);
set_uniform(sprogram, 1);
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D,1);
eyepoint.x = 3; eyepoint.y = 3; eyepoint.z = 3;
viewpoint.x = 0.0; viewpoint.y = 1; viewpoint.z = 0.0;
view_volume(eyepoint,viewpoint);
lights();
drawquads();
drawBack();
drawpot();
glutSwapBuffers();
}
drawquads()//draw the ground
drawBack()//draw the background
drawpot()//draw the teapot
void drawquads() {
float bottom[4][3]={{-GROUND_SIZE, 0, -GROUND_SIZE}, {-GROUND_SIZE, 0, GROUND_SIZE},
{GROUND_SIZE, 0, GROUND_SIZE}, {GROUND_SIZE, 0, -GROUND_SIZE}};
float mytexcoords[4][2] = {{0.0,0.0}, {1.0,0.0}, {1.0,1.0}, {0.0,1.0}};
glUseProgram(sprogram);
set_uniform(sprogram, 2);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,4);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glNormal3f(0.0,1.0,0.0);
int i;
for(i=0;i<4;i++){
glTexCoord2fv(mytexcoords[i]);
glVertex3f(bottom[i][0],bottom[i][1],bottom[i][2]);
}
glDisable(GL_TEXTURE_2D);
glEnd();
}
void drawBack() {
float back[4][3]={{-WALL_SIZE, 0, -WALL_SIZE}, {-WALL_SIZE, 2 * WALL_SIZE, -WALL_SIZE},
{WALL_SIZE, 2 * WALL_SIZE, -WALL_SIZE}, {WALL_SIZE ,0, -WALL_SIZE}};
float backtexcoords[4][2] = {{0.0,1.0},{0.0,0.0},{1.0,0.0},{1.0,1.0}};
float left[4][3]={{-WALL_SIZE,0,-WALL_SIZE},{-WALL_SIZE,2*WALL_SIZE,-WALL_SIZE},
{-WALL_SIZE,2*WALL_SIZE,WALL_SIZE},{-WALL_SIZE,0,WALL_SIZE}};
float lefttexcoords[4][2] = {{1.0,1.0},{1.0,0.0},{0.0,0.0},{0.0,1.0}};
glUseProgram(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,5);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glNormal3f(1.0,0.0,1.0);
int i;
for(i=0;i<4;i++){
glTexCoord2fv(backtexcoords[i]);
glVertex3f(back[i][0],back[i][1],back[i][2]);
}
for(i=0;i<4;i++){
glTexCoord2fv(lefttexcoords[i]);
glVertex3f(left[i][0],left[i][1],left[i][2]);
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
void drawpot() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 2);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 3);
glEnable(GL_TEXTURE_2D);
glUseProgram(sprogram);
set_uniform(sprogram, 3);
GLint tangent = glGetAttribLocation(sprogram,"tangent");
GLint bitangent = glGetAttribLocation(sprogram,"bitangent");
set_material();
glBegin(GL_QUADS);
int i;
for (i = 0;i < numOfFaces;++i) {
int j;
for (j = 0;j < 4;++j) {
int vi = face[i][j].v - 1;
int ti = face[i][j].t - 1;
int ni = face[i][j].n - 1;
glNormal3f(normal[ni].x, normal[ni].y, normal[ni].z);
glTexCoord2f(vt[ti].x, vt[ti].y);
glVertexAttrib3f(tangent, vx[vi].x, vx[vi].y, vx[vi].z);
glVertexAttrib3f(bitangent, vy[vi].x, vy[vi].y, vy[vi].z);
glVertex3f(vertex[vi].x, vertex[vi].y, vertex[vi].z);
}
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
Out teapot: