您的位置:首页 > 运维架构

OpenGL学习记录6

2014-04-20 17:29 357 查看
Exercise 6:放大镜功能

要求:

1. 在练习5的基础上,实现放大镜功能,放大场景中的任意部分;

2. 放大镜可以通过鼠标键盘进行控制;

考察目的:

1. 对OpenGL坐标系变换的理解;

by/scu xx

#include <iostream>
#include <gl\glew.h>
#include <glut.h>
#include <windows.h>

#pragma comment( lib, "glew32.lib")

using namespace std;

bool isRotatef;  // 控制要旋转整个视图
GLfloat LightPosition[] = {4.0f, 4.0f, 6.0f, 1.0f}; //点光源的位置

static int mousePosX = 0, mousePosY = 0, tempX, tempY;

bool isMosDownMove = false;//鼠标按下时是否移动的判断变量

///放大镜所需变量
GLuint framebuffer, renderbuffer;//声明FBO缓冲区名称
float MagnifierSize = 80;
float MagnifierRation = 20;
int mouseCurPosX = 0;
int mouseCurPosY = 0;
const int WIN_WIDTH = 800;
const int WIN_HEIGHT = 600;
bool isOpenMagnifier = false;

bool initFBO()
{
glEnable(GL_DEPTH_TEST);

//分配1个帧缓冲区对象名字,并且在framebuffer中返回这个名字,即创建FBO,生成FBO缓冲区名称
glGenFramebuffersEXT(1, &framebuffer);

//指定一个帧缓冲区对象用于读取或写入
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);

//判定一个特定的无符号整数是否是应用程序分配的一个帧缓冲区对象
//如果framebuffer是glGenFramebuffersEXT()返回的一个缓冲区的名字,将返回GL_TRUE
if (glIsFramebufferEXT(framebuffer) != GL_TRUE)
{
return false;
}

//分配一个未使用的渲染缓冲区的对象名,并把名字返回到renderbuffer中,即创建一个渲染缓冲区对象
glGenRenderbuffersEXT(1, &renderbuffer);
//影响一个渲染缓冲区的创建与修改它相关的状态
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer);
if (glIsRenderbufferEXT(renderbuffer) != GL_TRUE)
{
return false;
}
//分配存储空间存储图像数据,这里是把渲染缓冲区用做深度缓冲区
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, MagnifierSize, MagnifierSize);

//检查帧缓冲区是否完整
if (!glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_COMPLETE_EXT))
{
return false;
}
//一旦为渲染缓冲区创建了存储空间,需要将其附加到一个帧缓冲区对象,然后才能像其中渲染
//把渲染缓冲区绑定到帧缓冲区对象,即把renderbuffer和当前绑定的帧缓冲区(framebuffer)对象附加联系起来
glFramebufferRenderbufferEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, renderbuffer);

return true;
}

void createLight()
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
GLfloat LightAmbient[]= { 0.0f, 0.5f, 0.5f, 1.0f }; //环境光参数
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; //漫射光参数(由参数可知识最亮的漫射光)
GLfloat LightSpecular[]= { 0.5f, 0.5f, 0.0f, 1.0f }; //镜面光参数
//指定光源属性,3个参数决定了它所指定的哪个光源的属性、具体的属性以及该属性的预想值
glLightfv(GL_LIGHT0, GL_AMBIENT,  LightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE,  LightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpecular);

}

void init(void)
{
glClearColor(0.7f, 0.7f, 0.7f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);

if (GLEW_OK != glewInit()) {
cout << "Fail to initialize GLEW!\n";
exit(1);
}

createLight();
isRotatef = true; //默认移动鼠标旋转整个视图
}

void display(void)
{
GLfloat mat_emission1[] = { 0.8, 0.8, 0.8, 1.0 };
GLfloat mat_diffuse1[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_emission2[] = { 0.0, 0.8, 0.8, 0.6 };
GLfloat mat_diffuse2[] = { 0.0, 0.3, 0.3, 0.6 };
GLfloat mat_emission3[] = { 0.4, 0.4, 0.0, 0.4 };
GLfloat mat_diffuse3[] = { 0.6, 0.6, 0.0, 0.4 };
GLfloat mat_emission4[] = { 0.75, 0.75, 0.0, 0.5 };
GLfloat mat_diffuse4[] = { 0.4, 0.0, 0.4, 0.5 };
GLfloat mat_emission5[] = { 0.9, 0.9, 0.0, 0.6 };
GLfloat mat_diffuse5[] = { 0.0, 0.0, 0.0, 0.6 };
GLfloat mat_emission6[] = { 0.0, 0.6, 0.6, 1.0 };
GLfloat mat_diffuse6[] = { 0.0, 0.0, 0.0, 1.0 };

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//进行视图变换前调用下面两个函数,接下来的变换函数将影响模型变换矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//3组参数:指定了观察点的位置,定义照相机瞄准的参考点,提示哪个方向是朝上的(3个为一组)
//设置照相机的位置  b
gluLookAt(0.0f, 0.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0);

//通过平移与旋转按照预想的方式移动观察点
//glTranslatef(0.0f, 0.0f, 0.0f);

/*************************************点光源的处理***********************************************/
//复制一份当前矩阵,并把这份复制添加到堆栈的顶部(记住自己的位置)
glPushMatrix();
glTranslatef(LightPosition[0], LightPosition[1], LightPosition[2]);

//用于渲染一个球体 函数原型void glutSolidSphere(GLdouble radius , GLint slices , GLint stacks);
//radius球体的半径
//slices以Z轴上线段为直径分布的圆周线的条数(将Z轴看成地球的地轴,类似于经线)
//stacks围绕在Z轴周围的线的条数(类似于地球上纬线)
//一般而言, 后两个参数赋予较大的值, 渲染花费的时间要长, 效果更逼真
glutSolidSphere(0.1, 10.0, 10.0);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
glPopMatrix(); //丢弃堆栈顶部的那个矩阵(回到原来的位置)

if (isRotatef)  //判断是否需要旋转视图
{
glRotatef((GLfloat) mousePosX, -1.0, 0.0, 0.0);
glRotatef((GLfloat) mousePosY, 0.0, -1.0, 0.0);
}

/****************************************茶壶1************************************************/
glPushMatrix();
glTranslatef(-4.0f, 0.0f, 0.0f);//设定茶壶的初始位置
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse1);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);//控制深度缓冲区是否可写
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//选择源混合因子与目标混合因子
glutSolidTeapot(0.8);//显示一个茶壶,参数为茶壶的大小
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();

