OpenGL超级宝典笔记五 - 基础Shader

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 可以渲染一种腐蚀的效果

时间: 2024-10-03 04:44:13

OpenGL超级宝典笔记五 - 基础Shader的相关文章

OpenGL超级宝典笔记三 - 基础纹理1

纹理对象的使用:纹理图像数据的类型,图像数据的导入导出方式,纹理的使用过程:图像数据的加载,纹理参数的设置,纹理的绑定. 一.图像数据的分类:位图图像和像素图像 二.像素图像数据的包装: 在OpenGL中:使用4字节的行对齐方式,每一行补全到4的倍数,使用glPixelStorei(pname,param)可以改变或者恢复像素的存储方式 介绍常用的两组:内存<->缓冲区的压缩和解包 glPixcelStorei(GL_UNPACK_ALIGNMENT) ----图像数据从内存到缓冲区的解包设置

OpenGL超级宝典笔记二 - 基础变换

1.向量: 点乘:float m3dDotProduce3(u,v):返回两个单位向量的余弦值 叉乘:float m3dCrossProduct3(result,u,v):返回垂直于两个向量定义的平面的向量 2.矩阵: OpenGL使用的是列优先排序的矩阵 单位矩阵(对角线为1,其他为0):任何向量乘以一个单位矩阵都不会发生任何改变 3.变换:最终获得的变换矩阵会应用到每个顶点 视图矩阵x模型矩阵x投影矩阵->投影摄像机的位置变换,物体对象的位置变换,投影裁剪变换 若顶点向量为Vert,则变换公

OpenGL超级宝典笔记一 - 基础渲染

1.渲染中的双缓冲: 使用但缓冲的时候,在渲染每一帧的绘图时,会对画板进行擦除然后在慢慢填充绘制,如果绘制时间过长的时候,就会出现闪烁的现象.为解决这个问题,所以引入双缓冲 双缓冲相当于,在显示的画板中重新创建另外一个画板,绘制的过程在另外的画板进行,绘制完成之后,将显示的画板的内容直接替换成另外一个画板的内容.这样呈现的过程中就不会出现闪烁的问题,即使是绘制的过程比较慢,最多就是出现顿的现象 在例子中渲染的RenderScene()函数中,每次渲染结束之后都会调用glutSwapBuffers

OpenGL超级宝典笔记四 - 基础纹理2

一.使用MipMap贴图(主要是应用在纹理缩小过滤中) 优点: 防止当纹理缩小太大的时候,出现闪烁的问题 提高性能,需要缩小的时候就不加载大内存的纹理 缺点: 需要额外的内存作为代价 组成:由一系列缩小的纹理图像组成,子层是父层的1/4 过滤类型:NEAREST快速,LINEAR效果好 GL_NEAREST_MINMAP_NEAREST选择最邻近Mip层并执行邻近过滤 GL_NEAREST_MINMAP_LINEAR选择最Mip层线性插补并执行邻近过滤 GL_LINEAR_MINMAP_NEAR

【转载】OpenGL超级宝典笔记——GLSL语言基础

变量 GLSL的变量命名方式与C语言类似.变量的名称可以使用字母,数字以及下划线,但变量名不能以数字开头,还有变量名不能以gl_作为前缀,这个是GLSL保留的前缀,用于GLSL的内部变量.当然还有一些GLSL保留的名称是不能够作为变量的名称的. 基本类型 除了布尔型,整型,浮点型基本类型外,GLSL还引入了一些在着色器中经常用到的类型作为基本类型.这些基本类型都可以作为结构体内部的类型.如下表: 类型 描述 void 跟C语言的void类似,表示空类型.作为函数的返回类型,表示这个函数不返回值.

OpenGL超级宝典笔记----渲染管线

在OpenGL中任何事物都在3D空间中,但是屏幕和窗口是一个2D像素阵列,所以OpenGL的大部分工作都是关于如何把3D坐标转变为适应你屏幕的2D像素.3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线完成的.图像渲染管线可以被划分为两个主要部分:第一个部分把你的3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素. 渲染管线接收一组3D坐标,然后把它们转变为你屏幕上的有色2D像素.渲染管线可以被划分为几个阶段,每个阶段需要把前一阶段的输出作为输入.所有这些阶段都是高度

OpenGL超级宝典笔记——贝塞尔曲线和曲面(转)

http://my.oschina.net/sweetdark/blog/183721 参数方程表现形式 在中学的时候,我们都学习过直线的参数方程:y = kx + b;其中k表示斜率,b表示截距(即与y轴的交点坐标).类似地,我们也可以用一个参数方程来表示一条曲线.1962年,法国工程师贝塞尔发明了贝塞尔曲线方程.关于贝塞尔曲线的详细介绍可以参考(维基贝塞尔).这里只介绍OpenGL实现贝塞尔的函数. OpenGl定义一条曲线时,也把它定义为一个曲线方程.我们把这条曲线的参数成为u,它的值域就

OpenGL超级宝典笔记——深度纹理和阴影 【转】

目录[-] 光源视角 新型的纹理 深度纹理的大小 首先绘制阴影 然后是光照 投影阴影贴图 阴影比较 之前我们介绍过简单的把物体压平到投影平面来制造阴影.但这种阴影方式有其局限性(如投影平面须是平面).在OpenGL1.4引入了一种新的方法阴影贴图来产生阴影. 阴影贴图背后的原理是简单的.我们先把光源的位置当作照相机的位置,我们从这个位置观察物体,我们就知道哪些物体的表面是被照射到(被光源看到) 的,哪些是没有被照射到(被遮挡住)的(在某个方向上离光源最近的表面是被照射的,后面的表面则没有被照射到

OpenGL超级宝典笔记——遮挡查询 [转]

目录[-] 遮挡查询之前 包围体 遮挡查询 在一个场景中,如果有有些物体被其他物体遮住了不可见.那么我们就不需要绘制它.在复杂的场景中,这可以减少大量的顶点和像素的处理,大幅度的提高帧率.遮挡查询就是允许我们判断一组图形在进行了深度测试之后是否可见. 遮挡查询之前 为了显示遮挡查询对性能的提升,我们需要一个对照组(不使用遮挡查询来渲染场景). 首先我们先绘制“主遮挡物”.这个主遮挡物不需要太多的细节,一般是墙,天花板,地板之类的物体.在下面的例子中我们,使用6面墙来组成这个主遮挡物. void