#pragma once #include <windows.h> #include "math_3d.h" #define GLUT_DISABLE_ATEXIT_HACK #include <gl/glew.h>/*GL_BGR*/ #include <gl/glut.h> #include <atlimage.h> // 全局变量光照参数 float ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };/*环境光参数*/ float diffuseLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };/*漫反射光参数*/ float specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };/*镜面反射光参数*/ float specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };/*材质镜面反射颜色属性*/ float lightPos[] = { 8.0f, 10.0f, 4.0f, 1.0f };/*光源位置*/ //如果我们把lightPos数组的最后一个值设为0.0, //可以使光源看上去像是来自无限远处,并沿着向量(X,Y,Z)所指定的方向射入。 //这种看似来自无限远处的光源称为方向性光源,它会均匀地照射在物体的表面, //它的所有光线都是平行的, 是一种平行光。 //反之,对于位置性光源,光线会从光源处向不同方向发散开来。 float spotDir[] = { 0.0f, 0.0f, -1.0f };//聚光灯参数 //全局变量设置 // 旋转变量 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 = 40.0; unsigned int ATLLoadTexture(const char* fileName); unsigned int g_groundtex; unsigned int g_mirrorTex; void InitTexture() { g_groundtex = ATLLoadTexture("data/ground.jpg"); g_mirrorTex = ATLLoadTexture("data/mirror.jpg"); } //加载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; } // 声明一个阴影转换矩阵 M3DMatrix44f shadowMat;
//截图效果
<img src="http://img.blog.csdn.net/20151021183128451?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> //////////////////////////////////////////////// // 绘制光照物以及影子 void DrawaScenes(int nShadow) { glPushAttrib(GL_CURRENT_BIT); // 设置材质的颜色这里我们只需要设置为黑色表示阴影 if (nShadow == 0) glColor3f(1.0, 1.0, 1.0);/*非阴影时颜色设置为白色等*/ else { glColor3f(0.1, 0.1, 0.1);/*阴影时颜色设置为黑色*/ /*绘制还要镜面反射的球体阴影*/ glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glTranslatef(g_yRot, g_xRot, 4);//物体位置 glutSolidSphere(0.3, 20, 20); glPopMatrix(); glPopAttrib(); } /*绘制实体与阴影*/ glPushMatrix(); glTranslatef(-10.0, -5.0, 0.0); glScalef(0.5, 0.5, 0.5); glBegin(GL_QUADS); // 开始绘制四边形 // 前侧面 glNormal3f(0.0f, 0.0f, 1.0f); // 法线指向观察者 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 后侧面 glNormal3f(0.0f, 0.0f, -1.0f); // 法线背向观察者 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); // 顶面 glNormal3f(0.0f, 1.0f, 0.0f); // 法线向上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); // 底面 glNormal3f(0.0f, -1.0f, 0.0f); // 法线朝下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 右侧面 glNormal3f(1.0f, 0.0f, 0.0f); // 法线朝右 glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 左侧面 glNormal3f(-1.0f, 0.0f, 0.0f); // 法线朝左 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); // 四边形绘制结束 //glPopMatrix(); /*绘制一个三角形*/ glPushMatrix(); glTranslatef(-8, 0.0, -2.0); glBegin(GL_TRIANGLES); glVertex3f(0.0, 0.0, -1.0); glVertex3f(-1.0, 0.0, 1.0); glVertex3f(1.0, 0.0, 1.0); glEnd(); glTranslatef(-5.0, 0.0, 0.0); //glEnable(GL_TEXTURE_2D); //glBindTexture(GL_TEXTURE_2D, g_groundtex); glutSolidSphere(3.0, 20, 20); //glDisable(GL_TEXTURE_2D); glPopMatrix(); glPopAttrib(); } //绘制球体的函数 void drawSphere() { glEnable(GL_LIGHTING); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glColor3f(0.0, 0.5, 0.8); glTranslatef(g_yRot, g_xRot, 4);//物体位置 glutSolidSphere(0.3, 20, 20); glPopMatrix(); glPopAttrib(); glDisable(GL_LIGHTING); } // 绘制场景 void RenderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0, 0.0, 0.0); //// 移动z轴坐标系看到前面的一切东西 glLightfv(GL_LIGHT0, GL_POSITION, lightPos);/*实时改变光源的位置*/ //glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spotDir);/*聚光灯效果*/ //glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 60.0f); gluLookAt(g_cameraX, g_cameraY, g_cameraZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //地面任意三点 M3DVector3f points[3] = { { -3.0f, -10.0f, -2.0f }, { -3.0f, -10.0f, 2.0f }, { 4.0f, -10.0f, 2.0f } }; // 从三点得到的平面方程 M3DVector4f vPlaneEquation; m3dGetPlaneEquation(vPlaneEquation, points[0], points[1], points[2]); // 计算投影在一个平面上的阴影矩阵 m3dMakePlanarShadowMatrix(shadowMat, vPlaneEquation, lightPos); //glEnable(GL_NORMALIZE); glPushMatrix(); //绘制平面即阴影体的依附平面 glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, g_groundtex); float lenghtGround = 80.0;//地面长宽度 float heightGround = -11.0; glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-lenghtGround, heightGround, -lenghtGround); // 纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(-lenghtGround, heightGround, lenghtGround); // 纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(lenghtGround, heightGround, lenghtGround); // 纹理和四边形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(lenghtGround,heightGround, -lenghtGround); // 纹理和四边形的左上 glEnd(); glDisable(GL_TEXTURE_2D); glPopMatrix(); // 保存矩阵状态并进行旋转 glPushMatrix(); // 在绘制物体前将光源放在合适位置 glEnable(GL_LIGHTING); glRotatef(g_xRot, 1.0f, 0.0f, 0.0f); glRotatef(g_yRot, 0.0f, 1.0f, 0.0f); DrawaScenes(0);/*绘制物体*/ // 恢复原矩阵状态 glPopMatrix(); //// 绘制阴影与地面 //// 首先关闭光照和深度测试 glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glPushMatrix(); // 绘制光源体 glPushMatrix(); glTranslatef(lightPos[0], lightPos[1], lightPos[2]); glColor3f(1.0, 0.0, 0.0); glutSolidSphere(0.5f, 20, 20); glPopMatrix(); 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); float lengthMirror = 10.0;//镜子长宽 glBegin(GL_QUADS); //前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-lengthMirror, -lengthMirror, -2.0f); // 纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(lengthMirror, -lengthMirror, -2.0f); // 纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(lengthMirror, lengthMirror, -2.0f); // 纹理和四边形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-lengthMirror, lengthMirror, -2.0f); // 纹理和四边形的左上 glEnd(); glDisable(GL_TEXTURE_2D); glPopMatrix(); glPopAttrib(); /*绘制光源体*/ glPushMatrix(); glTranslatef(lightPos[0], lightPos[1], lightPos[2]); glColor3f(1.0, 1.0, 1.0); glutSolidSphere(0.1f, 20, 20); glPopMatrix(); //// 乘以阴影矩阵 glMultMatrixf((float *)shadowMat); //// 旋转物体 glRotatef(g_xRot, 1.0f, 0.0f, 0.0f); glRotatef(g_yRot, 0.0f, 1.0f, 0.0f); // 给予true来绘制阴影 DrawaScenes(1); // 恢复矩阵 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(); glDisable(GL_STENCIL_TEST); glDepthMask(true);//重新启用深度缓冲区 glutSwapBuffers(); } void SetupRC() { InitTexture();/*初始化图片纹理*/ glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); // 隐藏面消除; glFrontFace(GL_CCW); // 逆时针多边形面 glEnable(GL_CULL_FACE); // 剔除内部表面影响 // 启动光源0 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glEnable(GL_LIGHT0); // 启用颜色跟踪 glEnable(GL_COLOR_MATERIAL); // 实时设置材料属性遵循glColor值 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // 所有材料有全反射 glMaterialfv(GL_FRONT, GL_SPECULAR, specref);/*指定用于光照计算的当前材质属性*/ glMateriali(GL_FRONT, GL_SHININESS, 128);/*高亮显示*/ // 黑色背景 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_UP) g_xRot -= 1.0f; if (key == GLUT_KEY_DOWN) g_xRot += 1.0f; if (key == GLUT_KEY_LEFT) g_yRot -= 1.0f; if (key == GLUT_KEY_RIGHT) g_yRot += 1.0f; // Refresh the Window glutPostRedisplay(); } 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':lightPos[0] += 2.0; glutPostRedisplay(); break; case 'd':lightPos[0] -= 2.0; glutPostRedisplay(); break; default:break; } } void ChangeSize(int w, int h) { float fAspect; // 防止被0除 if (h == 0) h = 1; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); fAspect = (float)w / (float)h; gluPerspective(60.0f, fAspect, 0.1, 2000.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(1366, 768); glutCreateWindow("LightShadowMirrorReflect"); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutKeyboardFunc(NormalKeys); glutDisplayFunc(RenderScene); SetupRC(); glutMainLoop(); return 0; }