Volume阴影我认为是做cs游戏的最难的一个点,但了解实现原理后其实不难。

目前完成的实现效果

shadow volume原理

不过让我不理解的是,计算shadow volume三角面的扩展顶点使得cpu计算时间增加了10倍,就图中两个模型加载一共耗时将近1分钟。应该有更优化的方法。而且加了Volume阴影我的天空盒无法显示,这个问题有待解决。

关键点一:扩展三角面顶点,一般三角面是3个顶点,但为了实现Volume阴影,用用到6个顶点。

void ModelComponent::DetermineAdjacency(vector<unsigned int>& el)
{// Elements with adjacency infovector<unsigned int> elAdj;// Copy and make room for adjacency infofor (GLuint i = 0; i < el.size(); i += 3){elAdj.push_back(el[i]);elAdj.push_back(-1);elAdj.push_back(el[i + 1]);elAdj.push_back(-1);elAdj.push_back(el[i + 2]);elAdj.push_back(-1);}// Find matching edgesfor (GLuint i = 0; i < elAdj.size(); i += 6){// A triangleint a1 = elAdj[i];int b1 = elAdj[i + 2];int c1 = elAdj[i + 4];// Scan subsequent trianglesfor (GLuint j = i + 6; j < elAdj.size(); j += 6){int a2 = elAdj[j];int b2 = elAdj[j + 2];int c2 = elAdj[j + 4];// Edge 1 == Edge 1if ((a1 == a2 && b1 == b2) || (a1 == b2 && b1 == a2)){elAdj[i + 1] = c2;elAdj[j + 1] = c1;}// Edge 1 == Edge 2if ((a1 == b2 && b1 == c2) || (a1 == c2 && b1 == b2)){elAdj[i + 1] = a2;elAdj[j + 3] = c1;}// Edge 1 == Edge 3if ((a1 == c2 && b1 == a2) || (a1 == a2 && b1 == c2)){elAdj[i + 1] = b2;elAdj[j + 5] = c1;}// Edge 2 == Edge 1if ((b1 == a2 && c1 == b2) || (b1 == b2 && c1 == a2)){elAdj[i + 3] = c2;elAdj[j + 1] = a1;}// Edge 2 == Edge 2if ((b1 == b2 && c1 == c2) || (b1 == c2 && c1 == b2)){elAdj[i + 3] = a2;elAdj[j + 3] = a1;}// Edge 2 == Edge 3if ((b1 == c2 && c1 == a2) || (b1 == a2 && c1 == c2)){elAdj[i + 3] = b2;elAdj[j + 5] = a1;}// Edge 3 == Edge 1if ((c1 == a2 && a1 == b2) || (c1 == b2 && a1 == a2)){elAdj[i + 5] = c2;elAdj[j + 1] = b1;}// Edge 3 == Edge 2if ((c1 == b2 && a1 == c2) || (c1 == c2 && a1 == b2)){elAdj[i + 5] = a2;elAdj[j + 3] = b1;}// Edge 3 == Edge 3if ((c1 == c2 && a1 == a2) || (c1 == a2 && a1 == c2)){elAdj[i + 5] = b2;elAdj[j + 5] = b1;}}}// Look for any outside edgesfor (GLuint i = 0; i < elAdj.size(); i += 6){if (elAdj[i + 1] == -1) elAdj[i + 1] = elAdj[i + 4];if (elAdj[i + 3] == -1) elAdj[i + 3] = elAdj[i];if (elAdj[i + 5] == -1) elAdj[i + 5] = elAdj[i + 2];}// Copy all data back into elel = elAdj;
}

Volume shader