/****************************************茶壶2************************************************/
glPushMatrix();
glTranslatef(0.0f, 3.0f, -2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission2);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse2);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();

/****************************************茶壶3************************************************/
glPushMatrix();
glTranslatef(4.0f, 0.0f, 0.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission3);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse3);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();

/****************************************茶壶4************************************************/
glPushMatrix();
glTranslatef(0.0f, -3.0f, 2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission4);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse4);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();

/****************************************茶壶5************************************************/
glPushMatrix();
glTranslatef(-8.0f, -3.0f, 2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission5);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse5);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();

/****************************************茶壶6************************************************/
glPushMatrix();
glTranslatef(8.0f, -3.0f, 2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission6);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse6);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();

if (isOpenMagnifier)
{
float mouseY = WIN_HEIGHT - mouseCurPosY;

//指定了读取操作的源(0表示窗口系统默认缓冲区)
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
//指定帧缓冲区要渲染的目标framebuffer
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, framebuffer);
//前4个参数表示复制的区域,即复制的源
//中间四个参数表示复制到的区域,即复制的目标
//后2个参数分别是蒙板参数和过滤器
glBlitFramebufferEXT(mouseCurPosX - MagnifierRation, mouseY - MagnifierRation,
mouseCurPosX + MagnifierRation, mouseY + MagnifierRation,
WIN_WIDTH - MagnifierSize, WIN_HEIGHT - MagnifierSize,
WIN_WIDTH, WIN_HEIGHT,
GL_COLOR_BUFFER_BIT, GL_LINEAR);

glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebuffer);
glBlitFramebufferEXT(WIN_WIDTH - MagnifierSize, WIN_HEIGHT - MagnifierSize,
WIN_WIDTH, WIN_HEIGHT,
mouseCurPosX-MagnifierSize/2.0, mouseY-MagnifierSize/2.0,
mouseCurPosX+MagnifierSize/2.0, mouseY+MagnifierSize/2.0,
GL_COLOR_BUFFER_BIT, GL_LINEAR);

}

glutSwapBuffers();
}

void reshape(int w, int h)
{
float aspect = (float) w/((h)?h:1);	//平截头体的纵横比,也就是宽度除以高度,(h)?h:1意思是若h=0,则h=1

glViewport(0,0, w, h);

//进行投影变换前调用下面两个函数,接下来的变换函数将影响投影矩阵
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(45.0f, aspect, 1.0f, 100.0f);
glViewport(0,0,w,h);

glMatrixMode(GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'o':
isOpenMagnifier = !isOpenMagnifier;
break;
case 'x':
MagnifierRation += 4.0f;
break;
case 'd':
MagnifierRation -= 4.0f;
if (MagnifierRation < 1)
{
MagnifierRation = 1.0;
}
break;
case 27:	//退出程序
exit(0);
break;
}
}

void mouse(int button, int state, int x, int z)
{
switch(button)
{
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
{
tempX = x;
tempY = z;
isMosDownMove = true;	//鼠标移动时需要用到的判断变量
}
else
{
isMosDownMove = false;
}
break;
}
}

void motion(int x, int y)
{
if(isMosDownMove)
{
mousePosY = (mousePosY + (x - tempX))%360;
mousePosX = (mousePosX + (y - tempY))%360;
tempX = x;
tempY = y;
glutPostRedisplay();
}
}

void animate(void)
{
//刷新屏幕
glutPostRedisplay();
}

void move(int x, int y)
{
if (isOpenMagnifier)
{
mouseCurPosX = x;
mouseCurPosY = y;
}
}

int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
glutInitWindowSize(WIN_WIDTH, WIN_HEIGHT);
glutInitWindowPosition(100,100);
glutCreateWindow("Teaports");
GLenum err = glewInit(); //如果使用FBO的话,此句不能缺少
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutPassiveMotionFunc(move); //鼠标移动的回调函
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutIdleFunc(animate);
glutMainLoop();
return 0;
}


运行结果:





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: