// 编译,可以用glGetShaderiv,指定GL_COMPILE_STATUS知道究竟有没有错误。如果你写的代码没有错,那么你的着色器就可以使用了,如果有错,可以用glGetShaderiv指定GL_INFO_LOG_LENGTH获得错误文本的长度,glGetShaderInfoLog获得错误文本
glAttachShader(program, fragment_shader);
// 关联你的着色器到程序上,删除关联用glDetachShader,这都是动态的
glLinkProgram(program);
// 链接你的程序,用所有着色器生成一个完整的着色器程序,可以用glGetProgramiv指定GL_LINK_STATUS知道究竟有没有错误。如果有错,可以用glGetProgramiv指定GL_INFO_LOG_LENGTH获取错误文本的长度,glGetProgramInfoLog获取错误文本
glUseProgram(program);
// 使用你的着色器程序,直到使用 glUseProgram(NULL)所有的OPENGL固定功能被关闭,使用你的着色器来处理
好了,接下来我们来学习着色器语言,并且测试一下它
如果你成功的话,你会看到这样的画面
这是一个光照的效果,根据公式光照能量跟距离光源的距离的平方成反比做出来的。你也可以不用着色器写,用你的CPU写也能达到一样的效果,但是着色器的速度更快(快得不止一点~)
要实现这个效果我们需要知道光照的坐标、光照的颜色、光照的能量,因为是初学,这些都是定值就好了。假设光照在屏幕的正中央,颜色是黄色,能量是3000
要达到这种效果,需要遍历屏幕上面的所有的像素,这就要用到一种叫做像素着色器的技术。
像素着色器是这样一种着色器:顶点着色器只负责简单地传递坐标,主要的代码在片段着色器上面
顶点着色器看起来是这样的:
#version 440 // 关于version:这个是GLSL的version。我使用的是4.4版本,如果你的电脑不支持,请使用更低的版本,不过低版本有的语句需要修改,也有可能是你的高性能显卡没有打开,请到你的控制面板为你的程序选择高性能显卡,或者更改全局设置
in vec4 vertex_position; // in表示由上层传递过来的数据,传递给顶点着色器的数据有坐标等,这里用到一个,就是坐标
void main()
{
gl_Position = vertex_position; // 把接受到的坐标传递给片段着色器
}
不要问我顶点着色器在一次渲染中执行了几次,因为我也不知道,在今后的学习中我会把这个问题搞懂的。我只知道片段着色器至少执行屏幕上像素个数的次数。
片段着色器看起来是这样的:
#version 440
void main()
{
float r = 1.0f;
float g = 1.0f;
float b = 0.5f;
// 黄色
vec2 p;
p.x = gl_FragCoord.x - 500;
p.y = gl_FragCoord.y - 500;
// glFragCoord表示这个点的坐标
// 在(500,500) 的地方生成光照。注意:因为OPENGL的计算方式,屏幕底部的Y坐标为0
float length = p.x * p.x + p.y * p.y; // 距离的平方
float rate = 3000.0f / length; // 比值
gl_FragColor = vec4(rate * r, rate * g, rate * b, 1.0f); // glFragColor表示这个点的最终颜色
}
**vec4等类型的用法可以自行搜索,都是挺简单的。
接下来,你需要激活屏幕上面的所有像素,以便像素着色器的运行,用画一个矩形的方法再适合不过了
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glBegin(GL_QUADS);
glVertex2f(-1, -1);
glVertex2f(-1, 1);
glVertex2f(1, 1);
glVertex2f(1, -1);
glEnd();
// SwapBuffers 或者 glFlush
参考:《OpenGL编程指南》(原书第7版)