3D+OpenGL里的光照平面镜面反射以及漫游移动物体位置等的具体实现
在实现过程中涉及到
1.opengl里的蒙版缓冲等相关知识
2.观察坐标系的转换摄像漫游等
3.此外图中的mirror图片为导入的mirror.jpg文件
4.在纹理贴图中
unsigned int ATLLoadTexture(const char* fileName)函数实现了jpg/bmp等图片的加载<pre name="code" class="cpp">//加载jpg/bmp等各种纹理返回纹理id
#define GLUT_DISABLE_ATEXIT_HACK #include <gl/glew.h>/*GL_BGR*/ #include <atlimage.h> #include <GL/glut.h> //全局变量设置 // 旋转变量 static float g_xRot = 0.0f; static float g_yRot = 0.0f; float g_lightPos[] = { 4.0f, 4.0f,2.0f, 1.0f }; float g_ambientLight[] = { 0.0f, 0.0f, 1.0f, 1.0f }; float g_cameraX = 0.0, g_cameraY = 0.0, g_cameraZ = 10.0; unsigned int g_mirrorTex; //加载jpg/bmp等各种纹理返回纹理id unsigned int ATLLoadTexture(const char* fileName) { BITMAP bm; GLuint idTexture = 0; CImage img; //需要头文件atlimage.h HRESULT hr = img.Load(fileName); if (!SUCCEEDED(hr)) //文件加载失败 { MessageBox(NULL, "文件加载失败", "ERROR", 0); return NULL; } HBITMAP hbmp = img; if (!GetObject(hbmp, sizeof(bm), &bm)) return 0; glGenTextures(1, &idTexture); if (idTexture) { glBindTexture(GL_TEXTURE_2D, idTexture); 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_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glPixelStoref(GL_PACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, 3, bm.bmWidth, bm.bmHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, bm.bmBits); //这里不是GL_RGB } return idTexture; } void init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); g_mirrorTex = ATLLoadTexture("data/mirror.jpg"); } //绘制球体的函数 void drawSphere() { //光源设置 glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glLightfv(GL_LIGHT0, GL_POSITION, g_lightPos); glLightfv(GL_LIGHT0, GL_AMBIENT, g_ambientLight); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glColor3f(0.0, 0.5,0.8); glTranslatef(g_xRot, g_yRot, 4);//物体位置 glutSolidSphere(0.3, 20, 20); glPopMatrix(); glPopAttrib(); } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //设置观察点 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, 1, 0.1, 500); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(g_cameraX,g_cameraY,g_cameraZ, 0, 0, 0, 0, 1, 0); glEnable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); drawSphere(); glClearStencil(0x0); glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glEnable(GL_STENCIL_TEST); glDisable(GL_LIGHTING); /*绘制平面镜子*/ glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glColor3f(1.0f, 1.0f, 1.0f); glDepthMask(GL_FALSE);//设置深度缓冲区为只读 glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, g_mirrorTex); glBegin(GL_QUADS); //前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-2.0f, -2.0f, 1.0f); // 纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(2.0f, -2.0f, 1.0f); // 纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(2.0f, 2.0f, 1.0f); // 纹理和四边形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-2.0f, 2.0f, 1.0f); // 纹理和四边形的左上 glEnd(); glDisable(GL_TEXTURE_2D); glPopMatrix(); glPopAttrib(); /*绘制光源体*/ glPushMatrix(); glTranslatef(g_lightPos[0], g_lightPos[1], g_lightPos[2]); glColor3f(1.0, 1.0, 1.0); glutSolidSphere(0.1f, 20, 20); glPopMatrix(); glDepthMask(GL_TRUE);//重新启用深度缓冲区 ///明确说明函数的测试功能GL_NEVER,,GL_LESS, GL_LEQUAL, //GL_GREATER, GL_GEQUAL,,GL_EQUAL, GL_NOTEQUAL和 GL_ALWAYS。 //初始化的值是GL_ALWAYS //ref //明确说明该模板测试的引用值。 ref 值被限制在0~2 ^ (n - 1)间, //其中n是模板缓存中位平面数。初始化值是0 //mask // 该参数表示一个模板,用来和ref值以及存储的模板值做与运算。初始化值是全1 //要允许或禁止该测试的话,使用glEnable(GL_STENCIL_TEST)或glDisable(GL_STENCIL_TEST) glStencilFunc(GL_EQUAL, 1, 0xFF);//0xff==255 //glStencilOp函数,它用来根据比较结果修改蒙板缓存区中的值 //sfail当蒙板测试失败时所执行的操作 //zfail当蒙板测试通过,深度测试失败时所执行的操作 //zpass当蒙板测试通过,深度测试通过时所执行的操作 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glScalef(1.0f, 1.0f, -1.0f);//镜子里的影子方向取反 glPushAttrib(GL_CURRENT_BIT); drawSphere(); glPopAttrib(); glutSwapBuffers(); } void NormalKeys(unsigned char key, int x, int y) { switch (key) { case VK_ESCAPE:exit(0); break; /*摄像机移动命令*/ case 'w': g_cameraZ -= 1.0; glutPostRedisplay(); break; case 's': g_cameraZ += 1.0; glutPostRedisplay(); break; case 'a': g_cameraX += 1.0; glutPostRedisplay(); break; case 'd': g_cameraX -= 1.0; glutPostRedisplay(); break; default:break; } } void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_UP) g_yRot += 0.1f; if (key == GLUT_KEY_DOWN) g_yRot -= 0.1f; if (key == GLUT_KEY_LEFT) g_xRot -= 0.1f; if (key == GLUT_KEY_RIGHT) g_xRot += 0.1f; // Refresh the Window glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_STENCIL | GLUT_DEPTH); glutInitWindowSize(1376, 768); glutInitWindowPosition(0, 0); glutCreateWindow("镜面反射"); init(); glutDisplayFunc(display); //glutReshapeFunc(reshape); glutKeyboardFunc(NormalKeys); glutSpecialFunc(SpecialKeys); glutMainLoop(); return 0; }镜面反射实现的结果截图: