openGL之API学习(四十五)正向渲染和延迟渲染

2023-10-30

如果你是一个游戏开发者,在你使用的图形引擎中或多或少都听说过forward rendering和deferred rendering。通常你必须在你的游戏中选择一种。但它们是什么,彼此之间有什么不同,我们又该如何选择呢?

Modern Graphics Pipelines(现代图形管道)

在开始之前,我们必须要知道一点现代可编程图形管线的一些知识。早些时候,我们被显卡的功能限制,不能去改变每个像素的绘制方式,除了发送一些不同的纹理外,不能去修改顶点的数据。现在时代已经改变,我们能够基于显卡的图形管线进行编程。我们能够发送代码到显卡去改变像素的外观(颜色),使用法线纹理(normal maps)改变它们外观使其变的突起,也可以添加反射(以及大量的现实主义)。

此代码采用几何,顶点和片段着色器的形式,从本质上来说,它们控制显卡如何去渲染对象。

可编程图形管道的简化视图

Forward Rendering(正向渲染/前向渲染)

Forward Rendering 是大多数渲染引擎使用的渲染技术。你给显卡提供几何对象,它将几何对象分解成顶点送入顶点着色器,然后把这些顶点数据插值后分别送入片元/像素着色器,然后在它们被送入屏幕前做最终的渲染处理(模板测试,混合等)。

正向渲染:几何着色器到顶点着色器来分割着色器

这是一个线性的流程,每个几何对象分别通过渲染管线一步步的处理下去并产生最终的图像。

Deferred Rendering(延迟渲染)

延迟渲染,从这个名字来看就意味着渲染是被延迟的,直到所有几何对象都已经通过渲染管线处理后,在最后才应用着色(通过光照来决定最终的像素颜色)并产生最终的图像。

那么为什么要这样来处理呢?

延迟渲染:几何到顶点到片段着色器。传递给多个渲染目标,然后用光照阴影。

延迟照明是对延迟渲染的修改,通过在场景中使用更多遍来减少G缓冲区的大小。

Lighting Performance(光照性能)

标准前向渲染(Forward Rendering)光照的性能消耗也是为什么要另辟蹊径选择其他渲染方式的主要原因。在标准前向渲染(Forward Rendering)管线流程中,每个灯光都会在每个顶点/或片元上执行光照计算,这也就是常说的逐顶点光照和逐片元/像素光照。

如果你在场景中有100个几何对象,并且每个几何对象有1000个顶点,你大约就有100000多变形(非常粗略的计算)。显卡还能够很轻松的处理,但是当这些多边形被发送到片元着色器时, 昂贵的对灯光消耗会使性能急剧下降。开发者可以尝试放置光照计算到顶点着色器减少片元着色器对光照的计算。

不管它是不是此像素上最顶层的片元,还是被遮挡的片元,昂贵的光照计算都会在每个多边形的每个可见片元上执行。如果屏幕的分辨率是1024x768,你有将近800000个像素需要被渲染。你能很轻易的就达到每帧百万级的片元操作。并且大多数的片元还会被剔除(深度测试阶段),那么对于此片元的光照就算就白费了。

如果你要对这样一个达到百万级片元的场景的每一灯光进行渲染,那么你在每一帧将跃升的一个灯光数量x1000000个片元的操作上!想象一下你有一个小镇的街道上面布满点光源!!!!!

计算前向渲染(Forward Rendering)复杂度的公式参见: big O notatio,复杂度公式:O(num_geometry_fragments * num_lights)。你能看到这里的复杂度是和几何对象数量和灯光数量直接相关的。

片元是一个最终可能在屏幕上成为像素的一个”待转像素“,如果在深度测试阶段不被剔除的话,它将在屏幕上成为屏幕的最终像素。现在一些引擎通过其他的方式优化了光照计算,比如:剔除非常远的灯光,组合灯管或使用 Light maps(非常流行的,但是只能是静态的物体)。如果你有大量的灯光需要动态光照的话,我们需要一个更好的解决方案。

Deferred Rendering to the Rescue(前向渲染的救星–延迟渲染)

延迟渲染(Deferred Rendering)是一个减少光照着色对象数量有趣的方法。尤其是对于总的片元对象来说,执行光照的片元数量直接由屏幕的分辨率决定。

延迟渲染(Deferred Rendering)的复杂性,在big O notation中是O(screen_resolution * num_lights)。

