3DGAMES中WIN32+OpenGL游戏中实现光照阴影算法主要代码实现

来源:互联网 发布:轩通网络购物卡 编辑:程序博客网 时间:2024/05/29 00:32
在3D游戏中实现光照阴影算法,其实主要问题就是推导出平面阴影矩阵,参考到我的前几章写的博客就是关于平面矩阵的推导与演算,
<a target=_blank href="http://blog.csdn.net/liuchuang_mfc/article/details/49255731">光照阴影平面矩阵</a><pre name="code" class="cpp">http://blog.csdn.net/liuchuang_mfc/article/details/49255731

在这里实现就不是太难了,此外此次环境是WIN32下配置上OpenGL实现光照,再用平面阴影矩阵去计算物体在光照下的阴影,实现了最终结果。
有时候,比较复杂的模型,想获得他的光照阴影,我们不失找到该模型的简单多边形来替代从而得出其大概的阴影效果,这样效率就会提高上、很多。
</pre><pre name="code" class="cpp"><pre name="code" class="cpp">#include "stdafx.h"#include "OpenGL.h"#include "math_3d.h"#include <GL\glut.h>//////////////////////////////#define KEY_DOWN(vk_code)((GetAsyncKeyState(vk_code)& 0x8000)?1:0)   //键盘消息//实际需要的3dsmodel数量个数#define _3DSMODEEL_MAX  1    //////////////////////////////////////////////////////////////static float    g_framesPerSecond = 0.0f;                   // fpsextern int    g_screenX, g_screenY;              // 客户屏幕宽度extern HDC      hDC;  // GDI设备句柄,将窗口连接到 GDI( 图形设备接口)float g_LigObjRotX, g_LigObjRotY, g_LigObjRotZ;//光照物旋转角度///////////////光照参数设置//////////////float LightAmbient[] = { 0.0f, 0.0f, 0.0f, 1.0f };// 环境光参数float LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };// 漫射光参数float LightPosition[] = { 4.0f, 20.0f,-10.0f, 1.0f };// 光源位置float  specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };/*镜面反射光参数*/float  specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };/*材质镜面反射颜色属性*/int   g_fps = 0;             // FPS帧率值char  g_fpsStr[10] = { 0 };   // 存放帧率值float g_time = 0.0f;       // 系统运行时间float g_lastTime = 0.0f;   // 持续的时间//////////纹理存储////////////////unsigned int g_groundtex;unsigned int g_mirrorTex;///////////////////阴影矩阵//声明一个阴影转换矩阵M3DMatrix44f shadowMat;//存储平面方程ABCD系数M3DVector4f vPlaneEquation;//地面任意三点 M3DVector3f points[3] = { { -3.0f, -0.0f, -2.0f },{ -3.0f, -0.0f, 2.0f },{ 4.0f, -0.0f, 2.0f } };////////////////////////3ds模型///////////////////////////////////////////////enum Model_3DS{CAR, GUN, HOUSE};float g_3dsPlace[10] = {4.0, 0.5, 0.0,     //表示在世界矩阵的位置0.0005, 0.0005, 0.0005,      //表示xyz放大倍数90, 0, 1.0, 0  //表示旋转};////////////////////////////////////OpenGL::OpenGL(): m_MyDraw(NULL), m_MyFont(NULL){/*为对象分配内存空间*/m_MyDraw = new MyDraw();m_MyFont = new MyFont();m_hFont = CreateFont(24,                        // nHeight0,                         // nWidth0,                         // nEscapement0,                         // nOrientationFW_NORMAL,                 // nWeightFALSE,                     // bItalicFALSE,                     // bUnderline0,                         // cStrikeOutANSI_CHARSET,              // nCharSetOUT_DEFAULT_PRECIS,        // nOutPrecisionCLIP_DEFAULT_PRECIS,       // nClipPrecisionDEFAULT_QUALITY,           // nQualityDEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily_T("Arial"));              // lpszFacenamem_hFontSong = CreateFont(15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, GB2312_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS,"宋体");}/*初始化相应的绘图数据*/int OpenGL::InitDrawData(){// 从三点得到的平面方程m3dGetPlaneEquation(vPlaneEquation, points[0], points[1], points[2]);InitLight();                            //初始化光照信息m_MyDraw->InitDrawScene();              //初始化绘图要求如加载纹理等//创建部分显示列表m_MyDraw->CreateList();//创建天空显示列表m_MyDraw->CreateSkyList();//创建地板显示列表m_MyDraw->CreateFloorList();g_groundtex = m_MyDraw->ATLLoadTexture("data/ground.jpg");g_mirrorTex = m_MyDraw->ATLLoadTexture("data/mirror.jpg");//创建3ds模型对象for (int i = 0; i < _3DSMODEEL_MAX; i++){m_3dsLoad[i] = NULL;m_3dsLoad[i] = new CLoad3DS();}//导入模型 模型的文件夹尽量这样设置 m_3dsLoad[CAR]->Init3DSModel(&m_3dsModel[CAR], "data/3ds/AUDIAVUS.3DS", FALSE, TRUE);m_3dsLoad[GUN]->Init3DSModel(&m_3dsModel[GUN], "data/3ds/gun.3DS", FALSE, TRUE);m_3dsLoad[HOUSE]->Init3DSModel(&m_3dsModel[HOUSE], "data/3ds/apple.3DS", FALSE, TRUE);return 0;}OpenGL::~OpenGL(){CleanUp();}BOOL OpenGL::SetupPixelFormat(HDC hDC0)  //检测安装OpenGL{int nPixelFormat;hDC = hDC0;PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR),    // pfd结构的大小 1,                                // 版本号 PFD_DRAW_TO_WINDOW |              // 支持在窗口中绘图 PFD_SUPPORT_OPENGL |              // 支持 OpenGL PFD_DOUBLEBUFFER,                 // 双缓存模式 PFD_TYPE_RGBA,                    // RGBA 颜色模式 32,                               // 32 位颜色深度 0, 0, 0, 0, 0, 0,                 // 忽略颜色位 0,                                // 没有非透明度缓存 0,                                // 忽略移位位 0,                                // 无累加缓存 0, 0, 0, 0,                       // 忽略累加位 32,                               // 32 位深度缓存     0,                                // 无模板缓存 0,                                // 无辅助缓存 PFD_MAIN_PLANE,                   // 主层 0,                                // 保留 0, 0, 0                           // 忽略层,可见性和损毁掩模 };if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd))){MessageBox(NULL, "没有找到合适的显示模式", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;}SetPixelFormat(hDC, nPixelFormat, &pfd);//设置当前设备的像素点格式hRC = wglCreateContext(hDC);            //获取渲染描述句柄wglMakeCurrent(hDC, hRC);               //激活渲染描述句柄InitDrawData();/*初始化绘图数据*/return TRUE;}int OpenGL::InitLight()//设置并初始化光源信息{glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);   // 设置环境光glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);   // 设置漫射光glEnable(GL_LIGHT0);glEnable(GL_DEPTH_TEST);glShadeModel(GL_SMOOTH);//作用是控制多边形的正面是如何决定的。在默认情况下,mode是GL_CCW//GL_CCW 表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面glFrontFace(GL_CCW);// 逆时针多边形面glEnable(GL_CULL_FACE);     // 剔除内部表面影响//// 启用颜色跟踪glEnable(GL_COLOR_MATERIAL);//// 实时设置材料属性遵循glColor值glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);//// 所有材料有全反射glMaterialfv(GL_FRONT, GL_SPECULAR, specref);/*指定用于光照计算的当前材质属性*/glMateriali(GL_FRONT, GL_SHININESS, 128);/*高亮显示*/glEnable(GL_POINT_SMOOTH);//抗锯齿glEnable(GL_LINE_SMOOTH);glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Make round points, not square points  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);return TRUE;}void OpenGL::Init(int Width, int Height){glViewport(0, 0, Width, Height);         // 设置OpenGL视口大小。glMatrixMode(GL_PROJECTION);             // 设置当前矩阵为投影矩阵。glLoadIdentity();             // 重置当前指定的矩阵为单位矩阵gluPerspective             // 设置透视图(45.0f,                 // 透视角设置为 45 度(GLfloat)Width / (GLfloat)Height,             // 窗口的宽与高比0.1f,             // 视野透视深度:近点1.0f3000.0f                 // 视野透视深度:始点1f远点f);// 这和照象机很类似,第一个参数设置镜头广角度,第二个参数是长宽比,后面是远近剪切。glMatrixMode(GL_MODELVIEW);            // 设置当前矩阵为模型视图矩阵glLoadIdentity();            // 重置当前指定的矩阵为单位矩阵}
场景截图:
<img src="http://img.blog.csdn.net/20151023200318436?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />void OpenGL::Render()                                  // 游戏场景图形渲染处理{CalculateFPS();/*计算fps数据*/glClearColor(0.0f, 0.0f, 0.5f, 1.0f); // 设置刷新背景色glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();//单位化矩阵glTranslatef(0, 0, 0);//移入世界物理(0,0,0)即是屏幕坐标系原点m_MyDraw->CameraRoam();/*游戏场景漫游控制*/glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);/*实时改变光源的位置*/// 实时计算投影在一个平面上的阴影矩阵m3dMakePlanarShadowMatrix(shadowMat, vPlaneEquation, LightPosition);glPushMatrix();//绘制平面即阴影体的依附平面glEnable(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, g_groundtex);float lenghtGround = 20.0;//地面长宽度float heightGround = -0.4;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();//// 绘制阴影与地面//// 首先关闭光照和深度测试glDisable(GL_LIGHTING);// 绘制光源体glPushMatrix();glPushAttrib(GL_CURRENT_BIT);glTranslatef(LightPosition[0], LightPosition[1], LightPosition[2]);glColor3f(1.0, 1.0, 0.0);glutSolidSphere(0.3f, 20, 20);glPopAttrib();glPopMatrix();///////3DS模型渲染///////加载车的3ds模型m_3dsLoad[CAR]->Show3DSModel(&m_3dsModel[CAR], g_3dsPlace);// 保存矩阵状态并进行旋转glPushMatrix();// 在绘制物体前将光源放在合适位置glEnable(GL_LIGHTING);glRotatef(g_LigObjRotX, 1.0f, 0.0f, 0.0f);glRotatef(g_LigObjRotY, 0.0f, 1.0f, 0.0f);DrawaScenes(0);/*绘制物体*/glDisable(GL_LIGHTING);// 恢复原矩阵状态glPopMatrix();//// 乘以阴影矩阵glMultMatrixf((float *)shadowMat);//// 旋转物体Draw3DShadow();glRotatef(g_LigObjRotX, 1.0f, 0.0f, 0.0f);glRotatef(g_LigObjRotY, 0.0f, 1.0f, 0.0f);// 给予true来绘制阴影DrawaScenes(1);// 恢复矩阵glPopMatrix();/*光源位置动*/float speed = 0.2;if (KEY_DOWN(VK_UP)){LightPosition[2] -= speed;}if (KEY_DOWN(VK_DOWN)){LightPosition[2] += speed;}if (KEY_DOWN(VK_LEFT)){LightPosition[0] -= speed;}if (KEY_DOWN(VK_RIGHT)){LightPosition[0] += speed;}/*光照物的移动*///实用小键盘时注意键盘不能被锁否则2846被当成上下左右控制键if (KEY_DOWN(VK_NUMPAD8)){g_LigObjRotX -= speed;}if (KEY_DOWN(VK_NUMPAD2)){g_LigObjRotX += speed;}if (KEY_DOWN(VK_NUMPAD4)){g_LigObjRotY -= speed;}if (KEY_DOWN(VK_NUMPAD6)){g_LigObjRotY += speed;}TextShow();   //场景方位、fps等文字显示glFlush();SwapBuffers(hDC);                                  // 切换缓冲区}void OpenGL::TextShow()      //场景所有文字显示{//场景中心点“+”显示m_MyFont->PrintText(g_screenX / 2, g_screenY / 2, "+", m_hFont, 1.0, 0.0, 0.0);m_MyFont->PrintText(g_screenX / 2.5, g_screenY / 6, "开启3D--GAMES", m_hFont, 0.0, 1.0, 0.0);m_MyFont->PrintText(g_screenX / 1.5, g_screenY / 4, "WSAD漫游、8246光照物动、↑↓←→光源移动", m_hFont, 0.0, 1.0, 0.0);char str_Scene[44]; //存储场景信息方位角度int rad_direc = abs(int(m_MyDraw->m_tempAngle));//场景方位角sprintf_s(str_Scene, "[方位=%3i X=%1.0f Y=%1.0f 高=%1.0f 俯仰角=%1.0f]",rad_direc % 360, m_MyDraw->m_eye[0],m_MyDraw->m_eye[2],//屏幕上的y坐标就是空间的Z坐标m_MyDraw->m_eye[1], m_MyDraw->m_elev);m_MyFont->PrintText(g_screenX / 1.2, g_screenY / 1.5, str_Scene, m_hFontSong, 0.9, 0.2, 0.0);/*fps显示*/m_MyFont->PrintText(g_screenX / 1.2, g_screenY / 3, g_fpsStr, m_hFont, 0.0, 1.0, 0.0);}void OpenGL::CleanUp(){wglMakeCurrent(hDC, NULL);//清除OpenGLwglDeleteContext(hRC);    //清除OpenGL/*删除对象内存*/delete m_MyFont;//删除字体指针对象delete []m_3dsLoad;//删除模型对象}void OpenGL::CalculateFPS(){// g_time获取操作系统启动到现在所经过的毫秒数,乘以0.001f得到秒数g_time = GetTickCount() * 0.001f;// 持续时间是否大于1秒if (g_time - g_lastTime > 1.0f){// 记录新的持续时间g_lastTime = g_time;// 把整数g_fps格式化为一个字符串保存在g_fpsStr中,并输出该字符串sprintf_s(g_fpsStr, "FPS: %d", g_fps);// 重置帧率值为0g_fps = 0;}else{// 帧率值递增g_fps++;}}////////////////////////////////////////////////// 绘制光照物以及影子void OpenGL::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();glTranslatef(0.0, 0.2, 0.0);glScalef(0.2, 0.2, 0.2);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();            // 四边形绘制结束/*绘制一个三角形*/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);glutSolidSphere(1.0, 40, 40);glPopAttrib();}/*绘制3ds模型阴影*/void OpenGL::Draw3DShadow(){glPushAttrib(GL_CURRENT_BIT);glColor3f(0.1, 0.1, 0.1);/*阴影时颜色设置为黑色*///// 底面glPushMatrix();glTranslatef(g_3dsPlace[0], g_3dsPlace[1], g_3dsPlace[2]);//3ds空间位置//3ds简化汽车模型制造阴影glBegin(GL_QUADS);        // 开始绘制四边形float length = 2.0;float width = 0.6;float height = 0.1;// 顶面glNormal3f(0.0f, 1.0f, 0.0f);    // 法线向上glTexCoord2f(0.0f, 1.0f); glVertex3f(-length, height, -width);glTexCoord2f(0.0f, 0.0f); glVertex3f(-length, height, width);glTexCoord2f(1.0f, 0.0f); glVertex3f(length, height, width);glTexCoord2f(1.0f, 1.0f); glVertex3f(length, height, -width);// 底面glNormal3f(0.0f, -1.0f, 0.0f);    // 法线朝下glTexCoord2f(1.0f, 1.0f); glVertex3f(-length, -height, -width);glTexCoord2f(0.0f, 1.0f); glVertex3f(length, -height, -width);glTexCoord2f(0.0f, 0.0f); glVertex3f(length, -height, width);glTexCoord2f(1.0f, 0.0f); glVertex3f(-length, -height, width);glEnd();            // 四边形绘制结束glPopMatrix();glPopAttrib();}


                                             
0 0
原创粉丝点击