OpenGLES---GLSL学习

{GLSL
	0:GLSL介绍
	1:常用的数据类型
	2:修饰符
	3:内置变量/函数
	4:表达式
		1:操作符
		2:数组访问
		3:构造函数
		4:成分选择
	5:控制流
		1:循环(for,while,dowhile)
		2:条件(if/else)
		3:退出片段着色器(discard)
	6:函数
}

{0:GLSL介绍
	三大主流高级编程语言
		HLSL 基于DirctX(High Level Shading Language)
		GLSL 基于OpenGL(OpenGL Shading Language)
		CG 基于NVIDIA公司和C for Graphic简称
}

{1:常用的数据类型

	bool 布尔变量
	int  整形(代表至少包含16位的有符号的整数。可以是十进制的,十六进制的,八进制的。)
	float 单精度浮点数
	double 双精度浮点数

	向量:包含n个布尔
	bvec2 包含2个布尔成分的向量
	bvec3 包含3个布尔成分的向量
	bvec4 包含4个布尔成分的向量

	向量:包含n个整型
	ivec2 {x,y} 包含2个整型成分的向量
	ivec3 {x,y,z}包含3个整型成分的向量
	ivec4 {x,y,z,w}包含4个整型成分的向量

	向量:包含n个整型
	vec2 {x,y} 包含2个整型成分的向量
	vec3 {x,y,z} 包含3个整型成分的向量
	vec4 {x,y,z,w} 包含4个整型成分的向量
		{x,y,z,w}
		{r,g,b,a}
		{s,t,p,q}

	矩阵:
	mat2x2  mat2x2(2x2的浮点数矩阵类型)
	mat2x3  mat2x3 2列3行的浮点矩阵(OpenGL的矩阵是列主顺序的)
	mat2x4  mat2x4 2列4行的浮点矩阵

	矩阵:
	mat3x2  mat3x2 3列2行的浮点矩阵
	mat3x3  或者mat3x3(3x3的浮点数矩阵类型)
	mat3x4  mat3x4 3列4行的浮点矩阵

	mat4x2  mat4x2 4列2行的浮点矩阵
	mat4x3  mat4x3 4列3行的浮点矩阵
	mat4x4  mat4x4 4x4的浮点矩阵

	sampler1D 用于内建的纹理函数中引用指定的1D纹理的句柄。只可以作为一致变量或者函数参数使用
	sampler2D 二维纹理句柄
	sampler3D 三维纹理句柄
	samplerCube cube map纹理句柄(立体图,例如看镜子上的图片就是立体图)
	sampler1DShadow 一维深度纹理句柄
	sampler2DShadow 二维深度纹理句柄
}

{2:修饰符

变量的声明可以使用如下的修饰符

	precision 浮点精度
		lowp 低精度 
		mediump 中精度
		highp 高精度
	例如:
	precision  lowp  float //浮点精度低精度 float


	修饰符        描述
	const      常量值必须在声明是初始化。它是只读的不可修改的。
	attribute  表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。
				一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或则结构体
	uniform  一致变量。在着色器执行期间一致变量的值是不变的。
			与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。
			一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明

	varying   顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。
				必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵,不能是数组或者结构体。
	centorid varying  在没有多重采样的情况下,与varying是一样的意思。在多重采样时,
						centorid varying 在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。

	invariant (不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。
				所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。
				除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。

	in  	用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。
			相当于C语言的传值),这个是函数参数默认的修饰符
	out 	用在函数的参数中,表示该参数是输出参数,值是会改变的
	inout 	用在函数的参数,表示这个参数即是输入参数也是输出参数


个人总结:
	变量修饰符
		uniform 全局变量(由外部程序传递给vertex和fragment Shader的变量)
		attribute 局部变量(只能在顶点Shader中用)
			可以 	浮点数类型的标量,向量,或者矩阵。float,vec2,mat
			不可以   数组或则结构体

		varying 共享变量(vs和fs共享用)
			可以 	浮点数类型的标量,向量,或者矩阵。float,vec2,mat
			不可以   数组或则结构体
			
			以下是例子:
				const char* vs  = {
						...
					"attribute  vec4    _color;\n"
					"varying    vec4    _outColor;\n"
					"void main()\n"
					"{"
							...
					"   _outColor   =   _color;\n"
							...
					"}"
				};
				const char* fs  = {
					   ...
					"varying    vec4        _outColor;"
					"void main()"
					"{"
							...
					"   gl_FragColor    =   _outColor * texColor;" //输出的颜色用于随后的像素操作
					"}"
				};
	函数参数修饰符
		in     值传递,不是引用传参(default)
		out    引用(指针)参数
		inout  两者都有(in,out),

}