现在你能明白了,你有多少的光照数量是由你对灯光数量的使用来决定的。所以你能很高兴的增加你的灯光数量。(这不意味着你可以有无限的几何对象,它们还是要经过管线的及其他处理才能到G-Buffer中。)

The Guts of Deferred Rendering(延迟渲染的细节)

每个几何对象被渲染,但是没有使用光照,使用多目标渲染(multiple render targets),绘制出多个屏幕空间大小的Buffer。深度,法线和颜色分别写入各自的buffers(图像)。然后,这些Buffers和每个灯光像的素颜色进行合成,最后生成最终的图像。

颜色,深度和正常缓冲区。(图片由astrofa,通过维基共享资源。)

最终照明(阴影)使用三个缓冲区生成结果。(图片由astrofa,通过维基共享资源。)

选择哪一个呢?

一个最简短的回答是:如果你使用了大量灯光那么你就该使用延迟渲染(Deferred Rendering)了。但是延迟渲染(Deferred Rendering)也有一些明显的缺点:

•  这个处理需要显卡支持多目标渲染,老的显卡是不支持的,所有不能在上面工作,对于这个是没有变通的方案的,除非强制要求客服换显卡。

• 它需要高带宽的显卡,你要发送大的Buffer数据,老大的显卡可能处理不了。对于这个也没有变通的方案的,除非强制要求客服换显卡。

• 你不能使用透明对象。(除非你联合 使用deferred rendering 和Forward Rendering )。

• 没有抗锯齿。

• 仅有一个类型的材质被允许,除非你使用了被叫做Deferred Lighting的延迟渲染修改。

• 阴影依赖于光照的数量,延迟渲染没有解决任何阴影的问题。

如果你没有大量的灯光或者你想能够在比较老的显卡上允许,你应该选择使用前向渲染(Forward Rendering)并且替换你的灯光使用静态光照贴图。这个结果看起来还是令人吃惊的。

总结

我希望摆脱一些光照的主题。在这里你的选择是解决渲染问题,但是在游戏开始之前就做出正确的选择是非常重要的,因为可以避免日后的修改。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

