OpenGL笔记十五:GLSL光照计算
前言
期待您移步上篇:OpenGL笔记十四:GLSL语法
顶点着色器
- 业务
1.矩阵变换位置
2.计算光照公式⽣成逐顶点颜⾊
3.⽣成/变换纹理坐标
- 总结: 它可以⽤于执⾏⾃定义计算,实施新的变换,照明或者传统的固定功能所不允许的基于顶点的效果。
- 内建特殊变量
gl_VertexID
,是一个输入变量。用于保存顶点的整数索引。gl_VertexID 是整数型变量,用 highp 精度限定修饰符声明。
gl_InstanceID
,是一个输入变量。用于保存实例化绘图调用中图元的实例编号。对于常规的绘图调用,该值为0;gl_InstanceID 是整数型变量,用 highp 精度限定修饰符声明。
gl_Position
,用于输出顶点位置的裁剪坐标。该值在裁剪和视口变换用于执行相应的图元裁剪以及从裁剪坐标到屏幕坐标的顶点位置转换。如果顶点着色器位写入 gl_Position ,则 gl_Position 的值未定义。 gl_Position 是浮点型变量,用 highp 精度限定修饰符声明。
gl_PointSize
,可以写入像素标识点精灵(即像素点)的尺寸,在渲染点精灵时使用。顶点着色器输出的 gl_PointSize 值被限定在 OpenGL ES 3.0 实现支持的费平滑点大小范围之内。gl_PointSize 是浮点型变量,用 highp 精度限定修饰符声明。
gl_FrontFacing
,是一个特殊变量,但不是由顶点着色器直接写入的,而是根据顶点着色器生成的位置值和渲染图元的类型生成的。gl_FrontFacing 是一个布尔值类型。
在顶点着色器内可用的唯一内键 Uniform 状态是窗口坐标中的深度范围。这些由内建统一变量名 gl_DepthRange
给出。
struct gl_DepthRangeParameters
{
highp float near; //near z
highp float far; //near far
highp float diff; //far - near
}
uniform gl_DepthRangeParameters gl_DepthRange;
- 内建常量
const mediump int gl_MaxVertexAttribs = 16;
const mediump int gl_MaxVertexUniformVectors = 256;
const mediump int gl_MaxVertexOutputVectors = 16;
const mediump int gl_MaxVertexTextureImageUnits = 16;
const mediump int gl_MaxCombinedTextureImageUnits = 32;
gl_MaxVertexAttribs
:可以指定得顶点数据的最大数量。
gl_MaxVertexUniformVectors
:顶点着色器可以使用的 vect4 Uniform 变量的最大数量。
gl_MaxVertexOutputVectors
:输出向量的最大数量。
gl_MaxVertexTextureImageUnits
:顶点着色器可用纹理单元的最大数量。
gl_MaxCombinedTextureImageUnits
:顶点/片元着色器中的可用纹理单元的最大数量的总和。
-
矩阵变换
MVP矩阵(模型-视图-投影矩阵) 顶点着色器的位置输入保存的是物体坐标,而输出的坐标保存为剪裁坐标。MVP矩阵是3D图形中进行这种变化的3个非常重要的变换矩阵的乘积:模型矩阵,视图矩阵和投影矩阵。
组成MVP矩阵的每个单独矩阵执行的变换如下:
- 模型矩阵 -- 将物体坐标变换为世界坐标
- 视图矩阵 -- 将世界坐标变换为眼睛坐标(观察坐标)
- 投影矩阵 -- 讲眼睛坐标(观察者坐标)变换为裁剪坐标
片元着色器
- 业务
1.计算颜⾊
2.获取纹理值
3.往像素点中填充颜⾊值(纹理值/颜⾊值)
- 总结: 它可以⽤于图⽚/视频/图形中每个像素的颜⾊填充(⽐如给视频添加滤镜,实际上就是将视频中每个图⽚的像素点颜⾊填充进⾏修改)。
- 内建特殊变量
gl_FragCoord
:片元着色器中一个只读变量,这个变量保存片元的窗口相对坐标。
gl_FrontFacing
:片元着色器中额的一个只读变量,为布尔类型变量,正面图元时为true,否则为false。
gl_PointCoord
:只读变量,可以在渲染点精灵使用,保存点精灵的纹理坐标,这个坐标在点精灵光栅化期间自动生成,处于(0,1)区间。
gl_FragDepth
:一个只写输出变量,在片元着色器写入时,覆盖片元的固定功能深度值。尽量减少手动实现深度值写入。这个功能需要谨慎使用,因为它可能禁用许多GPU的深度优化。例如:许多GPU都有"Early -Z"的功能,在执行片元着色器之前进行深度测试,使用"Early -Z"的好处就是不能通过深度测试的片元就不会被着色(从而减少了着色器调用次数,提高性能),但是使用 gl_FragDepth 就必须禁用该功能,因为GPU在执行着色器之前不知道深度值。
- 内建常量
const mediump int gl_MaxFragmentInputVectors = 15;
const mediump int gl_MaxTextureImageUnits = 16;
const mediump int gl_MaxFragmentUniformVectors = 224;
const mediump int gl_MaxDrawBuffers = 4;
const mediump int gl_MinProgramTexelOffset = -8;
const mediump int gl_MaxProgramTexelOffset = 7;
gl_MaxFragmentInputVectors
:片元着色器输入的最大数量
gl_MaxFragmentUniformVectors
:可用纹理图像单元的最大数量
gl_MaxFragmentUniformVectors
:片元着色器可用vec4 Uniform变量的最大数量
gl_MaxDrawBuffers
:多重渲染目标最大支持数量
- 多个纹理单元渲染
- 1.片元着色器(服务端)代码:
attribute vec2 v_texCoord;
uniform sampler2D s_baseMap;
uniform sampler2D s_SecondMap;
void main() {
vec4 baseColor;
vec4 secondColor;
baseColor = texture(s_baseMap,v_texCoord);
secondColor = texture(s_SecondMap,v_texCoord);
gl_FragColor = baseColor * secondColor;
}
- 2.客户端代码:
//将各个纹理对象绑定到纹理单元0和1,为采样器设置数 值,将采集器绑定到对应的纹理单元
glActiveTexutre(GL_TEXTURE0);
glBindTeture(GL_TEXTURE_2D,baseMapTexId);
glUniformli(baseMapTexId,0);
glActiveTexutre(GL_TEXTURE1);
glBindTeture(GL_TEXTURE_2D,secondMapTexId);
glUniformli(secondMapTexId,1);
-
内建函数
常⽤内建函数:
dot :点乘
cross :叉乘
texture2D :⽤于对纹理采样
normalize :对⼀个向量规格化
clamp :将⼀个向量固定在⼀个最⼩值和最⼤值之间
光照特性
- 发射光:由物体⾃⾝发光
- 环境光:就是在环境中充分散射的光,⽽且⽆法分辨它的⽅向
- 漫反射光:光线来⾃某个⽅向,但在物体上各个⽅向反射
- 镜⾯⾼光:光线来⾃⼀个特定的⽅向,然后在物体表⾯上以⼀个特定的 ⽅向反射出去
材质属性
- 泛射材质
- 漫反射材质
- 镜⾯反射材质
- 发射材质
光照计算
1.环境光的计算
环境光 = 环境因子 * 物体的材质颜⾊
2.发射光的计算
发射颜⾊ = 物体的反射材质颜⾊
3.漫反射光计算
漫反射颜⾊ = 光源的漫反射颜⾊ * 物体的漫发射材质颜⾊ * DiffuseFactor
DiffuseFactor = max(0,dot(N,L))
漫反射因⼦DiffuseFactor 是光线 与顶点法线向量的点积
4.镜⾯光计算
镜⾯反射颜⾊ = 光源的镜⾯光的颜⾊ * 物体的镜⾯材质颜⾊ * SpecularFactor
SpecularFactor = power(max(0,dot(N,H)),shininess)
H :视线向量E 与 光线向量L 的半向量
dot(N,H) :H,N的点积⼏何意义,平⽅线与法线夹⻆角的cos值
shiniess : ⾼光的反光度
光照计算
光照颜⾊ = (环境颜⾊ + 漫反射颜⾊ + 镜⾯反射颜⾊) * 衰减因⼦
衰减因⼦
衰减因⼦ = 1.0/(距离衰减常量 + 线性衰减常量 * 距离 + ⼆次衰减常量 * 距离的平⽅)
注:
- 距离衰减常量,线性衰减常量和⼆次衰减常量均为常量值
- 环境光,漫反射光和镜⾯光的强度都会受距离的增⼤⽽衰减,只有发射光和全局环境光的强度不会受影响
聚光灯因⼦
聚光灯夹⻆角cos值 = power(max(0,dot(单位光源位置,单位光线向量)),聚光灯指数)
- 单位光线向量是从光源指向顶点的单位向量
- 聚光灯指数,表示聚光灯的亮度程度
- 公式解读:单位光源位置 * 单位光线向量 点积 的 聚光灯指数次⽅
增加过渡计算
聚光灯因⼦ = clamp((外环的聚光灯⻆角度cos值 - 当前顶点的聚光灯⻆角度cos值)/ (外环的聚光灯⻆角度cos值- 内环聚光灯的⻆角度的cos值),0,1)
光照计算终极公式
光照颜⾊ = 发射颜⾊ + 全局环境颜⾊ + (环境颜⾊ + 漫反射颜⾊ + 镜⾯反 射颜⾊) * 聚光灯效果 * 衰减因⼦