OpenGL: 阴影算法
2014-04-15 14:56
148 查看
图中有两条光线,一条沿视角方向,另一条偏右 采用阴影体算法,实现了多光源,多物体的阴影。
这个算法没有采用顶点shader,所以速度比较慢,学习算法用,在实际工程中用效率就太低了。。。
算法还有个缺陷,只对凸多面体有效,如果物体是凹多面体阴影就会错误。因为我不知道如何确定凹多面体的轮廓,从而构造一个封闭的阴影体。非常希望有牛人能指点一二!
主要代码如下 计算轮廓
/* 计算轮廓(silhouette edge),采用的算法,伪代码如下 for 三角形tri in 所有三角形 如果tri是前向面 for 边e1 in 三角形tri的三条边 如果e1在轮廓列表中,从轮廓列表中移除e1 否则把e1加入轮廓列表中 默认物体是凸多面体。。。 对凹多面体,如何用算出来的轮廓构造阴影体,至今还不知道,希望有前辈能提点提点。 */ void ShadowVolume::Build(const Model &model, const Vector3 &lightPos) { m_lightPos = Vector3(lightPos); m_silhouetteEdges.clear(); m_silhouettePoints.clear(); for(int j = 0; j < model.m_indexNum; j += 3) { Vector3 v1 = model.m_vbuf[model.m_ibuf[j]]; Vector3 v2 = model.m_vbuf[model.m_ibuf[j + 1]]; Vector3 v3 = model.m_vbuf[model.m_ibuf[j + 2]]; Vector3 n = (v2 - v1).crossProduct(v3 - v1); n.normalise(); if(n.dotProduct(lightPos - v1) > EPSILON) { // 注意此处要减去v1,才是正确的可见面判别。否则在离物体很近的时候会出现误差 AddEdge(SilEdge(v1, v2)); AddEdge(SilEdge(v2, v3)); AddEdge(SilEdge(v3, v1)); } } list<SilEdge>::iterator it = m_silhouetteEdges.begin(); m_silhouettePoints.push_back((*it).edges[0]); m_silhouettePoints.push_back((*it).edges[1]); m_silhouetteEdges.erase(it); bool erased = true; // 把轮廓边缘的点提取出来,构造出多边形的点集合。下面的方法很糟糕,可是我想不到更好的办法了。。 while(m_silhouetteEdges.size() != 0 && erased) { erased = false; for(it = m_silhouetteEdges.begin();it != m_silhouetteEdges.end(); it++) { SilEdge &edge = *it; if(edge.edges[0] == m_silhouettePoints[m_silhouettePoints.size() - 1]) { if(edge.edges[1] != m_silhouettePoints[0]) { m_silhouettePoints.push_back(edge.edges[1]); } m_silhouetteEdges.erase(it); erased = true; break; } if(edge.edges[1] == m_silhouettePoints[m_silhouettePoints.size() - 1]) { if(edge.edges[0] != m_silhouettePoints[0]) { m_silhouettePoints.push_back(edge.edges[0]); } m_silhouetteEdges.erase(it); erased = true; break; } if(edge.edges[1] == m_silhouettePoints[0] || edge.edges[0] == m_silhouettePoints[0]) { m_silhouetteEdges.erase(it); erased = true; break; } } } }绘制阴影体
void DrawVolume() { m_infinitePoints.clear(); for(size_t i = 0; i < m_silhouettePoints.size(); i++) { Vector3 a = m_silhouettePoints[i] - m_lightPos; Vector3 infinite = a; infinite.normalise(); infinite *= 100; infinite += a; m_infinitePoints.push_back(infinite); } glBegin(GL_POLYGON); for(int i = m_infinitePoints.size() - 1; i >= 0; i--) { glVertex3f(m_infinitePoints[i].x, m_infinitePoints[i].y, m_infinitePoints[i].z); } glEnd(); glBegin(GL_POLYGON); for(size_t i = 0; i < m_silhouettePoints.size(); i++) { glVertex3f(m_silhouettePoints[i].x, m_silhouettePoints[i].y, m_silhouettePoints[i].z); } glEnd(); glBegin(GL_QUADS); int n = m_silhouettePoints.size(); for(int i = 0; i < n; i++) { glVertex3f(m_silhouettePoints[(i+1) % n].x, m_silhouettePoints[(i+1) % n].y, m_silhouettePoints[(i+1) % n].z); glVertex3f(m_silhouettePoints[i].x, m_silhouettePoints[i].y, m_silhouettePoints[i].z); glVertex3f(m_infinitePoints[i].x, m_infinitePoints[i].y, m_infinitePoints[i].z); glVertex3f(m_infinitePoints[(i+1) % n].x, m_infinitePoints[(i+1) % n].y, m_infinitePoints[(i+1) % n].z); } glEnd(); }用蒙版缓存绘制阴影
// 用蒙版缓存(stencil buffer)的方法绘制阴影。 void Render() { // 绘制没有光线时的场景 for(size_t k = 0; k < mLight.size(); k++) { glDisable(GL_LIGHT0 + k); } glBlendFunc(GL_ONE, GL_ONE); drawWall(); for(size_t i = 0; i < mObjects.size(); i++) { mObjects[i]->Render(); } //处理每条光线 for(size_t k = 0; k < mLight.size(); k++) { glClear(GL_STENCIL_BUFFER_BIT); // 计算每一个物体阴影体 for(size_t i = 0; i < mObjects.size(); i++) { mObjects[i]->BuildShadow(mLight[k]->position); } glDepthFunc(GL_LESS); // 绘制阴影体,采用卡马克的depth fail算法 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthMask(GL_FALSE); glEnable(GL_CULL_FACE); glEnable(GL_STENCIL_TEST); glEnable(GL_POLYGON_OFFSET_FILL); // 对重叠表面的处理 glPolygonOffset(0.0f, 100.0f); glCullFace(GL_FRONT); glStencilFunc(GL_ALWAYS, 0x0, 0xff); glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); for(size_t i = 0; i < mObjects.size(); i++) { mObjects[i]->RenderShadow(); } glCullFace(GL_BACK); glStencilFunc(GL_ALWAYS, 0x0, 0xff); glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); for(size_t i = 0; i < mObjects.size(); i++) { mObjects[i]->RenderShadow(); } glDepthFunc(GL_LEQUAL); glDisable(GL_CULL_FACE); glDisable(GL_POLYGON_OFFSET_FILL); // 绘制整个场景,如果蒙版缓存的值为1,说明有阴影,不绘制 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); glStencilFunc(GL_EQUAL, 0x0, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // 开启当前光线的光照效果 glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_LIGHT0 + k); for(size_t i = 0; i < mObjects.size(); i++) { mObjects[i]->Render(); } drawWall(); glDisable(GL_LIGHT0 + k); glDisable(GL_BLEND); } }源码下载
相关文章推荐
- Win32+OpenGL计算机图形学光照阴影算法(参照超级宝典4改编)
- Win32+OpenGL计算机图形学光照阴影算法 可控制光源、光照物等位置的移动以及漫游等
- OpenGL 4.0 GLSL 用 shadow map 算法 生成阴影
- OpenGL光照阴影算法的实现
- [OpenGL]计算机图形学:直线裁剪算法中Cohen-Sutherland算法和Liang-Barsky算法
- OpenGL入门2——曲线生成算法
- OpenGL深度剥离算法(Depth Peeling)半透明实现
- 计算机图形学(二)输出图元_6_OpenGL曲线函数_1_圆生成算法
- [OpenGL] 网格细分算法 Loop Subdivision - 附我的实现结果
- OpenGL中点算法画圆弧、内接多边形算法画圆
- OpenGL 利用中点算法画抛物线:y = x*x / 16
- OpenGL圆形绘制算法
- OpenGL-2D(Cohen-Sutherland 裁线算法)
- opengl DDA直线算法的实现
- 基于Opencv的目标检测与跟踪阴影去除算法实现
- 使用OpenGL Midpoint Circle 算法来绘制一个八卦图
- 用OpenGL实现DDA画线算法
- 图片算法以及窗口阴影
- OpenGL中点算法和DDA算法画直线
- 综合图形学算法及OpenGL技术开发一个小型图形软件系统