*****************************************************************************************************************
這是來自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;
}