openGL之API学习(四十五)正向渲染和延迟渲染 的相关文章

  • 三角形未在 OSX 上的 OpenGL 2.1 中绘制

    我正在学习有关使用 OpenGL 在 Java 中创建游戏引擎的教程 我正在尝试在屏幕上渲染一个三角形 一切运行良好 我可以更改背景颜色 但三角形不会显示 我还尝试运行作为教程系列的一部分提供的代码 但它仍然不起作用 教程链接 http b
  • GLSL - 计算表面法线

    我有一个用 GLSL 编写的简单顶点着色器 我想知道是否有人可以帮助我计算表面的法线 我正在 升级 一个平面 所以当前的灯光模型看起来 很奇怪 这是我当前的代码 varying vec4 oColor varying vec3 oEyeNo
  • glutPostRedisplay 不在循环内工作

    我试图让一个人在 y 轴上跳跃 所以我使用 2 秒的循环 第一秒它应该向下移动并弯曲膝盖 第二秒它应该向上移动 然后在起始位置完成 现在我刚刚开始让这个人在第一秒内跪下并弯曲膝盖 我还没有编写动画的其余部分 问题是 glutPostRedi
  • OpenGL 和加载/读取 AoSoA(混合 SoA)格式的数据

    假设我有以下 AoSoA 格式的简化结构来表示顶点或点 struct VertexData float px 4 position x float py 4 position y 也就是说 每个实例VertexData存储4个顶点 我见过的
  • 使用 Qt 在 xoverlay 之上绘制

    我希望在使用 Xoverlay 渲染的视频流之上绘制一些 UI 我正在使用 gstreamer 播放视频并使用 xoverlay 在 xvimagesink 上渲染它 我的小部件继承自 QGLWidget 我希望使用 QPainter 绘制
  • GLSL 棋盘图案

    我想用跳棋来遮蔽四边形 f P 下限 Px 下限 Py mod2 我的四边形是 glBegin GL QUADS glVertex3f 0 0 0 0 glVertex3f 4 0 0 0 glVertex3f 4 4 0 0 glVert
  • 对齐坐标系

    Let s say I have 2 coordinate systems as it is shown in image attached 如何对齐这个坐标系 我知道我需要将第二个坐标系围绕 X 平移 180 度 然后将其平移到第一个坐标
  • 使用draw()而不是eventloop时的pyglet

    我正在尝试用 pyglet 画一个圆 但当我使用 draw 函数而不是 app run 循环时 它是不可见的 有什么建议我可以做什么吗 谢谢 from math import from pyglet gl import window pyg
  • SDL 鼠标位置调整大小后裁剪

    我在 SDL 中的鼠标位置上遇到了一些奇怪的行为 如果我将窗口大小调整得更大 则任一鼠标事件的 x y 位置似乎都限制为原始窗口的宽度和高度 如果我缺少一些函数调用来告诉 SDL 鼠标区域的大小已增加 应用程序的相关部分 void Resi
  • 为什么OpenGL使用float而不是double? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 无法在 WSL2 上运行 OpenGL

    我尝试在 WSL2 上运行 OpenGL 代码 但在尝试运行可执行文件时出现以下错误 GLFW error 65543 GLX Failed to create context GLXBadFBConfig Unable to create
  • OpenGL - 两个纹理的幂

    OpenGL 使用二次幂纹理 这是因为由于 MipMapping 某些 GPU 只接受 2 的幂纹理 当绘制比实际更大的纹理时 使用这些二次方纹理会导致问题 我想到了一种方法来解决这个问题 即仅在我们使纹理小于实际大小时使用 PO2 比率
  • GL_CULL_FACE使所有对象消失

    我正在尝试在 openGL3 3 中创建一些简单的多边形 我有两种类型的对象 具有以下属性 对象 1 10 个顶点 按顺序在下面列出 存储在GL ARRAY BUFFER并使用GL TRIANGLE FAN v x y z w v 0 0
  • 在 2D 纹理上绘制的红色矩形在绘制后立即消失

    跟随我的另一个问题 https stackoverflow com questions 18477291 render an outlined red rectangle on top a 2d texture in opengl 1847
  • 三角形纹理映射OpenGL

    我正在开发一个使用 Marching Cubes 算法并将数据更改为 3D 模型的项目 现在我想在 OpenGL 中为我的 3D 模型使用纹理映射 我首先尝试了一个简单的示例 它将图片映射到三角形上 这是我的代码 int DrawGLSce
  • 根据 GLSL 中向量的特定分量执行最小-最大的最快方法?

    我需要在我的 GLSL 代码中多次调用这种函数 vec2 minx vec2 a vec2 b if a x lt b x return a else return b 我担心过度分支 有没有办法避免 if else 结构 我建议使用 GL
  • 使用 GLSL 直接在着色器中从位置计算平移矩阵

    我正在开发 C OpengL 程序以及 GLSL 顶点和片段着色器 我正在创建同一对象的多个实例 我只需要改变实例之间的对象位置 这是我所做的 我正在使用一个统一变量 它是一个变换矩阵数组 每个矩阵代表一个对象实例 MVP 也是一个变换矩阵
  • 如何使用边缘和内部镶嵌因子完成三角形面片镶嵌?

    I am just learning tessellation and i came across with below example for triangle patch tessellation but i am not sure h
  • 在 OpenGL 中只使用纹理的 Alpha 通道?

    嘿 我正在尝试将恒定颜色绘制到帧缓冲区 并使用 RGBA 纹理中的 Alpha 通道将其混合 我一直在研究 glBlendFunc 和 glBlendColor 但似乎无法找到忽略纹理中的 RGB 值的方法 我想我必须自己提取 alpha
  • OpenGL:如何检查用户是否支持glGenBuffers()?

    我检查了文档 它说 OpenGL 版本必须至少为 1 5 才能制作glGenBuffers 工作 用户使用的是1 5版本但是函数调用会导致崩溃 这是文档中的错误 还是用户的驱动程序问题 我正在用这个glGenBuffers 对于VBO 我如

