实验三:场景漫游
win8.1+VS2013+GLUT
#include <math.h>
#include <glut.h>
#include <stdio.h>
#include<iostream>
#include <Windows.h>
// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include<vector>
using namespace std;
#define BMP_Header_Length 54
/////设计目标/////////
//纹理贴图(内侧)√
//设置光源
//层次建模建立三维模型(桌椅)√
//扫面建模(花瓶)
//几何变换(放在桌子上)
//交互控制及观察√
//简单光照明(添加屋顶灯光)
//阴影计算
//光线跟踪算法,全局光照明
//场景漫游√
//地球仪(底座、支撑杆、地球)
//读取dragon.odj
/////////////////////
GLfloat EyeX = 5.0;
GLfloat EyeY = 0.0;
GLfloat EyeZ = 0.0;
GLfloat RdegreeX = 0.0;
GLfloat RdegreeZ = 0.0;
float PI = 3.14159f;
static int du=90,oldmy=-1,oldmx=-1; //du是视点绕y轴的角度,opengl里
默认y轴是上方向
//场景漫游变量
// 追踪观察点的方向
static GLfloat s_eye[] = { 17.0,-3.0,0.0 };
static GLfloat s_at[] = { 0.0, -3.0,0.0 };
static GLfloat s_angle = -180.0;
//如果初始角度设置为0则初始面向X轴正方向,设置
//为-90面向Z轴负方向,符合默认情况下的设计习惯。
float rad;
float speed = 0.5; //漫游速度
//灯光位置
GLfloat position_light[] = {10,2,22}; //x,y,z
//贴图变量
GLint room_ground; //地面
GLint room_wall; //墙
GLint room_up; //房顶
GLint desk; //桌子
GLint chair; //椅子
GLint map; //地图
GLint vase; //花瓶
GLint dizuo; //地球仪底座
GLint w,h,total_bytes;
GLbyte *pixels = 0;
GLint last_texture_ID;
GLuint texture_ID = 0;
//带贴图的正方体
void MyCube(float size ,GLint tex){
glTranslatef(0.0,0.0,0.0); //整体平移桌子
glScalef(size/2, size/2, size/2);
// glColor4f(1.0,1.0,1.0,1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glPushMatrix();
//-z
glBegin(GL_POLYGON);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( -
1.0, -1.0, -1.0 );
glTexCoord2f( 1.0, 0.0 ); glVertex3f(
1.0, -1.0, -1.0 );
glTexCoord2f( 1.0, 1.0 ); glVertex3f(
1.0, 1.0, -1.0 );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( -
1.0, 1.0, -1.0 );
glEnd();
//z
glBegin(GL_POLYGON);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( -
1.0, -1.0, 1.0 );
glTexCoord2f( 1.0, 0.0 ); glVertex3f(
1.0, -1.0, 1.0 );
glTexCoord2f( 1.0, 1.0 ); glVertex3f(
1.0, 1.0, 1.0 );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( -
1.0, 1.0, 1.0 );
glEnd();
//-y
glBegin(GL_POLYGON);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( -
1.0, -1.0, -1.0 );
glTexCoord2f( 1.0, 0.0 ); glVertex3f(
1.0, -1.0, -1.0 );
glTexCoord2f( 1.0, 1.0 ); glVertex3f(
1.0, -1.0, 1.0 );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( -
1.0, -1.0, 1.0 );
glEnd();
//y
glBegin(GL_POLYGON);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( -
1.0, 1.0, -1.0 );
glTexCoord2f( 1.0, 0.0 ); glVertex3f(
1.0, 1.0, -1.0 );
glTexCoord2f( 1.0, 1.0 ); glVertex3f(
1.0, 1.0, 1.0 );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( -
1.0, 1.0, 1.0 );
glEnd();
//-x
glBegin(GL_POLYGON);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( -
1.0, -1.0, -1.0 );
glTexCoord2f( 1.0, 0.0 ); glVertex3f( -
1.0, 1.0, -1.0 );
glTexCoord2f( 1.0, 1.0 ); glVertex3f( -
1.0, 1.0, 1.0 );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( -
1.0, -1.0, 1.0 );
glEnd();
//x
glBegin(GL_POLYGON);
glTexCoord2f( 0.0, 0.0 ); glVertex3f(
1.0, -1.0,-1.0 );
glTexCoord2f( 1.0, 0.0 ); glVertex3f(
1.0, 1.0,-1.0 );
glTexCoord2f( 1.0, 1.0 ); glVertex3f(
1.0, 1.0, 1.0 );
glTexCoord2f( 0.0, 1.0 ); glVertex3f(
1.0, -1.0, 1.0 );
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
//贴图练习
void DrawMf(void){
float xishu=1; //贴图数量比例
glRotatef(90.0, 1.0, 0.0, 0.0);
glTranslatef(4.0,0.0,0.0 );
glColor4f(0,0,0,1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, room_ground);
glPushMatrix();
glBegin(GL_POLYGON);
glTexCoord2f( 0, 0.0 ); glVertex3f( -
10.0,10.0, -10.0 );
glTexCoord2f( xishu*1.0, 0.0 );
glVertex3f( 10.0,10.0, -10.0 );
glTexCoord2f( xishu*1.0, xishu*1.0 );
glVertex3f( 10.0,10.0, 10.0 );
glTexCoord2f( 0, xishu*1.0 ); glVertex3f(
-10.0,10.0, 10.0 );
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
//屋顶灯
void DrawLight(void){
glPushMatrix();
glTranslatef(0,0,30);
glScalef(8, 8, 0.8);
glutSolidCube(1.0); //测试灯光用的立方
体
glPopMatrix();
}
//房间
void DrawRoom(void){
//地面
glPushMatrix();
glTranslatef(0.0,0.0,-3.0); //整体平移
glScalef(80,80,0.2);
MyCube(1.0,room_ground);
glPopMatrix();
//墙
//1右
glPushMatrix();
glTranslatef(40.0,0.0,14.0); //整体平移
glScalef(0.2,80,35);
MyCube(1.0,room_wall);
glPopMatrix();
//2左
glPushMatrix();
glTranslatef(-40.0,0.0,14.0); //整体平移
glScalef(0.2,80,35);
MyCube(1.0,room_wall);
glPopMatrix();
/* //3前
glPushMatrix();
glTranslatef(0.0,-40,14.0); //整体平移
glScalef(80,0.2,35);
MyCube(1.0,room_wall);
glPopMatrix();
*/ //4后
glPushMatrix();
glTranslatef(0.0,40,14.0); //整体平移
glScalef(80,0.2,35);
MyCube(1.0,room_wall);
glPopMatrix();
//房顶
glPushMatrix();
glTranslatef(0.0,0.0,30.0); //整体平移
glScalef(80,80,0.2);
MyCube(1.0,room_up);
glPopMatrix();
}
//椅子
void DrawChair(void){
// glRotatef(90.0, 0.0, 0.0, 1.0);
// glScalef(0.8, 0.8, 0.8);
// glTranslatef(-6.0,0.0,-3.0); //整体平移
glPushMatrix();
//腿
// glColor4f(1,1,1,1.0);
//1
glPushMatrix();
glTranslatef(-1.5,-1.5,1.5);
glScalef(0.2, 0.2, 6);
MyCube(1.0,chair);
glPopMatrix();
//2
glPushMatrix();
glTranslatef(-1.5,1.5,1.5);
glScalef(0.2, 0.2, 6);
MyCube(1.0,chair);
glPopMatrix();
//3
glPushMatrix();
glTranslatef(1.5,1.5,0);
glScalef(0.2, 0.2, 3);
MyCube(1.0,chair);
glPopMatrix();
//4
glPushMatrix();
glTranslatef(1.5,-1.5,0);
glScalef(0.2, 0.2, 3);
MyCube(1.0,chair);
glPopMatrix();
//椅子面
glPushMatrix();
// glColor4f(0.6,1.0,0.0,1.0);
glTranslatef(0.0,0.0,1.5);
glScalef(3.4, 3.4, 0.2);
MyCube(1.0,chair);
glPopMatrix();
//椅子靠背
glPushMatrix();
glTranslatef(-1.5,0.0,3.7);
glScalef(0.1, 3.4, 1.5);
MyCube(1.0,chair);
glPopMatrix();
glPopMatrix();
}
//桌子
void DrawDesk(void){
glPushMatrix();
//桌子腿
glTranslatef(0.0,0.0,-3.0);
// glColor4f(0.914,0.467,0.192,1.0); //桌子腿的
颜色
//1
glPushMatrix();
glTranslatef(3.0,3.0,0.0);
glPushMatrix();
/*参数1(1.0F)是圆柱体的底面半径
,参数2(1.0F)
是圆柱体的饿顶面半径,参数3(3.0F
)是圆柱体的高度。
参数4(32)是纬线(环绕Z轴有多少细
分),参数5(32)
是经线(沿着Z轴有多少细分)*/
gluCylinder(gluNewQuadric
(),0.5,0.2,3.0,20,20);
glPopMatrix();
glPopMatrix();
//2
glPushMatrix();
glTranslatef(-3.0,3.0,0.0);
glPushMatrix();
gluCylinder(gluNewQuadric
(),0.5,0.2,3.0,20,20);
glPopMatrix();
glPopMatrix();
//3
glPushMatrix();
glTranslatef(-3.0,-3.0,0.0);
glPushMatrix();
gluCylinder(gluNewQuadric
(),0.5,0.2,3.0,20,20);
glPopMatrix();
glPopMatrix();
//4
glPushMatrix();
glTranslatef(3.0,-3.0,0.0);
glPushMatrix();
gluCylinder(gluNewQuadric
(),0.5,0.2,3.0,20,20);
glPopMatrix();
glPopMatrix();
//桌子面
glTranslatef(0.0,0.0,3.0);
// glColor4f(0.0,1.0,0.8,1.0);
glPushMatrix();
glScalef (8.0, 8.0, 0.2);
MyCube(1.0,desk);
glPopMatrix();
glPopMatrix();
}
//画花瓶
//用四边形带画花瓶的一层,该层上底面圆心坐标为(x,y,z),上底面
圆的半径为radius_up,下底面圆的半径为radius_down,M表示圆周的被分
成多少份,yy_down代表下圆面y值
void DrawVase_one(GLfloat xx, GLfloat yy_up, GLfloat zz, GLfloat
radius_up, GLfloat radius_down, GLfloat M, GLfloat yy_down,
GLfloat tt,GLfloat VaseN,GLint tex){
float step_z = 2*PI/M; //角度步长
float x[4],y[4],z[4];
float angle_z = 0.0; //角度
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
for(float i=0; i<M; i++)
{
angle_z = i * step_z;
x[0] = radius_up * sin(angle_z);
y[0] = yy_up;
z[0] = radius_up * cos(angle_z);
x[1] = radius_up * sin(angle_z + step_z);
y[1] = yy_up;
z[1] = radius_up * cos(angle_z + step_z);
x[2] = radius_down * sin(angle_z +
step_z);
y[2] = yy_down;
z[2] = radius_down * cos(angle_z +
step_z);
x[3] = radius_down * sin(angle_z);
y[3] = yy_down;
z[3] = radius_down * cos(angle_z);
glTexCoord2f( i/M, 1-tt/VaseN );
glVertex3f(xx+x[0], yy_up+y[0],zz+z[0]);
glTexCoord2f( (i+1)/M, 1-tt/VaseN );
glVertex3f(xx+x[1], yy_up+y[1],zz+z[1]);
glTexCoord2f( (i+1)/M, 1-(tt+1)/VaseN );
glVertex3f(xx+x[2], yy_up+y[2],zz+z[2]);
glTexCoord2f( i/M, 1-(tt+1)/VaseN );
glVertex3f(xx+x[3], yy_up+y[3],zz+z[3]);
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
//花瓶
void DrawVase(void){
float Hight=3; //花瓶高度
float VaseY_0;
int VaseN=30; //花瓶竖直方向细分数
float hh; //Y方向步长
float radius_down;
float radius_up;
VaseY_0=Hight/2;
hh=Hight/VaseN;
radius_down=VaseY_0;
glPushMatrix();
glTranslatef(8.0,0,5.5);
glRotatef(90, 1.0, 0.0, 0.0);
// glColor4f(1,1,1,1.0);
glScalef(0.7, 0.8, 0.7);
for(int tt=0;tt < VaseN;tt++){
radius_up=radius_down;
radius_down=VaseY_0-hh*(tt+1);
DrawVase_one(0,radius_up,0,0.7*sinf(2*PI*
(1-hh*tt/Hight))+1.1,0.7*sinf(2*PI*(1-hh*(tt
+1)/Hight))+1.1,200,radius_down-hh,tt,VaseN,vase);
}
glPopMatrix();
}
//地球仪
void DrawMap(void){
float Hight=3; //球体高度
float VaseY_0;
int VaseN=30; //球体竖直方向细分数
float hh; //Y方向步长
float radius_down;
float radius_up;
VaseY_0=Hight/2;
hh=Hight/VaseN;
radius_down=VaseY_0;
glPushMatrix();
glRotatef(90.0, 1.0, 0.0, 0.0);
glTranslatef(4.0,0.8,-3.0);
glScalef(0.5, 0.5, 0.5);
//画球体
glPushMatrix();
// glColor4f(1,1,1,1.0);
glScalef(1, 1, 1);
glRotatef(45.0, 0.0, 1.0, 0.0);
glTranslatef(0.0,9.0,0.0);
for(int tt=0;tt < VaseN;tt++){
radius_up=radius_down;
radius_down=VaseY_0-hh*(tt+1);
DrawVase_one(0,radius_up,0,sqrtf
(pow(Hight,2)-pow((2*Hight*(1-hh*tt/Hight)-Hight),2)),sqrtf(pow
(Hight,2)-pow((2*Hight*(1-hh*(tt+1)/Hight)-
Hight),2)),200,radius_down-hh,tt,VaseN,map);
}
glPopMatrix();
//底座
glPushMatrix();
glScalef(1.2, 0.8, 1.2);
glRotatef(0.0, 0.0, 1.0, 0.0);
glTranslatef(-0.0,5.0,-0.0);
// glColor4f(1,1,1,1.0);
DrawVase_one(0,1,0,0,2,200,0,1,1,dizuo);
glPopMatrix();
//轴
glPushMatrix();
glScalef(1, 1, 1);
glRotatef(0.0, 0.0, 1.0, 0.0);
glTranslatef(-0.0,0.0,0.0);
// glColor4f(1,1,1,1.0);
DrawVase_one
(0,5,0,0.1,0.1,100,0,1,1,dizuo);
glPopMatrix();
glPopMatrix();
}
//导入OBJ文件函数
vector<glm::vec3> vertices;
vector<glm::vec2> uvs;
vector<glm::vec3> normals;
int nodesSize;
bool loadOBJ(
const char * path,
std::vector<glm::vec3> & out_vertices,
std::vector<glm::vec2> & out_uvs,
std::vector<glm::vec3> & out_normals
){
printf("Loading OBJ file %s...\n", path);
std::vector<unsigned int> vertexIndices, uvIndices,
normalIndices;
std::vector<glm::vec3> temp_vertices;
std::vector<glm::vec2> temp_uvs;
std::vector<glm::vec3> temp_normals;
FILE * file = fopen(path, "r");
if( file == NULL ){
printf("Impossible to open the file ! Are you in
the right path ? See Tutorial 1 for details\n");
return false;
}
while( 1 ){
char lineHeader[128];
// read the first word of the line
int res = fscanf(file, "%s", lineHeader);
if (res == EOF)
break; // EOF = End Of File. Quit the
loop.
// else : parse lineHeader
if ( strcmp( lineHeader, "v" ) == 0 ){
//cout<<"Get v"<<endl;
glm::vec3 vertex;
fscanf(file, "%f %f %f\n", &vertex.x,
&vertex.y, &vertex.z );
temp_vertices.push_back(vertex);
}else if ( strcmp( lineHeader, "vt" ) == 0 ){
//cout<<"Get vt"<<endl;
glm::vec2 uv;
fscanf(file, "%f %f\n", &uv.x, &uv.y );
uv.y = -uv.y; // Invert V coordinate since
we will only use DDS texture, which are inverted. Remove if you
want to use TGA or BMP loaders.
temp_uvs.push_back(uv);
}else if ( strcmp( lineHeader, "vn" ) == 0 ){
//cout<<"Get vn"<<endl;
glm::vec3 normal;
fscanf(file, "%f %f %f\n", &normal.x,
&normal.y, &normal.z );
temp_normals.push_back(normal);
}else if ( strcmp( lineHeader, "f" ) == 0 ){
//cout<<"Get f"<<endl;
std::string vertex1, vertex2, vertex3;
unsigned int vertexIndex[3], uvIndex[3],
normalIndex[3];
int matches = fscanf(file, "%d//%d %d//%d
%d//%d\n", &vertexIndex[0], &normalIndex[0], &vertexIndex[1],
&normalIndex[1], &vertexIndex[2], &normalIndex[2]);
if (matches != 6){
printf("File can't be read by our
simple parser :-( Try exporting with other options\n");
return false;
}
vertexIndices.push_back(vertexIndex[0]);
vertexIndices.push_back(vertexIndex[1]);
vertexIndices.push_back(vertexIndex[2]);
normalIndices.push_back(normalIndex[0]);
normalIndices.push_back(normalIndex[1]);
normalIndices.push_back(normalIndex[2]);
}else{
// Probably a comment, eat up the rest of
the line
char stupidBuffer[1000];
fgets(stupidBuffer, 1000, file);
}
}
// For each vertex of each triangle
for( unsigned int i=0; i<vertexIndices.size(); i++ ){
// Get the indices of its attributes
unsigned int vertexIndex = vertexIndices[i];
unsigned int normalIndex = normalIndices[i];
// Get the attributes thanks to the index
glm::vec3 vertex = temp_vertices[ vertexIndex-1 ];
glm::vec3 normal = temp_normals[ normalIndex-1 ];
// Put the attributes in buffers
out_vertices.push_back(vertex);
out_normals .push_back(normal);
}
return true;
}
//画龙
void DrawDragon(void){
glPushMatrix();
glTranslatef(4,-3,4);
glRotated(0,0,0,1);
glRotated(90,1,0,0);
glScalef(2.0,2.0,2.0);
int i;
glBegin(GL_TRIANGLES);
for(i = 0; i<nodesSize; i++)
{
glNormal3f(normals[i].x, normals[i].y,
normals[i].z);
glVertex3f( vertices[i].x, vertices[i].y,
vertices[i].z);
}
glEnd();
glPopMatrix();
}
//实现场景漫游
void WalkMan(void){
rad = float(PI*s_angle / 180.0f); //计
算SIN和COS函数中需要的参数。
// 观察点
s_at[0] = float(s_eye[0] + 100 * cos(rad));
s_at[2] = float(s_eye[2] + 100 * sin(rad));
s_at[1] = s_eye[1];
//观察点可以设置的更远一些,如果设置的更小可能导致不能看到
较远的物体,也是通过sin和cos函数实现
//向前进方向去设置观察点。
// 设置观察点
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(s_eye[0], s_eye[1], s_eye[2],
s_at[0], s_at[1], s_at[2],
0.0, 1.0, 0.0);
}
//阴影
void pointSourceShadow( double lx, double ly, double lz,
double a, double b, double c, double d, GLfloat M[16]) {
double new_d = d + (a * lx + b * ly + c * lz);
M[0] = 1; M[4] = 0; M[8] = 0;
M[12] = 0;
M[1] = 0; M[5] = 1; M[9] = 0;
M[13] = 0;
M[2] = 0; M[6] = 0; M[10] = 1;
M[14] = 0;
M[3]= -a/new_d; M[7]= -b/new_d; M[11]= -c/new_d; M[15] =
0;
}
void myDisplay(void)
{
GLfloat position0[]={position_light[0],position_light
[1],position_light[2],0}; //光源位置,最后一位 0:
光源类型为方向光
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
WalkMan(); //通过改变摄像机的位置来实
现场景漫游
//绘制立方体
glColor4f(1.0,1.0,1.0,1.0);
glRotatef(RdegreeZ, 0.0, 1.0, 0.0);
glRotatef(RdegreeX, 1.0, 0.0, 0.0);
glColor4f(1.0,1.0,1.0,1.0);
glRotatef(-90.0, 1.0, 0.0, 0.0);
glTranslatef(-5.0,0.0,-5.0); //整体平移
桌子
DrawDesk(); //桌子
glColor4f(1.0,1.0,1.0,1.0);
glRotatef(90.0, 0.0, 0.0, 1.0);
glScalef(0.8, 0.8, 0.8);
glTranslatef(-6.0,0.0,-3.0); //整体平移
DrawChair(); //椅子
glColor4f(1.0,1.0,1.0,1.0);
DrawRoom(); //房间
glColor4f(1.0,1.0,1.0,1.0);
DrawMap(); //地球仪
glColor4f(1,0,0,1.0);
DrawDragon(); //画龙
glColor4f(1.0,1.0,1.0,1.0);
DrawVase(); //花瓶
glColor4f(1.0,1.0,1.0,1.0);
DrawLight(); //屋顶灯
glPushMatrix();
glTranslatef(position_light
[0],position_light[1],position_light[2]);
glRotated(0,0,0,0);
glutSolidCube(1.0); //测试灯光用的立方
体
glPopMatrix();
//阴影
GLfloat M[16];
double light_x = position_light[0], light_y =
position_light[1],light_z = position_light[2];
glPushMatrix();
glPushMatrix();
glDisable( GL_LIGHTING);
glDisable(GL_LIGHT0);
glColor4f( 0.2, 0.2, 0.2, 0.3);
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
glTranslatef( light_x, light_y, light_z);
pointSourceShadow( light_x, light_y,
light_z, 0, 0, 1, -3.2, M);
glMultMatrixf( M);
glTranslatef( -light_x, -light_y, -
light_z);
DrawMap(); //地球仪
DrawVase(); //花瓶
DrawDragon(); //画龙
glPopMatrix();
//glPushMatrix();
// glDisable( GL_LIGHTING);
// glDisable(GL_LIGHT0);
// glColor4f( 0, 0, 0, 1);
// //glMatrixMode(GL_MODELVIEW);
// //glLoadIdentity();
// glTranslatef( light_x, light_y, light_z);
// pointSourceShadow( light_x, light_y,
light_z, 0, 0, 1, 2.5, M);
// glMultMatrixf( M);
// glTranslatef( -light_x, -light_y, -
light_z);
// glPushMatrix();
// DrawDesk(); //
桌子
// glPopMatrix();
// DrawChair(); //椅子
//glPopMatrix();
glPopMatrix();
glEnable(GL_LIGHTING); //启用光源
glEnable(GL_LIGHT0); //使用指定灯光
glLightfv(GL_LIGHT0,GL_POSITION,position0); //
设置光源位置
printf("x=%f \t",position_light[0]); printf("y=%f
\t",position_light[1]); printf("z=%f \n",position_light[2]); //
输出灯光位置
glPopMatrix();
glutSwapBuffers();//双缓存刷新
}
//贴图
GLint load_texture(const char *file_name)
{
FILE* pFile = fopen(file_name, "rb"); //读取图片
if( pFile == 0 ) {return 0;}
fseek(pFile, 0x0012, SEEK_SET);//移动到0x0012位置
fread(&w, 4, 1, pFile);//读取宽度
fread(&h, 4, 1, pFile);//读取高度
fseek(pFile, BMP_Header_Length, SEEK_SET);//跳过BMP头部的
54个字节,这些字节我们不用
GLuint line_bytes = w * 3;//BMP里一个像素3字节
while( line_bytes % 4 != 0 ) {++line_bytes;}//补齐成4的倍
数
total_bytes = line_bytes * h;
pixels = (GLbyte*)malloc(total_bytes);//分配内存
if( pixels == 0 )
{
fclose(pFile); return 0;
}
if( fread(pixels, total_bytes, 1, pFile) <= 0 ) { free
(pixels); fclose(pFile); return 0; }
glGenTextures(1, &texture_ID);//创建新纹理并标记
if( texture_ID == 0 ) { free(pixels); fclose(pFile);
return 0; }
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);
glBindTexture(GL_TEXTURE_2D, texture_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT);
GLfloat blend[] = {1.0,1.0,1.0,1.0};
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, blend);//
最后一个参数必须为GL_BLEND才能实现光照和纹理融合
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
glBindTexture(GL_TEXTURE_2D, last_texture_ID);
free(pixels);//释放内存
return texture_ID;
}
//鼠标事件
void Mouse(int button, int state, int x, int y) //处理鼠标点击
{
if(state==GLUT_DOWN){ //第一次鼠标按下时,记录鼠标在窗口中的初
始坐标
oldmx=x,oldmy=y;
printf("%s \n", "this is mouse");
}
}
//鼠标移动事件
void onMouseMove(int x,int y) //处理鼠标拖动
{
s_angle += (x-oldmx);
oldmx=x,oldmy=y; //把此时的鼠标坐标作为旧值,为下一次计算增量
做准备
glutPostRedisplay();
}
//键盘控制
void keyboard(unsigned char key, int x, int y){
switch (key)
{
case'q':
// printf("%s \n", "this is Q");
position_light[0]-=1;
//如果按上方向键,沿着转换角度后的方向前进,speed
为每次前进的步长,通过sin和cos函数实现沿着现
//有角度方向前进。
glutPostRedisplay();
break;
case'w':
// printf("%s \n", "this is W");
position_light[0]+=1;
//如果按上方向键,沿着转换角度后的方向前进,speed
为每次前进的步长,通过sin和cos函数实现沿着现
//有角度方向前进。
glutPostRedisplay();
break;
case's':
// printf("%s \n", "this is S");
position_light[1]+=1;
//如果按上方向键,沿着转换角度后的方向前进,speed
为每次前进的步长,通过sin和cos函数实现沿着现
//有角度方向前进。
glutPostRedisplay();
break;
case'a':
// printf("%s \n", "this is A");
position_light[1]-=1;
glutPostRedisplay();
break;
case'd':
printf("%s \n", "this is D");
glutPostRedisplay();
break;
case'z':
// printf("%s \n", "this is Z");
position_light[2]-=1;
glutPostRedisplay();
break;
case'x':
// printf("%s \n", "this is X");
position_light[2]+=1;
glutPostRedisplay();
break;
default:
break;
}
}
//键盘方向键控制
void mySpecial(int key, int x, int y){
switch (key)
{
case GLUT_KEY_UP:
// printf("%s \n", "this is up");
// RdegreeX += 5.0;
s_eye[2] += (float)sin(rad) * speed;
s_eye[0] += (float)cos(rad) * speed;
//如果按上方向键,沿着转换角度后的方向前进,speed
为每次前进的步长,通过sin和cos函数实现沿着现
//有角度方向前进。
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
// printf("%s \n", "this is down");
// RdegreeX -= 5.0;
s_eye[2] -= (float)sin(rad) * speed;
s_eye[0] -= (float)cos(rad) * speed;
//如果按下方向键,沿着转换角度后的方向后退,speed
为每次前进的步长,通过sin和cos函数实现沿着现
//有角度方向前进。
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
// printf("%s \n", "this is left");
// RdegreeZ += 5.0;
s_angle -= 2.0; //每按一次
左键,旋转2度。
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
// printf("%s \n", "this is right");
// RdegreeZ -= 5.0;
s_angle += 2.0; //每按一次右
键,旋转2度。
glutPostRedisplay();
break;
}
}
//初始化函数
void init(){
//更改清屏颜色
glClearColor(0.0, 0.0, 0.0, 0.0);//黑色
glClearDepth(1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(75,1,0.1,1000); //视景体(摄像机)参数:60
度+长宽比=1+近点=1+远点=100
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
WalkMan();
glEnable(GL_DEPTH_TEST); //隐藏面消除
//贴图图片
room_ground = load_texture("地板.bmp");
room_wall= load_texture("墙.bmp");
room_up=load_texture("屋顶.bmp");
desk= load_texture("木纹_桌子.bmp");
chair= load_texture("木纹_椅子.bmp");
map= load_texture("地图.bmp");
vase= load_texture("花瓶.bmp");
dizuo=load_texture("底座.bmp");
//材质
GLfloat diffuseMaterial[]={0.5,0.5,0.5,1.0};
GLfloat mat_specular[]={1.0,1.0,1.0,1.0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuseMaterial);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialf(GL_FRONT,GL_SHININESS,25.0);
glEnable(GL_COLOR_MATERIAL); //启动颜色追踪
//灯光
glShadeModel(GL_SMOOTH);
//GL_SMOOTH:光滑明暗处理
//glEnable(GL_BLEND); //
启用颜色混合
//设置普通灯光照0位置及参数
GLfloat position0[]={position_light[0],position_light
[1],position_light[2],1};
/*光源位置,最后一位 0:方向光(线光源) 1:无方向(点光源
)
position的第四个分量如果是0,那么光源就是directional的,
postion值实际是一个向量;
否则这个光源就是postional,position就是他的位置。光源的位
置和方向都会受ModelView Matrix的影响。*/
GLfloat light0s[]={1,1,1,1}; //RGBA下的镜面光
GLfloat light0d[]={1,1,1,1}; //RGBA下的漫反射光
GLfloat light0a[]={1,1,1,1}; //RGBA下的环境光
GLfloat light_Model_Ambient[]={0.2,0.2,0.2,1.0};
glLightModelfv( GL_LIGHT_MODEL_AMBIENT ,
light_Model_Ambient ); //设置全局环境光的方法
glLightfv(GL_LIGHT0,GL_POSITION,position0); //
设置光源位置
glLightfv(GL_LIGHT0,GL_SPECULAR,light0s);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light0d);
glLightfv(GL_LIGHT0,GL_AMBIENT,light0a);
//聚光灯参数设置
//glLightf( GL_LIGHT0,GL_SPOT_CUTOFF , 45.0 ); //
灯锥张角
//GLfloat spot_direction[]={ 0.0 , 0.0 , -1.0 };
//聚光灯朝向
//glLightfv( GL_LIGHT0 , GL_SPOT_DIRECTION ,
spot_direction );
//glLightf( GL_LIGHT0 , GL_SPOT_EXPONENT , 0 ); //设置聚光
指数 聚光指数控制光的集中程度,光锥中心的光强最大,越靠边的光强越
小。缺省时为0,即均匀照射。
glEnable(GL_LIGHTING); //启用光源
glEnable(GL_LIGHT0); //使用指定灯光
// glDisable(GL_LIGHTING); //关闭光源
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(300, 50);
glutInitWindowSize(600, 600);
glutCreateWindow("hp_CG_03_三维场景");
init();
glutDisplayFunc(&myDisplay);
glutKeyboardFunc(keyboard);
glutMouseFunc(Mouse);
glutMotionFunc(onMouseMove);
glutSpecialFunc(mySpecial);
//导入OBJ文件
bool res = loadOBJ("dragon.obj", vertices, uvs, normals);
cout<<vertices.size()<<endl;
nodesSize = vertices.size();
glutMainLoop();
return 0;
}