*****************************************************************************************************************
这是来自lightthouse3d的教程,在此拙劣的翻译一下,完全是为了自己加深印象,若你不经意看见,请指正错误之处。这里并非逐句翻译,译者只是试图用更加容易理解的语句来代替原句。***********************************************************************************************************
GLSL 教程实例
HelloWorld in GLSL
这是GLSL的helloworld(译者注:还记得我们刚学编程时,很多第一课例子名字就是helloworld),一个最小的着色器,完成最基本任务:顶点转换和用单一色渲染物体。这里介绍顶点和片元着色器。
顶点着色器
顶点着色器是用来转换顶点的,下面将展示如何通过固定管线的等式进行顶点转换的,在固定管线状态下顶点转换是用模型视图矩阵和投影矩阵通过下面的等式转换的。
vTrans = projection * modelview * incomingVertex
为了在GLSL下些这样的转换,必须访问OpenGL状态来获取这两个矩阵,正如前面提到的,部分OpenGL状态在GLSL下是可以容易获取的,比如上面提到的两个矩阵,是通过预定义的uniform类型的变量声明的,如下:
uniform mat4 gl_ModelViewMatrix;
uniform mat4 gl_ProjectionMatrix;
还有一个必须做的事情:访问输入的顶点。这些顶点是通过预定义的attribute类型变量一个个传给顶点着色器的:
attribute vec4 gl_Vertex;
为了输出转换后的顶点的,着色器也定义了vec4的预定义变量 gl_Position。
根据上面我们可以写一个简单的着色器了,除了转换顶点其他什么也不做,这意味着其他功能都没有做,比如光照计算。
顶点着色器代码如下:
void main()
{
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
}
上面的代码中每个顶点都用投影矩阵乘以模型视图矩阵是一种浪费,因为这些矩阵不会每个顶点都会变的,GLSL提供了一个衍生矩阵,叫做gl_ModelViewProjectionMatrix 是上面两个矩阵乘积的结果。因此着色器代码改为:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
这两个结果相同。这能保证与固定管线相同吗?理论上会的。但在一些特变处理顶点的情况下可能会有所不同,比如在一些图形卡的高优化操作以及一些特别的函数利用了顶点转换,另外一个原因可能就是有限的数据精度,当计算在在不同的命令下完成时,由于有限的数据精度可能得到不同的计算结果。因此GLSL提供了一种完全与固定功能相同的方法:
void main()
{
gl_Position = ftransform();
}
片元着色器
片元着色器也有一个预定义的变量来表示颜色:
void main()
{
gl_FragColor = vec4(0.4,0.4,0.8,1.0);
}
例子源代码:opengl2.0下
/
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "textfile.h" //读取顶点和片元着色器代码的类
GLuint v,f,f2,p;
float lpos[4] = {1,0.5,1,0};
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;
float ratio = 1.0* w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the correct perspective.
gluPerspective(45,ratio,1,1000);
glMatrixMode(GL_MODELVIEW);
}
float a = 0;
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0,0.0,5.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
glLightfv(GL_LIGHT0, GL_POSITION, lpos);
glRotatef(a,0,1,1);
glutSolidTeapot(1);
a+=0.1;
glutSwapBuffers();
}
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27)
exit(0);
}
#define printOpenGLError() printOglError(__FILE__, __LINE__)
int printOglError(char *file, int line)
{
//
// Returns 1 if an OpenGL error occurred, 0 otherwise.
//
GLenum glErr;
int retCode = 0;
glErr = glGetError();
while (glErr != GL_NO_ERROR)
{
printf("glError in file %s @ line %d: %s/n", file, line, gluErrorString(glErr));
retCode = 1;
glErr = glGetError();
}
return retCode;
}
void printShaderInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s/n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s/n",infoLog);
free(infoLog);
}
}
void setShaders() {
char *vs = NULL,*fs = NULL,*fs2 = NULL;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
f2 = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead("minimal.vert");
fs = textFileRead("minimal.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSource(v, 1, &vv,NULL);
glShaderSource(f, 1, &ff,NULL);
free(vs);free(fs);
glCompileShader(v);
glCompileShader(f);
printShaderInfoLog(v);
printShaderInfoLog(f);
printShaderInfoLog(f2);
p = glCreateProgram();
glAttachShader(p,v);
glAttachShader(p,f);
glLinkProgram(p);
printProgramInfoLog(p);
glUseProgram(p);
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(320,320);
glutCreateWindow("MM 2004-05");
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutReshapeFunc(changeSize);
glutKeyboardFunc(processNormalKeys);
glEnable(GL_DEPTH_TEST);
glClearColor(1.0,1.0,1.0,1.0);
glEnable(GL_CULL_FACE);
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
printf("Ready for OpenGL 2.0/n");
else {
printf("OpenGL 2.0 not supported/n");
exit(1);
}
//setShaders();
glutMainLoop();
return 0;
}