--------------vs
#version 430
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 Tangent;
layout (location = 4) in vec3 Bitangent;
layout (location = 5) in ivec4 BoneIDs;
layout (location = 6) in vec4 Weights;const int MAX_BONES = 100; // Max number of bones
uniform mat4 gBones[MAX_BONES]; // Bone transformationsout vec3 VPosition;layout(std140 , binding = 0) uniform PV
{mat4 projection;mat4 view;
};
uniform mat4 model;void main()
{ mat4 BoneTransform = gBones[ BoneIDs[0] ] * Weights[0];BoneTransform += gBones[ BoneIDs[1] ] * Weights[1];BoneTransform += gBones[ BoneIDs[2] ] * Weights[2];BoneTransform += gBones[ BoneIDs[3] ] * Weights[3];vec4 world = BoneTransform * vec4(aPos, 1.0);VPosition = (model * world).xyz;
}------------------gs
#version 430
layout( triangles_adjacency ) in;
layout( triangle_strip, max_vertices = 18 ) out;in vec3 VPosition[];layout(std140 , binding = 0) uniform PV
{mat4 projection;mat4 view;
};layout(std140 , binding = 1) uniform BaseLight
{vec4 lightDir;vec4 color;vec4 ambient;vec4 lightPos;
};vec3 LightPosition = (view * lightPos).xyz;float EPSILON = 0.01;/*bool facesLight( vec3 a, vec3 b, vec3 c )
{LightPosition = (view * lightPos).xyz;vec3 n = cross( b - a, c - a );vec3 da = LightPosition.xyz - a;vec3 db = LightPosition.xyz - b;vec3 dc = LightPosition.xyz - c;return dot(n, da) > 0 || dot(n, db) > 0 || dot(n, dc) > 0;
}void emitEdgeQuad( vec3 a, vec3 b ) {LightPosition = (view * lightPos).xyz;vec3 LightDir = normalize(a - LightPosition.xyz); vec3 deviation = LightDir * EPSILON;gl_Position = projection * vec4(a + deviation, 1);EmitVertex();gl_Position = projection * vec4(LightDir, 0);EmitVertex();LightDir = normalize(b - LightPosition.xyz); deviation = LightDir * EPSILON;gl_Position = projection * vec4(b + deviation, 1);EmitVertex();gl_Position = projection * vec4(LightDir, 0);EmitVertex();EndPrimitive();
}void main()
{LightPosition = (view * lightPos).xyz;if( facesLight(VPosition[0], VPosition[2], VPosition[4]) ) {if( ! facesLight(VPosition[0],VPosition[1],VPosition[2]) ) emitEdgeQuad(VPosition[0],VPosition[2]);if( ! facesLight(VPosition[2],VPosition[3],VPosition[4]) ) emitEdgeQuad(VPosition[2],VPosition[4]);if( ! facesLight(VPosition[4],VPosition[5],VPosition[0]) ) emitEdgeQuad(VPosition[4],VPosition[0]);//FRONT CAPvec3 LightDir = normalize(VPosition[0] - LightPosition.xyz); vec3 deviation = LightDir * EPSILON;gl_Position = projection * vec4(VPosition[0] + deviation, 1);EmitVertex();LightDir = normalize(VPosition[2] - LightPosition.xyz); deviation = LightDir * EPSILON;gl_Position =  projection * vec4(VPosition[2] + deviation, 1);EmitVertex();LightDir = normalize(VPosition[4] - LightPosition.xyz); deviation = LightDir * EPSILON;gl_Position =  projection * vec4(VPosition[4] + deviation, 1);EmitVertex();EndPrimitive();//BACK CAPLightDir = normalize(VPosition[0] - LightPosition.xyz); gl_Position = projection * vec4(LightDir, 0);EmitVertex();LightDir = normalize(VPosition[4] - LightPosition.xyz); gl_Position =  projection * vec4(LightDir, 0);EmitVertex();LightDir = normalize(VPosition[2] - LightPosition.xyz); gl_Position =  projection * vec4(LightDir, 0);EmitVertex();EndPrimitive();}
}*/
struct sVSOutput
{         vec3 WorldPos;
};
void EmitQuad(int StartIndex, sVSOutput StartVertex, int EndIndex, sVSOutput EndVertex)
{vec3 LightDir = normalize(StartVertex.WorldPos - lightPos.xyz);vec3 l = LightDir * EPSILON;gl_Position = projection * view * vec4((StartVertex.WorldPos + l), 1.0);EmitVertex();gl_Position = projection * view * vec4(LightDir, 0.0);EmitVertex();LightDir = normalize(EndVertex.WorldPos - lightPos.xyz);l = LightDir * EPSILON;gl_Position = projection * view * vec4((EndVertex.WorldPos + l), 1.0);EmitVertex();gl_Position = projection * view * vec4(LightDir, 0.0);EmitVertex();EndPrimitive();
}void main()
{/*gl_Position = projection * view * vec4(VPosition[0] ,1.0);EmitVertex();gl_Position = projection * view * vec4(VPosition[1] ,1.0);EmitVertex();gl_Position = projection * view * vec4(VPosition[2] ,1.0);EmitVertex();EndPrimitive();*/vec3 e1 = VPosition[2] - VPosition[0];vec3 e2 = VPosition[4] - VPosition[0];vec3 e3 = VPosition[1] - VPosition[0];vec3 e4 = VPosition[3] - VPosition[2];vec3 e5 = VPosition[4] - VPosition[2];vec3 e6 = VPosition[5] - VPosition[0];vec3 Normal = cross(e1,e2);vec3 LightDir = lightPos.xyz - VPosition[0];if (dot(Normal, LightDir) > 0.000001) {struct sVSOutput StartVertex, EndVertex;Normal = cross(e3,e1);if (dot(Normal, LightDir) <= 0) {StartVertex.WorldPos = VPosition[0];EndVertex.WorldPos   = VPosition[2];EmitQuad(0, StartVertex, 2, EndVertex);}Normal = cross(e4,e5);LightDir = lightPos.xyz - VPosition[2];if (dot(Normal, LightDir) <= 0) {StartVertex.WorldPos = VPosition[2];EndVertex.WorldPos   = VPosition[4];EmitQuad(2, StartVertex, 4, EndVertex);}Normal = cross(e2,e6);LightDir = lightPos.xyz - VPosition[4];if (dot(Normal, LightDir) <= 0) {StartVertex.WorldPos = VPosition[4];EndVertex.WorldPos   = VPosition[0];EmitQuad(4, StartVertex, 0, EndVertex);}vec3 LightDir = (normalize(VPosition[0] - lightPos.xyz)) * EPSILON;gl_Position = projection * view * vec4((VPosition[0] + LightDir), 1.0);EmitVertex();LightDir = (normalize(VPosition[2] - lightPos.xyz)) * EPSILON;gl_Position = projection * view * vec4((VPosition[2] + LightDir), 1.0);EmitVertex();LightDir = (normalize(VPosition[4] - lightPos.xyz)) * EPSILON;gl_Position = projection * view * vec4((VPosition[4] + LightDir), 1.0);EmitVertex();EndPrimitive();}
}-------------fs
#version 430
out vec4 color;
void main() {
color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}