{3:内置变量/函数

内置变量
		内置变量可以与固定函数功能进行交互。在使用前不需要声明。顶点着色器可用的内置变量如下表:

		类型    名称        描述
		vec4  gl_Color 输入属性-表示顶点的主颜色
		vec4  gl_SecondaryColor 输入属性-表示顶点的辅助颜色
		vec3  gl_Normal  输入属性-表示顶点的法线值
		vec4  gl_Vertex  输入属性-表示物体空间的顶点位置
		vec4  gl_MultiTexCoordn 输入属性-表示顶点的第n个纹理的坐标
		float gl_FogCoord   输入属性-表示顶点的雾坐标
		float gl_PointSize  点的大小
		vec4  gl_Position   输出属性-变换后的顶点的位置,所有的顶点着色器都必须写这个值。
		vec4  gl_ClipVertex 输出坐标,用于用户裁剪平面的裁剪
		vec4  gl_FrontColor 正面的主颜色的 varying 输出
		vec4  gl_BackColor  背面主颜色的 varying 输出
		vec4  gl_FrontSecondaryColor 正面的辅助颜色的 varying 输出
		vec4  gl_BackSecondaryColor  背面的辅助颜色的 varying 输出
		vec4  gl_TexCoord[]    纹理坐标的数组 varying 输出
		float gl_FogFragCoord  雾坐标的 varying 输出

		片段着色器的内置变量如下表:

		类型   名称        描述
		vec4  gl_Color 包含主颜色的插值只读输入
		vec4  gl_SecondaryColor  包含辅助颜色的插值只读输入
		vec4  gl_TexCoord[]  包含纹理坐标数组的插值只读输入
		float gl_FogFragCoord 包含雾坐标的插值只读输入
		vec4  gl_FragCoord   只读输入,窗口的x,y,z和1/w
		bool  gl_FrontFacing 只读输入,如果是窗口正面图元的一部分,则这个值为true
		vec2  gl_PointCoord 点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。
		vec4  gl_FragData[] 使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。
		vec4  gl_FragColor  输出的颜色用于随后的像素操作
		float gl_FragDepth  输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替
	
	
内置函数
	
	1:角度和三角函数
	2:指数函数
	3:常用函数
	4:几何函数
	5:矩阵函数
	6:向量相关函数
	7:材质查找函数
	8:片元处理函数

	{2:指数函数
		//x的y次方。如果x小于0,结果是未定义的。同样,如果x=0并且y<=0,结果也是未定义的。使用时应特别注意。
		genType pow (genType x, genType y)
		//e的x次方
		genType exp (genType x)
		//计算满足x等于e的y次方的y的值。如果x的值小于0,结果是未定义的。
		genType log (genType x)
		//计算2的x次方
		genType exp2 (genType x)
		//计算满足x等于2的y次方的y的值。如果x的值小于0,结果是未定义的。
		genType log2 (genType x)
		//计算x的开方。如果x小于0,结果是未定义的。
		genType sqrt (genType x)
		//计算x的开方之一的值,如果x小于等于0,结果是未定义的。
		genType inversesqrt (genType x)
        
	}

	{3:常用函数
		//返回x的绝对值
		genType abs (genType x)
		//如果x>0,返回1.0;如果x=0,返回0,如果x<0,返回-1.0
		genType sign (genType x)
		//返回小于等于x的最大整数值
		genType floor (genType x)
		//返回大于等于x的最小整数值
		genType ceil (genType x)
		//返回x-floor(x),即返回x的小数部分
		genType fract (genType x)
		//返回x – y * floor (x/y),即求模计算%
		genType mod (genType x, float y)、genType mod (genType x, genType y)
		//返回x和y的值较小的那个值。
		genType min (genType x, genType y),genType min (genType x, float y)
		//返回x和y的值较大的那个值。
		genType max (genType x, genType y),genType max (genType x, float y)

		genType clamp (genType x, genType minVal, genType maxVal)
		genType clamp (genType x, float minVal, float maxVal)

		//返回线性混合的x和y,如:x⋅(1−a)+y⋅a
		genType mix (genType x, genType y, genType a)、genType mix (genType x, genType y, float a)
		//如果x < edge,返回0.0,否则返回1.0
		genType step (genType edge, genType x),genType step (float edge, genType x)
		//如果x <= edge0,返回0.0 ;如果x >= edge1 返回1.0;如果edge0 < x < edge1,则执行0~1之间的平滑埃尔米特差值。如果edge0 >= edge1,结果是未定义的。
		genType smoothstep (genType edge0,genType edge1,genType x)
		genType smoothstep (float edge0,float edge1,genType x)

	}
	{4:几何函数
		//返回向量x的长度
		float length (genType x)
		//计算向量p0,p1之间的距离
		float distance (genType p0, genType p1)
		//向量x,y之间的点积
		float dot (genType x, genType y)
		//向量x,y之间的叉积
		vec3 cross (vec3 x, vec3 y)
		//标准化向量,返回一个方向和x相同但长度为1的向量
		genType normalize (genType x)
		//如果Nref和I的点积小于0,返回N;否则,返回-N;
		genType faceforward(genType N, genType I, genType Nref)
		//返回反射向量
		genType reflect (genType I, genType N)
		//返回折射向量
		genType refract(genType I, genType N,float eta)
	}

	{5:
		//矩阵x乘以y,result[i][j]是 x[i][j] 和 y[i][j] 的标量积。注意,要获取线性代数矩阵的乘法,使用乘法操作符*。
		mat matrixCompMult (mat x, mat y)
	}
	{7:材质查找函数
	 	lowp vec4 texture2D (sampler2D sampler, vec2 coord[,float bias]);
	 	lowp vec4 texture2DProj (sampler2D sampler, vec3 coord[,float bias]);
	 	lowp vec4 texture2DProj (sampler2D sampler, vec4 coord[,float bias]);
	 	lowp vec4 texture2DLod (sampler2D sampler, vec2 coord,float lod);
	 	lowp vec4 texture2DProjLod (sampler2D sampler, vec3 coord,float lod);
	 	lowp vec4 texture2DProjLod (sampler2D sampler, vec4 coord,float lod);

	 	lowp vec4 textureCube (SamplerCube sampler, vec3 coord[,float bias]);
	 	lowp vec4 textureCube (SamplerCube sampler, vec3 coord,float lod);


	 	//解释
		Use the texture coordinate coord to do a texture lookup in the 2D texture currently boound to sampler. For the projective("Proj")versions,the texture coordinate (coord.s,coord.t)is divided by the last component of coord. The third component of coord is ignored for the vec4 coord variant.
		//翻译
		使用纹理坐标coord 2d纹理的纹理查找目前boound取样器。的投影(“项目”)的版本中,纹理坐标(coord.s coord.t)除以coord。最后一个组件coord的第三个组成部分被忽略的vec4 coord变体。
	}

	//博客地址(推荐博客)
	http://blog.csdn.net/hgl868/article/details/7876257

}

