图形学实验报告
发布时间:2015-05-05 22:46:57
发布时间:2015-05-05 22:46:57
实验 四 基于着色器的纹理映射与光照渲染
一、 实验内容
在实验三的基础上,增加如下功能:
1、 绘制一个由细分四面体得到的三维镂垫(或三维迷宫)及其适当的场景(任选);
2、 在场景中至少添加三个光源:一个平行光、一个点光源、一个聚光灯;
3、 给三维镂垫表面(或三维迷宫)添加适当的纹理;
4、 可通过鼠标或键盘的按键(包括特殊健、组合健等)、菜单、滑动条等工具来实现光源、材质属性参数的设置,也包括对光源位置的控制等。
二、 实验环境
VS2012
三、 实验方案与程序设计
主程序(Exe4):
#pragma comment(lib, "glew32.lib")
#include "Angel.h"
static bool flag1 = true;
static bool flag2 = true;
const int NumTimesToSubdivide = 5;
const int NumTetrahedrons = 1024;
const int NumTriangles = 4*NumTetrahedrons;
const int NumVertices = 3 * NumTriangles;
const int TextureSize = 64;
typedef Angel::vec4 point4;
typedef Angel::vec4 color4;
GLuint textures[2];
GLubyte image[TextureSize][TextureSize][3];
GLubyte image2[TextureSize][TextureSize][3];
point4 points[NumVertices];
vec3 normals[NumVertices];
vec2 tex_coords[NumVertices];
GLuint ModelView, Projection, LightPosition;
//GLuint LightPosition;
float a = 0.0, b = 0.0, c = 2.0;
static GLfloat light_position[] = { a, b, c, 0.0 };
int Index = 0;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat z = 1.0;;
GLfloat LeftOrRight = 0.0;
GLfloat UpOrDown = 0.0;
void
draw( const vec3& a, const vec3& b, const vec3& c )
{
vec3 normal = normalize( cross(b - a, c - b) );
normals[Index] = normal; points[Index] = a; tex_coords[Index] = vec2( 0.0, 0.0 ); Index++;
normals[Index] = normal; points[Index] = b; tex_coords[Index] = vec2( 0.0, 1.0 ); Index++;
normals[Index] = normal; points[Index] = c; tex_coords[Index] = vec2( 1.0, 1.0 ); Index++;
}
void
tetra( const vec3& a, const vec3& b, const vec3& c, const vec3& d )
{
draw( a, b, c );
draw( a, c, d );
draw( a, d, b );
draw( b, d, c );
}
void
divide_tetra( const vec3& a, const vec3& b,
const vec3& c, const vec3& d, int count )
{
if ( count > 0 ) {
vec3 v0 = ( a + b ) / 2.0;
vec3 v1 = ( a + c ) / 2.0;
vec3 v2 = ( a + d ) / 2.0;
vec3 v3 = ( b + c ) / 2.0;
vec3 v4 = ( c + d ) / 2.0;
vec3 v5 = ( b + d ) / 2.0;
divide_tetra( a, v0, v1, v2, count - 1 );
divide_tetra( v0, b, v3, v5, count - 1 );
divide_tetra( v1, v3, c, v4, count - 1 );
divide_tetra( v2, v4, d, v5, count - 1 );
}
else {
tetra( a, b, c, d );
}
}
void
init(void)
{
vec3 vertices[4] = {
vec3( 0.0, 0.0, 1.0 ),
vec3( 0.0, 0.942809, -0.333333 ),
vec3( -0.816497, -0.471405, -0.333333 ),
vec3( 0.816497, -0.471405, -0.333333 )
};
divide_tetra( vertices[0], vertices[1], vertices[2], vertices[3],
NumTimesToSubdivide );
for ( int i = 0; i < 64; i++ ) {
for ( int j = 0; j < 64; j++ ) {
GLubyte c = (((i & 0x8) == 0) ^ ((j & 0x8) == 0)) * 255;
image[i][j][0] = c;
image[i][j][1] = c;
image[i][j][2] = c;
image2[i][j][0] = c;
image2[i][j][1] = 0;
image2[i][j][2] = c;
}
}
glGenTextures( 2, textures );
glBindTexture( GL_TEXTURE_2D, textures[0] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0,
GL_RGB, GL_UNSIGNED_BYTE, image );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glBindTexture( GL_TEXTURE_2D, textures[1] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0,
GL_RGB, GL_UNSIGNED_BYTE, image2 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, textures[0] );
GLuint vao;
glGenVertexs( 1, &vao );
glBindVertex( vao );
GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(points) + sizeof(normals)+ sizeof(tex_coords),
NULL, GL_STATIC_DRAW );
GLintptr offset = 0;
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(points), points );
offset += sizeof(points);
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(normals), normals );
offset += sizeof(normals);
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(tex_coords), tex_coords );
GLuint program = InitShader( "vshader4.glsl", "fshader4.glsl" );
glUseProgram( program );
offset = 0;
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttrib( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
offset += sizeof(points);
GLuint vNormal = glGetAttribLocation( program, "vNormal" );
glEnableVertexAttrib( vNormal );
glVertexAttribPointer( vNormal, 3, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
offset += sizeof(normals);
GLuint vTexCoord = glGetAttribLocation( program, "vTexCoord" );
glEnableVertexAttrib( vTexCoord );
glVertexAttribPointer( vTexCoord, 2, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
glUniform1i( glGetUniformLocation(program, "texture"), 0 );
color4 light_ambient( 0.2, 0.2, 0.2, 1.0 );
color4 light_diffuse( 1.0, 1.0, 1.0, 1.0 );
color4 light_specular( 1.0, 1.0, 1.0, 1.0 );
color4 material_ambient( 1.0, 0.0, 1.0, 1.0 );
color4 material_diffuse( 1.0, 0.8, 0.0, 1.0 );
color4 material_specular( 1.0, 0.0, 1.0, 1.0 );
float material_shininess = 5.0;
color4 ambient_product = light_ambient * material_ambient;
color4 diffuse_product = light_diffuse * material_diffuse;
color4 specular_product = light_specular * material_specular;
glUniform4fv( glGetUniformLocation(program, "AmbientProduct"),
1, ambient_product );
glUniform4fv( glGetUniformLocation(program, "DiffuseProduct"),
1, diffuse_product );
glUniform4fv( glGetUniformLocation(program, "SpecularProduct"),
1, specular_product );
// glUniform4fv( glGetUniformLocation(program, "LightPosition"),
// 1, light_position );
glUniform1f( glGetUniformLocation(program, "Shininess"),
material_shininess );
ModelView = glGetUniformLocation( program, "ModelView" );
Projection = glGetUniformLocation( program, "Projection" );
LightPosition = glGetUniformLocation( program, "LightPosition" );
glUniform4fv( LightPosition ,1,light_position);
glEnable( GL_DEPTH_TEST );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
point4 eye( x,y,z,1.0 );
point4 at( LeftOrRight, UpOrDown, 0.0, 1.0 );
vec4 up( 0.0, 1.0, 0.0, 0.0 );
mat4 model_view = LookAt( eye, at, up );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view );
mat4 p = Ortho( -1.0, 2.5, -1.0, 2.5, 1.0, 100);
glUniformMatrix4fv( Projection, 1, GL_TRUE, p );
glDraws( GL_TRIANGLES, 0, NumVertices );
glutSwapBuffers();
}
void
keyboard( unsigned char key, int MM, int VB )
{
if(key == 'q' || key == 'Q') exit( EXIT_SUCCESS );
//漫游
if(key == 'D' || key == 'd') LeftOrRight += 0.1;
if(key == 'A' || key == 'a') LeftOrRight -= 0.1;
if(key == 'W' || key == 'w') UpOrDown += 0.1;
if(key == 'S' || key == 's') UpOrDown -= 0.1;
//环视
if(key == 'J' || key == 'j'){
// if(y>1.0) y =0;
y += 0.1;
}
if(key == 'K' || key == 'k'){
y -= 0.1;
}
if(key == 'U' || key == 'u'){
//if(z>=0.7)
z -= 0.1;
}
if(key == 'I' || key == 'i'){
z += 0.1;
}
if(key == 'N' || key == 'n'){
x -= 0.1;
}
if(key == 'M' || key == 'm'){
x += 0.1;
}
if(key == 'B' || key == 'b')
{
LeftOrRight = 0.0;
UpOrDown = 0.0;
x = 0.0;
y = 0.0;
z = 1.0;
//light_position( 0.0, 0.0, 2.0, 0.0 );
light_position[0] = a;
light_position[1] = b;
light_position[2] = c;
glUniform4fv( LightPosition ,1,light_position);
}
if(key =='1'){
flag1 = !flag1;
if(flag1){
glBindTexture( GL_TEXTURE_2D, textures[0] );
}
else{
glBindTexture( GL_TEXTURE_2D, textures[1] );
}
}
glutPostRedisplay();
}
void special(int key,int x,int y){
if(key == GLUT_KEY_SHIFT_L){
flag2 = !flag2;
}
}
void mouse(int key,int state,int x,int y){
glEnable(GL_LIGHTING);
if(key == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
if(flag2){
light_position[0]++;
}
else{
light_position[0]--;
}
}
if(key == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN){
if(flag2){
light_position[1]++;
}
else{
light_position[1]--;
}
}
if(key == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
if(flag2){
light_position[2]++;
}
else{
light_position[2]--;
}
}
glUniform4fv( LightPosition ,1,light_position);
glutPostRedisplay();
}
void
reshape( int width, int height )
{
glViewport( 0, 0, width, height );
GLfloat left = -2.0, right = 2.0;
GLfloat top = 2.0, bottom = -2.0;
GLfloat zNear = -20.0, zFar = 20.0;
GLfloat aspect = GLfloat(width)/height;
if ( aspect > 1.0 ) {
left *= aspect;
right *= aspect;
}
else {
top /= aspect;
bottom /= aspect;
}
mat4 projection = Ortho( left, right, bottom, top, zNear, zFar );
glUniformMatrix4fv( Projection, 1, GL_TRUE, projection );
}
int
main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH );
glutInitWindowSize( 640, 640 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "Exe4" );
glewExperimental = true;
glewInit();
init();
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutKeyboardFunc( keyboard );
glutSpecialFunc(special);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
片元着色器(fshader):
#version 150
// per-fragment interpolated values from the vertex shader
in vec3 fN;
in vec3 fL;
in vec3 fE;
in vec4 color;
in vec2 texCoord;
out vec4 fColor;
uniform vec4 AmbientProduct, DiffuseProduct, SpecularProduct;
uniform mat4 ModelView;
uniform vec4 LightPosition;
uniform float Shininess;
uniform sampler2D texture;
void main()
{
// Normalize the input lighting vectors
vec3 N = normalize(fN);
vec3 E = normalize(fE);
vec3 L = normalize(fL);
vec3 H = normalize( L + E );
vec4 ambient = AmbientProduct;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd*DiffuseProduct;
float Ks = pow(max(dot(N, H), 0.0), Shininess);
vec4 specular = Ks*SpecularProduct;
// discard the specular highlight if the light's behind the vertex
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
fColor = ambient + diffuse + specular;
fColor.a = 1.0;
fColor += color * texture2D( texture, texCoord );
}
顶点着色器(vshader):
#version 150
in vec4 vPosition;
in vec3 vNormal;
in vec4 vColor;
in vec2 vTexCoord;
// output values that will be interpretated per-fragment
out vec3 fN;
out vec3 fE;
out vec3 fL;
out vec4 color;
out vec2 texCoord;
uniform mat4 ModelView;
uniform vec4 LightPosition;
uniform mat4 Projection;
void main()
{
fN = vNormal;
fE = vPosition.xyz;
fL = LightPosition.xyz;
if( LightPosition.w != 0.0 ) {
fL = LightPosition.xyz - vPosition.xyz;
}
color = vColor;
texCoord = vTexCoord;
gl_Position = Projection*ModelView*vPosition;
}
四、 实验结果与分析(包括功能说明、操作说明)
实现功能:
绘制一个由细分四面体得到的三维镂垫;
光源: 在场景中添加一个点光源;通过鼠标点击左键,中间和右键来改变光源位置,左SHIFT可以切换点击时如何改变,相当于有6个改变光源位置的不同按键。
纹理:按键‘1’用来切换两种不同的纹理类型;似乎是光照的影响,纹理的效 果不能明显的看出来
摄像漫游:通过键盘W、S、A和D键来前后左右地移动摄像机;
摄像机环视:U、I,J、K,N、M键旋转摄像机环顾四周;
按键B进行初始化,按键Q退出程序。
五、 实验心得(自我评价)与建议
通过此次实验,我对OPENGL的光照模型和纹理映射有了一定的了解,在实现修改光源位置功能的时候遇到了很多困难,虽然最后解决了问题,还是有一些不足,同时对于纹理映射明白得不够透彻,在今后的学习中,我将继续深入探讨OPENGL的奥秘。