OpenGL之Shader编程入门

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编程主要过程:

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.总结
在这里插入图片描述

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

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秘境之眼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值