{4:表达式

	{
		1:操作符
		2:数组访问
		3:构造函数
		4:成分选择
	}  

	1:操作符
	  GLSL语言的操作符与C语言相似。如下表(操作符的优先级从高到低排列)

	  操作符 描述
	  ()  用于表达式组合,函数调用,构造
	  []  数组下标,向量或矩阵的选择器
	  . 结构体和向量的成员选择
	  ++ -- 前缀或后缀的自增自减操作符
	  + – ! 一元操作符,表示正 负 逻辑非
	  * / 乘 除操作符
	  + - 二元操作符 表示加 减操作
	  <> <= >= == !=  小于,大于,小于等于, 大于等于,等于,不等于 判断符
	  && || ^^  逻辑与,或,异或
	  ?:  条件判断符
	  = += –= *=  /=  赋值操作符
	  , 表示序列
	  像 求地址的& 和 解引用的 * 操作符不再GLSL中出现,因为GLSL不能直接操作地址。类型转换操作也是不允许的。 位操作符(&,|,^,~, <<, >> ,&=, |=, ^=, <<=, >>=)是GLSL保留的操作符,将来可能会被使用。还有求模操作(%,%=)也是保留的。

	2:数组访问

	  数组的下标从0开始。合理的范围是[0, size - 1]。跟C语言一样。如果数组访问越界了,那行为是未定义的。如果着色器的编译器在编译时知道数组访问越界了,就会提示编译失败。

	  vec4 myColor, ambient, diffuse[6], specular[6];
	  myColor = ambient + diffuse[4] + specular[4];

	3:构造函数
	  构造函数可以用于初始化包含多个成员的变量,包括数组和结构体。构造函数也可以用在表达式中。调用方式如下:

	  vec3 myNormal = vec3(1.0, 1.0, 1.0);
	  greenTint = myColor + vec3(0.0, 1.0, 0.0);
	  ivec4 myColor = ivec4(255);

	  还可以使用混合标量和向量的方式来构造,只要你的元素足以填满该向量。

	  vec4 color = vec4(1.0, vec2(0.0, 1.0), 1.0);
	  vec3 v = vec3(1.0, 10.0, 1.0);
	  vec3 v1 = vec3(v);
	  vec2 fv = vec2(5.0, 6.0);
	  float f = float(fv); //用x值2.5构造,y值被舍弃

	  对于矩阵,OpenGL中矩阵是列主顺序的。如果只传了一个值,则会构造成对角矩阵,其余的元素为0.

	  mat3 m3 = mat3(1.0);
	  构造出来的矩阵式:(单位矩阵)
		1.0 0.0 0.0
		0.0 1.0 0.0
		0.0 0.0 1.0

	  mat2 matrix1 = mat2(1.0, 0.0, 0.0, 1.0);
	  mat2 matrix2 = mat2(vec2(1.0, 0.0), vec2(0.0, 1.0));
	  mat2 matrix3 = mat2(1.0); 
	  mat2 matrix4 = mat2(mat4(2.0)); //会取 4x4矩阵左上角的2x2矩阵。

	  构造函数可以用于标量数据类型的转换。GLSL不支持隐式或显示的转换,只能通过构造函数来转。其中int转为float值是一样的。float转为int则小数部分被丢弃。int或float转为bool,0和0.0转为false,其余的值转为true. bool转为int或float,false值转为0和0.0,true转为1和1.0.

	  float f = 1.7;
	  int I = int(f); // I = 1

	  数组的初始化,可以在构造函数中传入值来初始化数组中对应的每一个值。

	  ivec2 position[3] = ivec2[3]((0,0), (1,1), (2,2));
	  ivec2 pos2[3] = ivec2[]((3,3), (2,1), (3,1));

	  构造函数也可以对结构体进行初始化。其中顺序和类型要一一对应。

		struct surface {  
			int  index;
			vec3 color;
			float rotate;
		};
		surface mySurface = surface(3, vec3(red, green, blue), 0.5);

	4:成分选择
	  向量中单独的成分可以通过{x,y,z,w},{r,g,b,a}或者{s,t,p,q}的记法来表示。这些不同的记法用于顶点,颜色,纹理坐标。
	  在成分选择中,你不可以混合使用这些记法。其中{s,t,p,q}中的p替换了纹理的r坐标,因为与颜色r重复了。

		下面是用法举例:
			vec3 vec = {0.5, 0.35, 0.7};
			float r = vec.r;
			float myYz = vec.yz;
			float myQ = vec.q;//出错,数组越界访问,q代表第四个元素
			float myRY = vec.ry; //不合法,混合使用记法

	  较特殊的使用方式,你可以重复向量中的元素,或者颠倒其顺序。
		如
	  		vec3 yxz = vec.yxz; //调换顺序vec4 mySSTT = vec.sstt; //重复其中的值
	  		在赋值是,也可以选择你想要的顺序,但是不能重复其中的成分。

			vec4 myColor = {0.0, 1.0, 2.0, 1.0};
			myColor.x = -1.0;
			myColor.yz = vec2(3.0, 5.0);
			myColor.wx = vec2(1.0, 3.0);
			myColor.zz = vec2(2.0, 3.0); //不合法

	  我们也可以通过使用下标来访问向量或矩阵中的元素。如果越界那行为将是未定义的。

	  float myY = vec[1];
	  在矩阵中,可以通过一维的下标来获得该列的向量(OpenGL的矩阵是列主顺序的)。二维的小标来获得向量中的元素。

	  mat3 myMat = mat3(1.0);
		1.0 0.0 0.0
		0.0 1.0 0.0
		0.0 0.0 1.0
	  vec3 vec = myMat[0];  //获得第一列向量 1.0, 0.0, 0.0
	  float f = myMat[0][0];//第一列的第一个向量 1.0

}