关键点二 模板测试。

while (!glfwWindowShouldClose(Window::window_ptr)){currentFrame = glfwGetTime();SetCurTime(currentFrame);float deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;SetDeltaTime(deltaTime);glEnable(GL_DEPTH_TEST);glDepthMask(GL_TRUE);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);glClearColor(0.05f, 0.05f, 0.05f, 1.0f);glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);glEnable(GL_DEPTH_TEST);glDepthMask(GL_TRUE);_input->Update();//for each frameScene::Instace->Update();Scene::Instace->LateUpdate();Scene::Instace->Render();//glBindFramebuffer(GL_FRAMEBUFFER, 0);//RenderShadowVolIntoStencil();//SpecularGBuffer();glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // write to default framebuffer// blit to default framebuffer. Note that this may or may not work as the internal formats of both the FBO and default framebuffer have to match.// the internal formats are implementation defined. This works on all of my systems, but if it doesn't on yours you'll likely have to write to the// depth buffer in another shader stage (or somehow see to match the default framebuffer's internal format with the FBO's internal format).glBlitFramebuffer(0, 0, Width, Height, 0, 0, Width, Height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);glBindFramebuffer(GL_FRAMEBUFFER, 0);// 2. lighting pass: calculate lighting by iterating over a screen filled quad pixel-by-pixel using the gbuffer's content.// -----------------------------------------------------------------------------------------------------------------------glClear(GL_COLOR_BUFFER_BIT);glDepthMask(GL_FALSE);//glDrawBuffer(GL_BACK);AmbientGBuffer();glEnable(GL_STENCIL_TEST);//glEnable(GL_DEPTH_CLAMP);//glEnable(GL_DEPTH_TEST);//glDepthMask(GL_TRUE);RenderShadowVolIntoStencil();glDrawBuffer(GL_BACK);//glDisable(GL_DEPTH_TEST);//glDisable(GL_DEPTH_CLAMP);// prevent update to the stencil bufferglStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP);glStencilFunc(GL_EQUAL, 0x0, 0xFF);glDepthMask(GL_FALSE);glDisable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendEquation(GL_FUNC_ADD);glBlendFunc(GL_ONE, GL_ONE);//glDrawBuffer(GL_BACK);SpecularGBuffer();glDisable(GL_STENCIL_TEST);glDisable(GL_BLEND);glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);glBlitFramebuffer(0, 0, Width, Height, 0, 0, Width, Height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);glBindFramebuffer(GL_FRAMEBUFFER, 0);glDepthFunc(GL_LEQUAL);RenderSkyBox();glDepthFunc(GL_LESS);glClear(GL_DEPTH_BUFFER_BIT);glfwSwapBuffers(window_ptr);glfwPollEvents();}