随机推荐

  • 尤里的复仇Ⅰ 小芳!

    尤里的复仇 小芳 作者 admin 时间 2021 06 15 分类 封神台 第一章 为了女神小芳 找到get参数id 使用 1 1 or 1 1 1 or 1 2 测试 发现存在sql注入 最终payload为 id 1 and 1 2
  • XMind中的 “甘特图”视图

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 甘特图 视图 当所有任务信息添加完成后 点击 任务信息 视图底部的 显示甘特图 按钮 XMind将弹出 甘特图 视图 所有任务信息将不同属性的线条展现 如果此时切换画布或者
  • math模块

    math 模块是Python中的标准模块 并且始终可用 要在此模块下使用数学函数 您必须使用导入模块import math 它提供对基础C库函数的访问 导入数学函数库 import math 查看 math 查看包中的内容 print di
  • C99与C89主要区别

    http www cnblogs com xiaoyoucai p 6146784 html
  • P4162 [SCOI2009]最长距离

    题目链接 这道题数据范围比较小 所以方法还是比较暴力的 思路 先按每个格子的状态 让所有格子与他周围的格子连一条权值为它连向那个格子的值 0或1 然后我们n方枚举所有格子跑最短路 最短路即为从起点到终点的最小障碍数 然后我们枚举所有最短路
  • Spring的两种定时器

    1 spring学习系列 定时器一TimerTask spring定时器一般有两种 TimerTask Quartz 本节只讲TimerTask 需要的包 aopalliance 1 0 jar commons logging 1 1 1
  • 使用html2Canvas跟jspdf将一部分页面生成PDF

    刚好碰到这么一个需求 前端需要将后端返回的json对象数据生成表单样式的pdf文件 首次接触所以简单记录一下 经过反复查找大致流程为 现在页面画一个表单 gt 拿到数据将数据放表单中 gt 给表单最外层加个ref利用html2Canvas生
  • Linux:NTP服务离线安装及配置

    0 常用命令 rpm qa grep ntp 查询已安装的ntp版本信息等 service ntpd status 查询ntp服务状态 service ntpd start 启动 service ntpd stop 停止 service n
  • hack the box - tier0

    Tier0 Meow Recommended Academy Modules INTRO TO ACADEMY STARTING POINT Tier 0 Machines Tags Enumeration Telnet External
  • 嵌入式linux解决方法

    一 问题描述 u boot version 2016 03 ubuntu version 18 04 ubuntu中环境配置正确 通过其他客户端能够挂载上 但是使用uboot得nfs下载命令会报错 gt nfs 80800000 192 1
  • CSS中表格以及表单的属性以及运用

    一 表格 按照一定的顺序摆放数据 表格是由一些单元格组成 1属性 border边框 cellspacing 单元格与单元格之间的距离 cell padding 单元格 边框和内容之间的距离 align 表格水平的位置 tr行 align 调
  • 并发编程NO.2

    并发编程 共享模型之管程 4 1共享资源问题 临界区 一个程序运行多个线程本身是没问题的 问题出在多个线程访问共享资源 多个线程读共享资源没有问题 但是多线程对共享资源进行读写操作 就会有问题 一段代码内如果存在对共享资源的多线程读写操作
  • leetcode 2. 两数相加

    2023 9 14 这道题还是有点难度 需要维护一个进位值 构造一个虚拟头节点dummy 用于结果的返回 还要构造一个当前节点cur 用于遍历修改新链表 整体思路就是长度短的链表需要补0 然后两链表从头开始遍历相加 要考虑进位 需要注意的点
  • [PHP] CURL获取cookie,模拟登录获取数据

    需求 通过CURL先登录 然后获取登录后的cookie 在请求数据接口的时候带上这个cookie即可 直接贴代码 1
  • 决策树分箱-特征工程之数据离散化处理-基于python实现

    一 简介 离散化是通过创建一组跨越变量值范围的连续区间将连续变量转换为离散变量的过程 1 1 离散化有助于处理异常值和高度偏斜的变量 离散化通过将这些值 与分布的剩余内点值一起放入较低或较高的区间来帮助处理异常值 因此 这些异常值观察不再与
  • rosbag与csv等格式转换

    1 rosbag 转换成csv 参看 https blog csdn net cliukai article details 94554350 具体就是 rostopic echo b
  • Cocos Creator 用JS脚本实现游戏背景的无限滚动

    首先是实现的一个原理 使用2张相同的图片 让它们在脚本中不停的移动 用y值的减少来实现 当有图片离开场景时 给此图片的y重新赋值 相当于位置的重置 在update中无限调用背景移动的函数 我的canvas 位于上方的图片结点名称为BG 下方
  • 迷宫游戏源码

    mainwindow h ifndef MAINWINDOW H define MAINWINDOW H include MAZE h include
  • 【leetcode每日一题】479. 最大回文数乘积

    最大回文数乘积 题目来源 题意 思路 代码 注意 题目来源 点这里 题意 给定一个整数 n 返回可表示为两个 n 位整数乘积的最大回文整数 因为答案可能非常大 所以返回它对 1337 取余 思路 开始刷leetcode每日一题的Day3 我
  • openGL之API学习(四十五)正向渲染和延迟渲染

    如果你是一个游戏开发者 在你使用的图形引擎中或多或少都听说过forward rendering和deferred rendering 通常你必须在你的游戏中选择一种 但它们是什么 彼此之间有什么不同 我们又该如何选择呢 Modern Gra