1、基本着色器的架构
顶点着色器:接收客户端输入的Attribute属性数据,有些计算后自己用于顶点变换,有些传给片段着色器。除此之外,顶点着色器还接受uniform数据,一般是变换矩阵。最后输出顶点的位置变换值。
片段着色器:接收来自顶点着色器输出的纹理坐标和纹理等属性,另外也接收用于计算光照的光照颜色的uniform值,最后输出像素的颜色值。
2、Shader的变量和数据类型
数据类型:整数(有符号和无符号),浮点数和布尔值。。没有指针和字符类型
复合数据类型:向量类型(vec3,ivec3...)和矩阵类型(max4,mac2x3...)
1、向量类型的特点:
a、向量类型的特殊寻址:我们用点号来确定多达4个向量元素的地址,可以使用下列三组标识符的任何一组:xyzw,rgba,stpq
b、调换操作:vNewColor.bgra = vOldColor.rgba
2、矩阵类型的特点:
a、矩阵其实就是一个由向量组成的数组。矩阵可以乘以向量得到一个新的向量:顶点的空间变换-> vOutPos = mvpMatrix * vVertex
3、Shader的存储限定符:in,out,inout,uniform,flat,smooth
in(输入变量):接收来自客户端提交的属性或者以前的着色器阶段传递的属性
out(输出变量):前一阶段的out变量在后续阶段的着色器能够接收到的变量
inout:由于Shader没有指针,所以这是将一个值传到一个函数并且运行这个函数修改并返回一个变量的唯一方法
flat:在两个着色器阶段之间不以一种透视正确的方法进行插值
smooth:在两个着色器阶段之间以一种透视正确的方法进行插值
4、简单的着色器分析:绘制一个有颜色的三角形
//顶点着色器
<span style="white-space:pre"> </span>#version 130 in vec4 vColor; //客户端传给的顶点颜色 in vec4 vVertex; //顶点位置 out flat vec4 vVaryingColor; //需要传递给片段着色器的颜色变量,如果为flat则不插值,输出一个纯色的三角形,如果是smooth则输出一个插值变化的三角形 void main(){ vVaryingColor = vColor; //必须输出 gl_Position = vVertex; //gl_Position是预定义的内建变量,用于几何图形装配阶段 }
//片段着色器
<span style="white-space:pre"> </span>#version 130 out vec4 vFragColor; in flat vec4 vVaryingColor; void main(void) { vFragColor = vVaryingColor; }
5、着色器的编译,绑定和链接过程:
1、首先通过hVertexShader = glCreateShader(GL_VERTEX_SHADER)创建着色器对象
2、gltLoadShaderFile(szVertexProg,hVertexShader)随后加载着色器文件
3、加载之后再进行编译:glComplileShader(hVertexShader)
4、创建最终的程序对象:
hReturn = glCreateProgram();
glAttachShader(hReturn,hVertexShader)
glAttachShader(hReturn,hFragmentShader)
5、将参数名绑定到指定的参数位置列表上
6、绑定之后进行链接:glLinkProgram(hRet)
7、链接完成删除之前的顶点着色器和片段着色器glDeleteShader(hVertexShader)
8、使用着色器:glUseProgram(myShader)
6、着色器的统一值Uniform
1、Uniform是作用于整个图元批次渲染过程的,是逐批次,顶点着色器和片段着色器都可以接收;属性则是逐顶点的,只有顶点着色器才可以接收属性数据。
2、获取统一值的位置:GLint location = glGetUniformLocation(myShader,"vColorValue"
)
3、设置统一值:
标量向量:glUniform4i(location,v0,v1,v2,v3)
例:
glUniform4f(locColor,1.0f,0.0f,0.0f,1.0f)
glUniform1i(locIndex,42)
数组:glUniform1fv(localtion,count,GLfloat* v)
例:
uniform vec4 vColor;
GLfloat vColor[4] = {1.0f,1.0f,1.0f,1.0f};
glUniform4fv(iColorLocation,1vColor);
矩阵:glUniformMatrix4fv(GLint location,Glint count,GLboolean transpose,const GLfloat *m)
例:
glUniformMatrix4fv(locMVP,1,GL_FALSE,transformPipeline.GetModelViewProjectionMatrix());
7、内建函数
anyFloat->float/vec2/vec3/vec4
常用:
<span style="white-space:pre"> </span>radians(degress) ->角度转弧度 degress(radians) ->弧度转角度 pow(x,y) ->x的y次方 float dot(vec x,vec y) ->x和y的点乘结果 vec3 cross(vec3 x,vec3 y) ->x和y的叉乘结果 vec normalize(vec x) ->x方向相同的单位长度向量 vec reflect(vec l,vec N) ->返回入射l在表面N的放射方向向量
其他自查资料
8、光照
漫反射:需要两个向量->光源的方向向量和顶点的法线向量
计算: float intensity = max(0.0,dot(vSurfaceNormal,vLightDir))
使用该值与顶点的一个颜色值相乘,则得到一个基于光照强度的颜色值
取值:这个值越大(接近1)则光照效果越强,越接近0,则效果越差
变换:表面法向需要根据视图变换而做变换,但是只需要进行旋转变换就可以。所以不能用表面法向直接乘以模型视图矩阵。这时可以通过GLTransformationPipeline渲染的变换管线中获取一个法向矩阵GetNormalMatrix,从而获得表面法向在视觉坐标中的位置
vec3 vEyeNormal = normalMatrix * vNormal
由于我们传递的是光源的位置而非光源的方向,需要将顶点位置变换到视觉坐标并计算:
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition.w;
vec3 vLightDir = normalize(vLightPosition - vPosition3);
ADS光照:环境光(Ambient),漫射光(Diffuse),镜面光(Specular)
环境光:一个“照明”因子,vec3 vAmbientColor = vAmbientMaterial*AmbientLight
漫射光:float fDotProduct = max(0.0,dot(vNormal,vLightDir))
vec3 vDiffuseColor = vDiffuseMaterial*vDiffuseLight*fDotProduct
镜面光:表面法线向量和光源反射向量的点乘再取“反光度”次幂
float shininess = 128;
vec3 vReflection = reflect(-vLightDir,vEyeNormal)
float EyeReflectionAngle = max(0.0,dot(vEyeNormal,vReflection))
fspec = pow(EyeReflectionAngle,shiniess)
vec3 vSpecularColor = vSpecularLight * vSpecularMaterial * fSpec
Phong着色:颜色的计算过程在片段着色器中进行,不需要进行插值,提高了渲染质量,但是比较消耗性能。
9、纹理的使用
需要两个参数:一个是顶点的纹理坐标,一个是图元的纹理单元
<span style="white-space:pre"> </span>uniform sampler2D colorMap; out vec4 vFragColor; in vec4 vVaryingTexCoords; vFragColor = texture(colorMap,vVaryingTexCoords.st);
sampler2D代表我们将要采样的纹理所绑定的纹理单元
加上光照的纹理:(环境光+漫射光)*纹理颜色+镜面光
丢弃片段:discard 可以渲染一种腐蚀的效果