从零开始的openGL--cs游戏(15) Volume阴影。相关推荐

  1. 从零开始学习OpenGL ES之五 – 材质

    从零开始学习OpenGL ES之五 – 材质 作者: iPhoneGeek 爱疯极客 09-Jan-10 iPhone Development 浏览次数: 411 |  评论 ↓ Tweet Shar ...

  2. Unity Shader: 理解Stencil buffer并将它用于一些实战案例(描边,多边形填充,反射区域限定,阴影体shadow volume阴影渲染)

    本文示例项目Github连接:https://github.com/liu-if-else/UnityStencilBufferUses 最近有两次被人问到stencil buffer的用法,回答的含 ...

  3. [转载]漫谈游戏中的阴影技术

    学习啦~~~~~~ 原文地址:漫谈游戏中的阴影技术作者:flymemory 随着硬件的越来越高端化,各种以前可望而不可及的效果越来越多的应用到网络游戏里.本篇文章是介绍目前游戏中影子的实现方式,它们的 ...

  4. 视频教程-从零开始开发3D跑酷游戏教程-Unity3D

    从零开始开发3D跑酷游戏教程 从业8年以上,学过一点知识,写过一点代码,擅长计算机图形学,擅长unity3d,擅长将抽象的东西讲明白,写看得懂的代码,讲听得懂的课程,不闲聊,不扯淡,满满的干货 洪青霞 ...

  5. 从零开始开发3D跑酷游戏教程-洪青霞-专题视频课程

    从零开始开发3D跑酷游戏教程-1425人已学习 课程介绍         从零开发3D跑酷游戏视频培训课程,教大家从零开始开发一个3D跑酷游戏,涵盖了手势识别.动画系统.水平控制.纵向控制.金币获取. ...

  6. Android 3D游戏开发——Opengl ES游戏引擎实现

    Android 3D游戏 开发 (基础篇)--Opengl ES游戏引擎实现 详情请看:http://www.hztraining.com/bbs/showtopic-26.aspx 课程描述:   ...

  7. OpenGL Sample Rate Shading采样率阴影的实例

    OpenGL Sample Rate Shading采样率阴影 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <vmath.h> # ...

  8. OpenGL定向光的投影阴影

    OpenGL定向光的投影阴影 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL/ ...

  9. OpenGL 点光源的多遍阴影贴图

    OpenGL点光源的多遍阴影贴图 OpenGL点光源的多遍阴影贴图简介 源代码剖析 主要源代码 OpenGL点光源的多遍阴影贴图简介 我们学习了阴影贴图的基础知识-第一次从光源位置通过使用光方向作为视 ...

最新文章

  1. SpringBoot日期格式处理
  2. 小白巷分享 -- Laravel5的新特性之异常处理
  3. 【FTP】FTP 命令模式下 PASV OR PORT
  4. Behave用户自定义数据类型
  5. android 格式化分区,Android FAT分区格式化
  6. java实现文件合并_Java实现文件分割和文件合并实例
  7. 【BZOJ1096】仓库建设,斜率优化DP练习
  8. MORMOT的数据序列
  9. 解决安装驱动时提示的“未签名的驱动程序”警告信息!!
  10. ALTOVA XMLSpy 2013中文版下载教程及简单运用
  11. 小米平板2的win11生存指北
  12. AM5SE-IS防孤岛保护装置如何解决分布式光伏发电过程中的影响?
  13. chrome 打印布局_Chrome 网页打印中的宽度控制
  14. 爱上小西装外套的16个瞬间
  15. swiper滑动时每页都有动画
  16. cisco路由器基本实验之五 配置Loopback接口进行远程登录 (Boson NetSim)
  17. Python 时间序列预测:Hot-winters
  18. html作品简介代码,HTML5的标签的代码的简单介绍 HTML5标签的简介
  19. python全栈生鲜电商_Django REST framework+Vue 打造生鲜电商项目(笔记八)
  20. 32. DDR2内存内部结构-1

热门文章

  1. C# 霍尼韦尔扫码枪扫码打印
  2. 我是一个计算机作文,我是一台电脑作文
  3. 干货|FOF资产配置方案全解析
  4. (转)ENVI端元提取(MNF→PPI→n-D Visualizer)
  5. java线程详细介绍
  6. 互联网手机卡资费对比
  7. 酷狗音乐9.2.0_酷狗音乐安卓版 v9.2.0下载 - 艾薇下载站
  8. 2021-下载酷狗音乐-爬虫-java
  9. python爬取豆瓣top250信息并存入数据库中 | sqlite3
  10. i春秋百度杯CTF比赛2016年12月场writeup