- 博客(946)
- 收藏
- 关注
原创 GLFW (3)简单示例
#include <GLFW/glfw3.h>int main(void){ GLFWwindow* window; /* Initialize the library */ if (!glfwInit()) return -1; /* Create a windowed mode window and its OpenGL context */ window = glfwCreateWindow(640, 480, "Hello
2022-04-28 22:34:51
735
原创 渲染管道(4)像素阶段“透明度测试”
1. Alpha测试/ 透明度测试(Alpha Test)透明度测试采用一种很极端的机制,通过片元数据,可以获取该片元的alpha值,如果alpha值小于某个阈值,则直接将该片元丢弃,不进行渲染(即只渲染透明度在某一范围内的片元),可以用来做一些树叶镂空的效果。alpha测试本身消耗较大,性能较低,颜色一般采用RGBA四分量来进行表示,其中颜色的Alpha值用来表示物体本身的不透明度(alpha=1表示完全不透明,alpha=0表示完全透明)。Alpha测试可以根据片段颜色的Alpha值来裁剪
2022-04-14 07:14:51
331
原创 渲染管道(4)像素阶段“模板测试”
1. 模板测试(Stencil Test)GPU会首先读取模板缓冲区中该片元位置的模板值,然后将该值和读取到的参考值进行比较,这个比较函数可以是由开发者指定的,例如小于时舍弃该片元,或者大于等于时舍弃该片元。如果这个片元没有通过这个测试,该片元就会被舍弃。不管这个片元有没有通过测试,我们都可以根据模板测试和后面的深度测试结果来修改模板缓冲区,我们可以根据不同的结果修改模板缓冲区,修改操作也是由开发者设定。eg. 在模板测试失败时,可以保持模板缓冲区不变,也可以在对应的位置+1等等。模板测试默认是
2022-04-14 06:56:07
431
原创 渲染管道(4)像素阶段“Alpha混合”
1. Alpha混合 (Alpha Blending)GPU会取出源颜色和目标颜色,将两种颜色进行混合,可以根据片段的alpha值进行混合,用来产生半透明的效果。OpenGL可以通过glEnable(GL_BLEND)来开启混合1.1 混合方程源颜色:该片元在片元着色器计算后得到的颜色目标颜色:已经存在颜色缓冲中的颜色其中,四个变量分别表示源颜色、源因子值、目标颜色和目标因子值。方程常常与透明通道(alpha 通道)相关。eg.通过glBlendFuncSeparate()、gl
2022-04-14 06:51:46
801
原创 渲染管道(4)像素阶段“混合”
混合(Blend)一个片元经过层层测试,最后进行混合处理.对于半透明物体,我们就需要使用混合操作来让这个物体看起来是透明的。对于不透明物体,开发者可以关闭混合(Blend)操作。这样片元着色器计算得到的颜色值就会直接覆盖掉颜色缓冲区中的像素值。开发者可以选择 开启/关闭 混合功能 1.1 步骤...
2022-04-14 06:47:05
204
原创 渲染管道(4)像素阶段“深度测试”
1. 深度测试(Depth Test)通过深度测试来模拟实现近处的物体遮挡远处的物体。1.1 原理它通过将深度缓存中的值和当前片元的深度进行比较,计算是否需要更新深度缓存和颜色缓存,如果不需要则将该片元丢弃,如果通过了,则由开发者决定是否用这个片元的深度来覆盖原有的深度,通过开启/关闭深度写入来实现。大量的被遮挡片元在该阶段被剔除,而在之前它们同样进行了计算,这占用了大量的GPU资源。1.2 步骤 1.3 效果图...
2022-04-14 06:44:15
574
原创 渲染管道(4)像素阶段“子流程”
1. 子流程最初像素着色器的输出只能是混合阶段,但是现在可以输出到多个 buffer 里面,称之为 MRT(multiple render target). 这样就可以同时输出多种信息,一个典型例子是延迟渲染
2022-04-13 08:16:56
192
原创 渲染管道(3)光栅阶段五“逐片元操作”
1. 逐片元操作(Per-Fragment Operations)/合并阶段主要就是对片元进行测试(Test)以及合并(Merge)。不可编程,但可通过参数高度可配置性OpenGL称为逐片元操作(对每一个片元进行操作)Direct X 称为输出合并(Output-Merger合并)渲染管线的最后一步1.1 测试决定每个片元的可见性。可通过参数配置来控制,涉及到很多测试。为什么要进行测试呢?因为屏幕上的一个像素可能存在多个片元进行竞争,通过测试等规则,可以决定哪个片元最终能够渲染到屏幕上
2022-04-13 07:55:19
493
原创 渲染管道(3)光栅阶段四“片元着色器”
1. 片段着色器(Fragment Shader)/像素着色器(Pixel Shader)DirextX称为像素着色器(Pixel Shader)用来决定屏幕上像素的最终颜色。为每个片元计算颜色,包括光照计算以及阴影处理等高级效果。如何计算由开发者配置,比如通过三角形重心坐标插值计算颜色值,计算阴影,或者直接用纹理覆盖。可编程,可选。片元经过一系列的测试(深度测试,透明度测试等)才有可能被选上而转变为像素,这也是将之称为预备像素的原因。如果一个片元被选定作为一个像素,经过一系列的变换,最终将转变
2022-04-13 07:50:43
1527
原创 渲染管道(3)光栅阶段二“图元组装”
1.图元组装 (Primitive Assembly)/三角形设置(Triangle Setup)图元组装将输入的顶点组装成指定的图元,需要关心顶点之间的关系,依据顶点的数据和信息,将需要连接的顶点连线,组成一个个面。输入:屏幕映射后,会将顶点的屏幕坐标系下的位置信息,以及存储的额外信息:深度值(z坐标)、法线方向、视角方向等数据。不可编程、不可配置,GPU固定实现。顶点不一定会连线,单个顶点,或者顶点的连线,也可作为图元,图元不一定是一个面。图元组装阶段会进行裁剪和背面剔除相关的优化,以减少进
2022-04-13 07:44:37
538
原创 渲染管道(3)光栅阶段三“三角形遍历”
1. 三角形遍历(Triangle Traversal)/扫描转换(scan conversion)不可编程且不可配置,GPU固定实现。将变换到屏幕空间的图元离散化为片元的过程,输出一个片元序列。根据上一个阶段的计算结果来判断一个三角网格覆盖了哪些像素,会检查每个像素是否被一个三角形网格所覆盖。如果屏幕上某个像素点被判断为被图元覆盖,则会生成对应像素大小的片元(fragment)。并使用三角网格3个顶点的顶点信息对整个覆盖区域的像素进行插值。1.1step1. 进行逐像素检查操作, 即检查每个图元
2022-04-13 07:40:24
943
原创 渲染管道(3)光栅阶段一“总览”
1. 光栅阶段(Rasterization)将一系列带有深度信息的屏幕坐标点及其附属的其他信息转移到屏幕上的每个像素。光栅化是个离散化的过程,将3D连续的物体转化为离散屏幕像素点的过程。 光栅化会确定图元所覆盖的片段,利用顶点属性插值得到片段的属性信息,然后送到片段着色器进行颜色计算和混合。从二维顶点的屏幕空间(包含深度值, 及相关着色信息), 到屏幕上的像素转换由几何阶段确定屏幕上的顶点, 颜色, 纹理坐标后, 给每个像素(Pixel)正确配色, 绘制整幅图像1.1 多个阶段图元装
2022-04-13 07:28:43
290
原创 渲染管道(2)几何阶段五“投影”
1. 投影projection将顶点从视图空间转换到裁剪空间(齐次裁剪空间):也就是 view space --》 clip space:将视体变换到一个单位立方体内(规范立方体(Canonical View Volume, CVV, 对角顶点为(-1, -1, -1), (1, 1, 1))不可编程且不可配置,GPU硬件实现。投影完成后顶点就被约束在裁剪空间(摄像机空间), 实现了从 3d 转为 2d,可进行下一步的裁剪操作。z 坐标将不会保存于得到的图片中, z 坐标信息仍会存储在 z-bu
2022-04-13 06:13:28
280
原创 渲染管道(2)几何阶段四“几何着色器”
1. 几何着色(Geometry Shader)可编程,可选的阶段。将输入的点或线扩展成多边形,可以将一个或多个顶点转变为完全不同的基本图形(或称为图元),从而生成比原来多得多的顶点。eg. 可以通过让每个三角形创建线边,将三角形网格转换为线框。或者,可以将这些线替换为面向观察者的四边形,从而使线框渲染的边缘更厚。输入信息:完整的图元(比如,点),为图元(点,线,三角面)输出信息:一个或多个其他的图元(比如,三角面),或者不输出任何的图元。可以对顶点进行增删改操作并行程度低,调用硬件困难,性
2022-04-12 08:21:46
289
原创 渲染管道(2)几何阶段三“曲面细分着色器”子阶段
1. 三个子阶段Hull-Shader Stage(HS细分控制)可编程,操作人员设定细分的操作与数量。接收控制点信息, 与一些系数发送到 Domain Shader, 同时发送一些系数到 Tesselator。可以指挥GPU如何对顶点进行曲面细分操作,但是还未具体执行细分。Tessellation Stage(TS细分操作)不可编程,由硬件管理,GPU会根据 Hull-Shader Stage 阶段对曲面细分的指令,执行曲面细分,这个阶段才是真正的曲面细分执行阶段。Domain-Shader
2022-04-12 08:08:55
307
原创 渲染管道(2)几何阶段三“曲面细分着色器”
1. 曲面细分着色器 (Tessellation Shader)可编程,此阶段可选。将曲面进一步划分为更小的子曲面(增加了更多的顶点),主要是对三角面进行细分,以此来增加物体表面的三角面的数量。借助它可以实现细节层次(LOD,Level-of-Detail)的机制,使得离摄像机越近的物体具有更加丰富的细节,而远离摄像机的物体具有较少的细节。通过 Tesselation, 原有的模型增加了大量 vertex, 再应用 Displacement Mapping(存储高度信息, 真正改变顶点位置), 改变
2022-04-12 08:05:13
414
原创 渲染管道(2)几何阶段二“顶点着色器”
1. 顶点着色器 (Vertex Shader)可编程。输入是单个顶点(以及属性), 输出的是经过变换后的顶点。1.1 两个主要的任务计算顶点的位置(vertex position)MVP变换的模型变换和视图变换,将每个顶点在虚拟空间中的 3D 位置转换为它出现在屏幕上的 2D 坐标(以及 Z 缓冲区的深度值)可以操纵法线、位置、颜色和纹理坐标、光照信息等属性,提供所有程序员想要的顶点输出数据(vertex output data)1.2A Vertex Shader must h
2022-04-12 07:20:47
304
原创 渲染管道(1)子流程
1. 3个阶段的子模块1.1 几何阶段工作内容:顶点坐标变换、光照、裁剪、投影以及屏幕映射等。工作地点:GPU计算单元。工作产出:变换、投影后的顶点坐标、颜色、以及纹理坐标,一堆三角形面片,装配后的图元(根据顶点连接,还原出的模型网格结构)。1.2 光栅化阶段图元装配(三角形组装)、三角形遍历、片段着色器、逐片元操作。...
2022-04-11 23:24:41
304
原创 渲染管道(3)几何阶段二“坐标转换”
1. 概述 模型变换 视图变换model space模型空间 --> world space世界空间 --> view space观察空间最后投影阶段会将图像投影到屏幕上,那个叫做投影变换,这三个变换矩阵称为 MVP矩阵1.1step1. 局部坐标->世界坐标模型的每个顶点都可以由世界坐标表达出来,由物体坐标到
2022-04-10 11:58:17
585
原创 渲染管道(3)几何阶段一“概述”
多个阶段Vertex Shading顶点着色Projection投影Clipping裁剪Screen Mapping屏幕映射
2022-04-10 11:38:03
286
原创 渲染管道(2)应用阶段“顶点数据”
1. 定义CPU用来为GPU后面的顶点着色器等阶段提供处理的数据,是渲染管线的数据主要来源。(在DirectX中在输入装配阶段(Input Assembler State)完成)1.1 数据内容模型信息:顶点坐标、纹理坐标,顶点法线、UV、切线、顶点颜色、索引列表…变换矩阵:世界变换矩阵、VP矩阵(根据摄像机位置和fov等参数构建)灯光、材质参数:shader、材质参数、灯光信息1.2 图元顶点数据在流水线中以图元的方式进行处理,常见的图元有:点、线和三角面。eg. 在OpenGL,对
2022-04-09 16:19:16
503
原创 渲染管道(2)应用阶段“功能”
1. 应用程序应用程序使用高级编程语言(C、C++、JAVA 等)进行开发,主要和CPU、内存打交道。eg, 碰撞检测、场景图建立、空间八叉树更新、视锥裁剪等经典算法都在此阶段执行。主要工作为:准备场景数据,例如摄像机的位置、视锥体、场景中包含了哪些模型、使用了哪些光源等;设置渲染状态,包括但不限于使用的材质属性(漫反射颜色、高光反射颜色)、使用的纹理、使用的Shader,是否透明等;CPU的其他工作:粗粒度剔除工作,把那些不可见的物体剔除出去,这样就不需要再移交给几何阶段进行处理;物
2022-04-09 16:09:57
236
原创 渲染管道(1)整体流程
1. GPU渲染流程即是“给定视点、三维物体、光源、照明模式,和纹理等元素,如何绘制一幅二维图像”。将物体3D坐标转变为屏幕空间2D坐标为屏幕每个像素点进行着色。2. 4个阶段2.1 . Application阶段定义当下要构建世界的模型图元, 对 GPU 中的各个 Shader 进行编程和参数设定。开发者通过程序对图元数据进行配置和调控, 由于可以对该阶段进行完全控制, 可以通过更改实现方法来改变性能,通常有: 碰撞检测, 加速算法, 输入检测, 动画, 力反馈, 纹理动画, 变换
2022-04-09 15:24:30
442
原创 图形基础 GPU架构(5)并行计算
1. GPU对每个数据进行独立的并行计算,多个数据并行运算的时间和1个数据单独执行的时间是一样的。eg. 提取2D 图像上每个像素点的颜色值
2022-04-09 15:15:27
305
原创 图形基础 GPU架构(5)GPU vs CPU
特点|CPU|GPU||–|–|–|–||双目算术运算符| +cpuCPU本质上是一个标量计算模型,计算单元偏少,主要针对复杂控制和低延迟而非高带宽优化,大部分面积为控制器和寄存器。GPU拥有更多的ALU(Arithmetic Logic Unit,逻辑运算单元)用于数据处理,而非数据高速缓存和流控制,适合对密集型数据进行并行处理。CPU执行计算任务时,一个时刻只处理一个数据,不存在真正意义上的并行GPU具有多个处理器核,在一个时刻可以并行处理多个数据CPU 的 RAM 池较大,速度慢.
2022-04-09 15:06:35
290
原创 图形基础 GPU架构(4)GPU & CPU
1. GPU渲染功能step1. 多边形生成:完成3D图形的生成,将图形映射到相应的像素点上。step2. 多边形上颜色:对每个像素进行计算确定最终颜色并完成输出。2. CPU & GPU2.1 Draw Call命令draw call会给出一个需要被渲染的图元(primitives)列表(该列表不会包含渲染状态,渲染状态在之前已经设置过了),GPU会根据渲染状态和所有的输入顶点数据来进行计算,最终形成屏幕上的图像。CPU向GPU发送的指令会被压栈入一个命令缓冲区,GPU一次取出执行
2022-04-09 15:01:25
359
原创 图形基础 GPU架构(3)功能
1. 硬体T&L、立方环境材质贴图和顶点混合、纹理压缩和凹凸映射贴图、双重纹理四像素256位渲染引擎等支持vertex programmability 和fragment programmability支持IEEE32 位浮点运算支持4 元向量,4 阶矩阵计算提供分支指令,支持循环控制语句具有高带宽的内存传输能力(>27.1GB/s)支持1D、2D、3D 纹理像素查询和使用,且速度极快支持绘制到纹理功能(Render to Texture,RTT)1.1 T&L(T
2022-04-09 14:38:23
430
原创 图形基础 GPU架构(1)背景
1. 图形处理器GPU(Graphics Processing Unit)进行各种绘制计算机图形所需的运算,包括顶点设置、光影、像素操作等。GPU实际上是一组图形函数的集合,而这些函数由硬件实现。1.1 背景早期的显卡只包含简单的存储器和帧缓冲区,它们实际上只起了一个图形的存储和传递作用。传统 Z-buffer 算法不能满足新的应用需求:强算力 ,比如支持碰撞检测、近似物理模拟;图像透明性、高质量反走样、运动模糊、景深和微多边形染色等问题 ,不能很好支持实时光线跟踪、Reyes(Render
2022-04-09 00:20:33
278
原创 c++新特性11 (12)weak_ptr
1. 用于避免shared_ptr相互指向产生的环形结构,造成的内存泄漏:“死锁”内存都没有释放。struct A;struct B;struct A { std::shared_ptr<B> pointer; ~A() { std::cout << "A 被销毁" << std::endl; }};struct B { std::shared_ptr<A> pointer; ~B() {
2022-04-08 00:03:21
468
原创 c++新特性11 (12)weak_ptr其他函数
~weak_ptr() noexcept { this->_Decwref(); } weak_ptr& operator=(const weak_ptr& _Right) noexcept { weak_ptr(_Right).swap(*this); return *this; } template <class _Ty2> weak_ptr& operator=(...
2022-04-07 00:00:05
582
1
原创 c++新特性11 (11)unique_ptr
有一个_Compressed_pair成员,类似于pair<key,value>队// CLASS TEMPLATE unique_ptr SCALARtemplate <class _Ty, class _Dx /* = default_delete<_Ty> */>class unique_ptr { // non-copyable pointer to an objectpublic: using pointer = typenam.
2022-04-05 15:48:43
1142
原创 c++新特性11 (12)weak_ptr类定义
1. 类定义// CLASS TEMPLATE weak_ptrtemplate <class _Ty>class weak_ptr : public _Ptr_base<_Ty> { // class for pointer to reference counted resourcepublic: constexpr weak_ptr() noexcept {} weak_ptr(const weak_ptr& _Other) noexcept {
2022-04-04 23:57:19
573
原创 c++新特性11 (10)shared_ptr六”构造函数unique_ptr参数“
1. 构造函数shared_ptr p(u) p从unique_ptr u中接管了对象的所有权;将u置为空template <class _Ux, class _Dx, enable_if_t<conjunction_v<_SP_pointer_compatible<_Ux, _Ty>, is_convertible<typename unique_ptr<_Ux, _Dx>::poin
2022-04-02 23:38:40
632
原创 c++新特性11 (9)智能指针一”_Compressed_pair类“
template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty firstpublic: _Ty2 _Myval2; using _Mybase = _Ty
2022-04-02 23:36:15
870
原创 c++新特性11 (10)shared_ptr八”shared_ptr类“
template <class _Ty>class shared_ptr : public _Ptr_base<_Ty> { // class for reference counted resource managementprivate: constexpr shared_ptr() noexcept = default; constexpr shared_ptr(nullptr_t) noexcept {} // construct empty shared_
2022-04-02 22:10:53
287
原创 STL源代码分析(ch2 内存分配)uninitialized_fill
1. uninitialized_fill(ForwardIter first, ForwardIter last, const T& value)// uninitialized_fill// 在 [first, last) 区间内填充元素值template <class ForwardIter, class T>void uninitialized_fill(ForwardIter first, ForwardIter last, const T& value)
2022-04-02 06:55:04
154
原创 c++新特性11 (10)shared_ptr七reset
1. 使用场景shared_ptr p(u) p从unique_ptr u中接管了对象的所有权;将u置为空 1.1 函数定义template <class _Ux, class _Dx, enable_if_t<conjunction_v<_SP_pointer_compatible<_Ux, _Ty>, is_convertible<typename unique_ptr<_Ux, _Dx>::point
2022-04-02 06:47:27
1884
原创 c++新特性11 (10)shared_ptr五”构造函数“
1. 几种构造函数shared_ptr p(q) p管理内置指针q所指的对象;q必须指向new分配的内存,且能够转换为T类型shared_ptr p(q,d) p接管了内置指针q所指向的对象的所有权。q必须能转换为T类型。p将使用可调用对象d来代替deleteshared_ptr p(p2,d) p是shared_ptr p2的拷贝,唯一的区别是p将使用可调用对象d来代替delete1.1 如果参数是shared_ptr引用,那么调用底层的construct函数,计算器加1,否则如果是&&
2022-04-02 00:03:34
1759
原创 c++新特性11 (10)shared_ptr四”_Ptr_base 类“
template <class _Ty>class _Ptr_base { // base class for shared_ptr and weak_ptrpublic: using element_type = remove_extent_t<_Ty>; _NODISCARD long use_count() const noexcept { return _Rep ? _Rep->_Use_count() : 0; }
2022-04-01 23:54:41
481
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