之前自己总结的一些opengl的知识点,放上来供参考。如有问题,望高人指点。
OpenGL概念
•OpenGL本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范(Specification)。
•实际的OpenGL库的开发者通常是显卡的生产商。你购买的显卡所支持的OpenGL版本都为这个系列的显卡专门开发的。当你使用Apple系统的时候,OpenGL库是由Apple自身维护的。
•早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管线)
•OpenGL的核心模式,可编程模式
Opengl库
•GLFW
•GLAD
等等。这里我不细说具体内容了。
渲染基本流程
•注意蓝色部分代表的是我们可以注入自定义的着色器的部分
Opengl对象
•顶点缓冲对象vbo
•顶点缓存对象(VBO)准许顶点数组数据存放在服务端的高性能显卡内存中,且提供高效数据传输
•顶点数组对象vao
•假如有两个顶点数组,我们申请两个顶点数组对象,将两个顶点数组,绑定到不同对象上,这样,使用的时候,就只需要在两个对象之间切换,不需要来回绑定
•索引缓冲对象ibo
存储修饰符
•Const:常量修饰符
•Attribute: attribute修饰符用于声明通过OpenGL ES应用程序传递到顶点着色器中的变量值。在其它任何非顶点着色器的着色器中声明attribute变量是错误的。
•Uniform:修饰符用来修饰那些在整个图元被处理的过程中保持不变的全局变量。所有的uniform变量都是只读的,可以通过应用程序调用API命令初始化,或者通过OpenGL ES间接初始化。
•Varying:变量提供了顶点着色器,片元着色器和二者通讯控制模块之间的接口。顶点着色器计算每个顶点的值(如颜色,纹理坐标等)并将它们写到varying变量中。顶点着色器也会从varying变量中读值,获取和它写入相同的值。如果从顶点着色器中读取一个尚未被写入的varying变量,将返回未定义值。
纹理
•纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)
•使用纹理坐标获取纹理颜色叫做采样(Sampling)
•纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角
纹理环绕方式
环绕方式 |
描述 |
GL_REPEAT |
对纹理的默认行为。重复纹理图像。 |
GL_MIRRORED_REPEAT |
和GL_REPEAT一样,但每次重复图片是镜像放置的。 |
GL_CLAMP_TO_EDGE |
纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。 |
GL_CLAMP_TO_BORDER |
超出的坐标为用户指定的边缘颜色。 |
纹理过滤
•GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素
•GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大
•让我们看看在一个很大的物体上应用一张低分辨率的纹理会发生什么吧
多级渐远纹理(Mipmap)
•后一个纹理图像是前一个的二分之一
•多级渐远纹理另一加分之处是它的性能非常好
•观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个
不同多级渐远纹理级别之间的过滤方式
过滤方式 |
描述 |
GL_NEAREST_MIPMAP_NEAREST |
使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样 |
GL_LINEAR_MIPMAP_NEAREST |
使用最邻近的多级渐远纹理级别,并使用线性插值进行采样 |
GL_NEAREST_MIPMAP_LINEAR |
在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样 |
GL_LINEAR_MIPMAP_LINEAR |
在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样 |
变换
•向量最基本的定义就是一个方向
向量运算
•向量与标量运算
•向量取反
•向量加减
向量长度
•单位向量,单位向量有一个特别的性质——它的长度是1,我们可以用任意向量的每个分量除以向量的长度得到它的单位向量
向量相乘
•要计算两个单位向量间的夹角,我们可以使用反余弦函数
矩阵
缩放,位移
•齐次坐标(Homogeneous Coordinates)
•向量的w分量也叫齐次坐标。想要从齐次向量得到3D向量,我们可以把x、y和z坐标分别除以w坐标。我们通常不会注意这个问题,因为w分量通常是1.0。使用齐次坐标有几点好处:它允许我们在3D向量上进行位移(如果没有w分量我们是不能位移向量的)
•如果一个向量的齐次坐标是0,这个坐标就是方向向量(Direction Vector),因为w坐标是0,这个向量就不能位移(译注:这也就是我们说的不能位移一个方向)。
•如果有一个公式需要将[5,2]点参与的运算3维运算,而我们的点只有2维的表示,那么我们在值不变的情况下增加一个齐次坐标,使之变成3维,而能够参加运算并不影响最终结果,这就是齐次坐标的价值
旋转
大多数旋转函数需要用弧度制的角,但幸运的是角度制的角也可以很容易地转化为弧度制的:
•弧度转角度:角度 = 弧度 * (180.0f / PI)
•角度转弧度:弧度 = 角度 * (PI / 180.0f)
PI约等于3.14159265359。
(Rx,Ry,Rz)(Rx,Ry,Rz)代表任意旋转轴
坐标系统
•局部空间(Local Space,或者称为物体空间(Object Space))
•世界空间(World Space)
•观察空间(View Space,或者称为视觉空间(Eye Space))
•裁剪空间(Clip Space)
•屏幕空间(Screen Space)
投影方式
•正射投影,正射平截头体直接将平截头体内部的所有坐标映射为标准化设备坐标,因为每个向量的w分量都没有进行改变;如果w分量等于1.0,透视除法则不会改变这个坐标
•透视投影,fov的值,它表示的是视野(Field of View)
摄像机
•摄像机位置
•摄像机方向:实际上指向从它到目标向量的相反方向
•右轴
Look At
•位置向量是相反的,因为我们最终希望把世界平移到与我们自身移动的相反方向
其中R是右向量,U是上向量,D是方向向量P是摄像机位置向量。
视角移动
•欧拉角,一共有3种欧拉角:俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)
欧拉角
•欧拉角的优点:
欧拉角仅使用三个数来表达方位,并且这三个数都是角度。这使欧拉角具有一些独特的优点:
1、欧拉角对我们来说很容易使用。2、最简洁的表达方式。3、任意三个数都是合法的。
•欧拉角的缺点:
•给定方位的表达方式不唯一。
•在将一个角度加上360度的倍数时,并不会改变方位。
•还有一种情况,由三个角度不互相独立而导致的。例如,pitch135度等价于heading180度,pitch45度,然后bank180度。为了保证任意方位都只有独一无二的表示,必须限制角度的范围。一种常用的技术是将heading和bank限制在+180度到-180度之间,pitch限制在+90度到-90度之间。
•万向锁:
欧拉角最著名的别名问题是这样的:先heading45度再pitch90度,这与先pitch90度再bank45度是等价的。事实上,一旦选择+(-)90度为pitch角,就被限制在只能绕竖直轴旋转。这种现象,角度为+(-)90度的第二次旋转使得第一次和第三次旋转的旋转轴相同,称作万向锁。为了消除限制欧拉角的这种别名现象,规定万向锁情况下由heading完成绕竖直轴的全部旋转。换句话说,在限制欧拉角中,如果pitch为+(-)90度,则bank为0。
•两个角度间求插值非常困难。
•如果没有使用限制欧拉角,方位A的heading为720度,方位B的heading为45度,heading值只相差45度,但简单的插值会在错误的方向上绕将近两周。
•设A的heading为-170度,B的heading为170度。这两个值只相差20度,但插值操作又一次发生了错误,旋转是沿 "长弧"绕了340度而不是更短的20度。
•解决这类问题的方法是将插值的"差"角度折到-180度到180度之间,以找到最短弧。
•https://blog.csdn.net/qq_35957011/article/details/77188036
着色器
•着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性
•GLSL中包含C等其它语言大部分的默认基础数据类型:int,float,double,uint,bool
•GLSL也有两种容器类型:分别是向量(Vector)和矩阵(Matrix)
•
•Shader language目前主要有3种语言:基于OpenGL的GLSL,基于Direct3D的HLSL,还有NVIDIA公司的Cg 语言。
顶点着色器
•顶点着色器是在GPU上运行的小程序。顾名思义,顶点着色器是用来处理顶点数据的
•一 般来说,可以将几何图形顶点数据放在VertexBuffer中,然后将其上传至GPU。顶点着色器程序将处理VertextBuffer中的每一个顶点,这就好像在着色器周围使用了一个for循环,但实际上你根本看不到这个for循环, 如下:
•for (var i:int = 0; i <vertexBuffer.length; i++)
•{
•executeVertexShader(vertexBuffer);
•}
片段着色器
•就像顶点着色器一样,片段着色器也是运行在GPU上的小程序。顾名思义,用它来处理片段。它们负责输出每个三角形像素的最终颜色。
•基本上来说,它是这样运行的:片段着色器将顶点着色器输出的片段作为输入,片段的顶点属性已被光栅化单元进行了插值处理。
•片段着色器执行的流程基本上也很像一个循环,如果你能把未经处理的片段想象成某种数据流,就叫片段流吧,片段着色器的处理就像代码中描述的一样:
•for (var i:int = 0; i <fragmentStream.length; i++)
•{
•executeFragmentShader(fragmentStream);
•}
多重采样
•Multi-sampling或者说Multi-sample Anti-Alias (简称MSAA)是一种抗锯齿的技术,它通过在一个像素上进行多次采样多次计算并最终汇总(Resolve to single-sample),可使绘制的图像边缘更加平滑
•MSAA4, MSAA8, MSAA16, MSAA32
•MSAA则把每个小的矩形网格再进行细分。比如MSAA4/MSAA8分别把每个piexl再分为4个或者8个sub-pixel,其中每一个sub-pixel称为一个sample
•1)光栅化阶段(Rasterization)
•2)采样阶段
•3)片段着色阶段
•4)Blitting
•参考:https://blog.csdn.net/yunchao_he/article/details/78354528?locationNum=5&fps=1
变体
•根据不同的情况,使用不同的预处理器指令,来多次编译Shader代码
•#pragma multi_compile TEST_OFF TEST_ON
•这样会编译两个Shader变体,一个是TEST_OFF的版本,一个是TEST_ON的版本。运行的时候会根据材质关键之或者Shader全局关键字判断应该使用哪个,如果两个关键字都为false,那么会使用第一个(TEST_OFF)变体
•参考:https://blog.csdn.net/ecidevilin/article/details/52882400
OpenGL的片段方案
•#pragma fragmentoption ARB_precision_hint_fastest
•最快的,意思就是会用低精度(一般是指fp16),以提升fragment着色器的运行速度,减少时间
•#pragma fragmentoption ARB_fog_exp2
•我们添加指数平方雾支持。
•#pragma fragmentoption name加上一个选项来编译OpenGL的片段方案。
最后推给大家一个网站,里面可以学到很多opengl的知识
参考:https://learnopengl-cn.github.io/