{5:控制流
	{
	  1:循环(for,while,dowhile)
	  2:条件(if/else)
	  3:退出片段着色器(discard)
	}

1:循环(for,while,dowhile)
  与C和C++相似,GLSL语言也提供了for, while, do/while的循环方式。使用continue跳入下一次循环,break结束循环。

  for (l = 0; l < numLights; l++){
      if (!lightExists[l])continue;
      color += light[l];
  }

  while (i < num){
      sum += color[i];
      i++;
  }

  do{
      color += light[lightNum];
      lightNum--;
  }while (lightNum > 0)

2:条件(if/else)

  color = unlitColor;
  if (numLights > 0){
      color = litColor;
  }else{
      color = unlitColor;
  }

3:退出片段着色器(discard)

  片段着色器中有一种特殊的控制流成为discard。使用discard会退出片段着色器,不执行后面的片段着色操作。片段也不会写入帧缓冲区。

  if (color.a < 0.9)
  discard;
}

{6:函数


  在每个shader中必须有一个main函数。main函数中的void参数是可选的,但返回值是void时必须的。

  void main(void){
   ...
  }
  

  GLSL中的函数,必须是在全局范围定义和声明的。不能在函数定义中声明或定义函数。函数必须有返回类型,参数是可选的。
  参数的修饰符(in, out, inout, const等)是可选的。

  //函数声明 
  bool isAnyNegative(const vec4 v);
  void main(void){//函数调用 
    bool isNegative = isAnyNegative(gl_Color);
      ...
  }
  //定义
  bool isAnyNegative(const vec4 v){
    if (v.x < 0.0 || v.y < 0.0 || v.z < 0.0 || v.w < 0.0)
      return true;
    else
      return false;
  }

  结构体和数组也可以作为函数的参数。如果是数组作为函数的参数,则必须制定其大小。在调用传参时,只传数组名就可以了。

  vec4 sumVectors(int sumSize, vec4 v[10]);

  void main(){
      vec4 myColors[10];
      ...
      vec4 sumColor = sumVectors(5, myColors);
  }

  vec4 sumVectors(int sumSize, vec4 v[10]){
    int i = 0;
    vec4 sum = vec4(0.0);
    for(; i < sumSize; ++i){
      sum += v[i]; 
    }
    return sum;
  }
  GLSL的函数是支持重载的。函数可以同名但其参数类型或者参数个数不同即可。

  float sum(float a, float b){
    return a + b;
  }

  vec3 sum(vec3 v1, vec3 v2){
    return v1 + v2;
  }

	GLSL中函数递归是不被允许的。其行为是未定义的。
}

GLSL中提供了许多内建的函数,来方便我们的使用。可以在官方手册中查找相关的函数 http://www.opengl.org/sdk/docs/man/
GLSL指南 http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf	


 
  

强烈推荐
http://glslsandbox.com/
http://glslb.in/
https://www.shadertoy.com/
http://shaderfrog.com/


你可能感兴趣的:(OpenGLES)