您现在的位置是:首页 > 正文

OpenGL之Shader编程入门

2024-02-01 01:33:06阅读 2

1.shader 编程基础

1.1 Vertex shader与Fragment shader
Vertex shader即顶点着色器,用来改变顶点的属性。Fragment shader即片元着色器,用来改变片元的颜色,在Direct3D中称为Pixel shader,像素着色器。

1.2 编程语言
面向OpenGL的GLSL语言,Cg语言,以及面向Direct3D的HLSL语言。Cg语言与HLSL语言语法基本上相同。

1.3 Vertex shader 功能
vertex shader 可以控制如下方框中的通道对应的属性信息,包括几何变换、投影变换、光照计算等。
在这里插入图片描述

1.4 Fragment shader功能
Fragment shader的功能如下。
在这里插入图片描述
主颜色与辅助颜色(Primary Color、Secondary Color):设置辅助颜色的目的是将Specular颜色与Ambient、Diffuse颜色分开;

  • 在典型的光照计算中,分别计算ambient、diffuse、specular和自发光的值,让后进行叠加;而在这之后进行纹理映射的话,specular可能会被覆盖(弱化)。
  • 为了解决这个问题,OpenGL中提供了glLightModelfv(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)函数,调用函数可以将每个顶点的光照计算分为主颜色和辅助颜色,主颜色包含所有非镜面反射光照的总贡献,而辅助颜色为镜面反射光照的贡献。
  • 纹理映射的时候只将主颜色和辅助颜色混合起来,执行完纹理映射后,再将主颜色和纹理颜色混合的结果与辅助颜色混合起来。

Fragment shader可以做片元测试,但实际中可以交给固定管线来做。在新版本中alpha测试需要在Frgment shader来做,固定管线已经废弃。可以使用discard来做alpha测试。

//alpha 值小于0.1f。该片元将被丢弃
if(vColorValue.a < 0.1f)
{
	discard;
}

1.5 vertex shader 与fragment shader案例

  • vertex shader
void main(void{
	gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_vertex;
}
uniform float time;
void main(void{
	vec4 v = gl_Vertex;
	v.z = sin(5.0 * v.x * time ) * 0.25;
	gl_Position = gl_ModelViewMatrix * v;
}
  • fragment shader
//改变颜色
void main(void)
{
	gl_FragColor = vec4(0.0,1.0,0.0,1.0);
}

2.OpenGL中的shader编程

2.1 OpenGL通过引入扩展库 glew来更方便的进行shader编程。
glew下载地址:http://glew.sourceforge.net/,对下载的源码进行编译生成lib和dll即可引用。

2.2 检测显卡是否支持shader编程

if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
{
	printf("Ready for glsl\n");
{

2.3 shader代码可以在C++源代码文件中存储在字符串变量中,也可将shader代码编写到独立的文件中,然后将文本文件读取到字符串中即可。

2.4 两个概念

  • 着色器对象(shader):一个着色器对象对应一个shader程序;
  • 着色器程序(program):可以装载多个着色器对象;

shader编程主要过程:

  • 创建着色器对象;
  • 将着色器源代码装载入着色器对象;
  • 将源代码编译为目标代码;
  • 创建着色器程序;
  • 将着色器对象附加到着色器程序中;
  • 链接着色器程序;
    在这里插入图片描述http://www.lighthouse3d.com.tutorials/glsl-tutorial/

2.5 shader编程

glUseProgram(GL_shaderProgram);
//释放
glUseProgram(0);
  • 检测编译是否正确
//获取编译错误,存放到param中
glGetShaderiv(GLuint objec,GLenum type ,int* param);
type : GL_COMPILE_STATUS
  • 检查链接是否正确
glGetProgramiv(GLuint objec,GLenum type ,int* param)
type : GL_LINK_STATUS
  • 获取日志Infolog
glGetSHaderInfoLog(GLuint objec,int maxLen ,int* len,char* log);
glGetProgramInfoLog(GLuint objec,int maxLen ,int* len,char* log);
  • 清除
glDetachShader(GLuint program,GLuint shader);
glDeleteShader(GLuint id);
glDeleteProgram(GLuint id);

3.VS与FS之间的数据流
vertex shader代码只需要编写对单个顶点的操作即可,GPU会自动将其作用到其他顶点上;fragment shader只需要编写对单个片元的操作即可。
在这里插入图片描述

  • VS的输入:针对顶点的属性、一致型变量(uniform)(对所有顶点都一样);
  • VS的输出:针对顶点的数据;
  • FS的输入:针对片元的属性、一致型变量(uniform)(对所有片元都一样);
  • FS的输出:gl_FragColor、gl_FragDepth 、…;

编写shader时,内建的变量以gl开头,可以直接使用。而自定义的变量,从程序中传入。

  • 代码程序,如下进行time以及vertCol变量的传递,与VS中的同名变量绑定。
glUseProgram(GL_shaderProgram);
//取得shader代码中的time变量的location
time_location = glGetUniformLocation(G_shaderProgram,"time");
//将time_location与程序中定义的变量shaderTime进行关联,则shaderTime的值就可以传递到time,即可对shaderTime进行操作即可;
glUniform1f(time_location,shaderTime);

//取得shader中vertCol变量的localtion
vertCol_location = glGetAttributeLocation(G_shaderProgram,"vertCol");

//通过函数将值进行传递
glVertexAttrib4f(vertCol_location ,1.0f,0.0f,0.0f,0.0f);
  • vertex shader程序
uniform float time;
in vec4 vertCol; // 表述输入数据
out vec4 col;	 //输出数据;

void main(void)
{
	vec4 v = gl_Vertex;
	v.y += time * 0.1;
	col = vertCol;
	gl_Position  = gl_ModelViewProjectionMatrix * v;
}
  • fragment shader程序
in vec4 col;	//与vertxe中col对应
void main(void)
{
	gl_FragColor = col;
}

4.VS/FS的输入与输出变量

4.1 可以传输给VS的数据

  • 内建的uniform变量,如gl_ModelViewMatrix;只读类型;
    在这里插入图片描述

  • 内建的顶点属性变量(in 类型),如gl_Vertex;只读。
    在这里插入图片描述

  • 自己定义的uniform 类型变量,需要人为赋值,如下进行赋值操作。
    在这里插入图片描述

  • 自己定义的in类型变量,并进行赋值操作;也可以利用内建的变量来传递,如rgba中的a分量;

in vec4 vertMass;

在这里插入图片描述

  • 纹理数据;

shader编程还是内嵌到固定流水线当中,内建变量的值还是来自固定流水线。

4.2 VS的输出

  • 特定变量(Special Output Variables);可读可写;
    在这里插入图片描述

  • 内建顶点属性变量(加out限定符);可读可写;
    在这里插入图片描述

  • 自定义的顶点属性变量(加out限定符);

4.3 FS输入

  • 内建的uniform变量;
  • 内建的in类型变量;
  • 其他
    在这里插入图片描述

4.4 FS的输出
在这里插入图片描述
可以将缓冲数据绘制到gl_FragData,后面通过gl_FragData获取绘制到缓冲区的数据;

5.VS的out变量与FS的in变量的对应
在这里插入图片描述
6.总结
在这里插入图片描述

附录:图形编程技术,北京林业大学,杨刚

网站文章