OpenGL3.3_C++_Windows(24)

渲染平行光阴影

阴影作用:

  • 有了阴影的渲染,更容易地区分出物体之间的位置关系,
  • 如何判断片段是否在阴影中?

普通思路:

  • 以光的位置为视角进行渲染,我们绘制一条从光源出发的射线,测试更新射线经过的所有片段,与当前min最近片段比较,如果更远,就在阴影中

弊端:

  • 射线上的成千上万个点进行遍历是个极端消耗性能,所以换种思路,利用深度缓冲

深度缓冲:

  • 深度缓冲大小符合窗口的宽高,当运行深度测试时,每个像素的深度值和已经存储在这个像素的深度值(深度缓冲)进行比较,根据深度测试函数,决定片段是否丢弃

深度/阴影/shadow Mapping贴图

  • 从光源的透视图 来渲染场景,并把深度值的结果储存到纹理中,深度值因为会不断测试更新,最后的结果,就是最近的片段的深度值,通过纹理坐标,可以对它进行采样,获取深度值

T变换

  • 来自光源的视图投影矩阵,可以将任何三维位置(从世界坐标)转变到光源的可见坐标空间

如何利用深度贴图判断片段是否在阴影中?

  • 首先T变换 到光源的坐标空间里,使用生成的深度贴图计算片段是否在阴影之中,z深度 如果 > 片段的深度缓冲的深度值,则在阴影中

运算:

创建新的帧缓冲

  • 因为要对深度值采样,所以应存储在纹理附件(非渲染缓冲对象附件),应用的纹理格式为GL_DEPTH_COMPONENT,
  • 注意:不包含颜色缓冲的帧缓冲对象是不完整的,所以我们需要显式告诉OpenGL我们不适用任何颜色数据进行渲染。glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE);

平行光源空间的T变换矩阵

  • LookAt()计算光(位置+看的方向)的view矩阵(实质,将物体坐标变换到相机坐标的视角下),

  • 如果使用一个所有光线都平行的定向光,使用正交投影矩阵,否则点光源和聚光灯,使用透视投影矩阵(因为投影矩阵实质,是决定可见的范围,以及范围的形状,光空间的范围,即光线的散射组成的范围,被光覆盖的范围)

渲染到深度贴图

  • 启用帧缓冲,渲染场景,使用的新glsl中,将每个顶点变换到光空间,从而深度值保存到了深度纹理附件中,fragment什么都不用做,我们只需要深度缓冲(默认更新),也可以手动设置gl_FragDepth = gl_FragCoord.z;

//深度缓冲视觉化

  • 这次渲染quad,并应用深度纹理附件作为quad 的纹理。
  • 但是注意:正交不受深度值影响,透视投影矩阵,当深度缓冲视觉化经常会得到一个几乎全白的结果,深度变成了非线性的深度值,只有距离很近,颜色亮度才会骤降。
  • 解决方案就是变为线性深度值。

深度缓冲视觉化

渲染阴影:Fragment glsl

  • 将要产生阴影的物体,在vs中将世界空间顶点位置转换为光空间,传入fs,计算出一个shadow值,当fragment在阴影中时是1.0,在阴影外是0.0
  • 将(1 - shadow )* 其他冯氏颜色分量(由于当shadow = 1的时候(在阴影),结果颜色为0),由于阴影不会是全黑的,把ambient分量从乘法中剔除。
  • 这样保证,当片断位于阴影,结果为ambient * 其他冯氏颜色分量,当非阴影 = ((ambient + 1 * 其他冯氏颜色分量

计算阴影():

  • 光空间的片段位置(被判断的像素)和第一个渲染阶段得到的深度贴图(取深度值)
    • 光空间片段位置转换为裁切空间的标准化设备坐标。
    • 当运行到gl_Position时,OpenGL自动进行一个透视除法,x、y、z元素除以向量的w元素来实现,我们必须自己做透视除法
    • 因为来自深度贴图的深度在0到1的范围,我们再次将NDC坐标变换为0到1的范围
    • 从深度贴图,采样片段坐标,对应的深度值,如果片段的z高于采样的深度值,则表明片段在阴影中,返回1,否则返回0
相关推荐
MZ_ZXD0014 小时前
springboot汽车租赁服务管理系统-计算机毕业设计源码58196
java·c++·spring boot·python·django·flask·php
岁忧6 小时前
(nice!!!)(LeetCode 每日一题) 679. 24 点游戏 (深度优先搜索)
java·c++·leetcode·游戏·go·深度优先
小欣加油6 小时前
leetcode 3 无重复字符的最长子串
c++·算法·leetcode
zylyehuo9 小时前
C++基础编程
c++
tt55555555555510 小时前
C/C++嵌入式笔试核心考点精解
c语言·开发语言·c++
lg_cool_10 小时前
Qt 中最经典、最常用的多线程通信场景
c++·qt6.3
科大饭桶11 小时前
C++入门自学Day14-- Stack和Queue的自实现(适配器)
c语言·开发语言·数据结构·c++·容器
tt55555555555511 小时前
字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密
c++·算法·矩阵
rainFFrain12 小时前
Boost搜索引擎项目(详细思路版)
网络·c++·http·搜索引擎
long_run13 小时前
C++之模板函数
c++