著色器代碼
Vertex Shader (basic.vert)
#version 400
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec3 VertexColor;
out vec3 Color;
uniform mat4 Matrix;
void main() {
Color = VertexColor;
gl_Position = Matrix * vec4(VertexPosition, 1.0);
}
Fragment Shader (basic.frag)
#version 400
in vec3 Color;
out vec4 FragColor;
void main() {
FragColor = vec4(Color, 1.0);
}
C 主程式 (main.c)
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "readtext.h" // 自訂著色器讀取工具
GLuint vShader, fShader, programHandle;
GLuint vaoHandle, vboHandles[2];
float positionData[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
float colorData[] = { 0.2f, 0.8f, 0.0f, 0.4f, 0.6f, 0.0f, 0.1f, 0.9f, 1.0f };
float matrix[16] = {
0.5f, 0.0f, -0.866f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.866f, 0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
}; // Y 軸旋轉 60 度矩陣
void initShader() {
glewInit();
// 編譯 Vertex Shader
vShader = glCreateShader(GL_VERTEX_SHADER);
char *vs = readText("basic.vert");
glShaderSource(vShader, 1, (const char**)&vs, NULL);
glCompileShader(vShader);
free(vs);
// 檢查編譯錯誤...
// 編譯 Fragment Shader (同理)
// 連結程式
programHandle = glCreateProgram();
glAttachShader(programHandle, vShader);
glAttachShader(programHandle, fShader);
glLinkProgram(programHandle);
glUseProgram(programHandle);
}
void initVBO() {
glGenBuffers(2, vboHandles);
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(positionData), positionData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(colorData), colorData, GL_STATIC_DRAW);
glGenVertexArrays(1, &vaoHandle);
glBindVertexArray(vaoHandle);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, vboHandles[1]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vaoHandle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
// 傳遞矩陣 uniform
GLint loc = glGetUniformLocation(programHandle, "Matrix");
glUniformMatrix4fv(loc, 1, GL_TRUE, matrix);
glutSwapBuffers();
glutPostRedisplay();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("GLSL Triangle");
initShader();
initVBO();
glClearColor(0.0, 0.0, 0.0, 1.0);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
編譯鏈結
gcc main.c readtext.c -o triangle -lGLEW -lGL -lglut -lGLU -lm
# 需安裝 freeglut3-dev, libglew-dev
關鍵概念
- VAO (Vertex Array Object):封裝 VBO 綁定狀態與屬性指標配置,切換繪製物件只需綁定 VAO。
- VBO (Vertex Buffer Object):顯存緩衝區儲存頂點屬性 (位置、顏色、法線、UV)。
- Uniform:著色器只讀常數 (矩陣、時間、材質參數),CPU 透過
glUniform* 更新。
- Attribute:頂點輸入屬性 (位置、顏色),對應
layout(location=N)。
- GLSL 版本:
#version 400 要求 OpenGL 4.0+,舊硬體可用 #version 330 或 #version 130。
常見問題
| 現象 | 原因與解決 |
| 黑屏/無輸出 | 著色器編譯/連結失敗 → 必須檢查 glGetShaderInfoLog/glGetProgramInfoLog |
| 顏色錯誤 | Attribute 位置不匹配 → 確認 layout(location) 與 glVertexAttribPointer index 一致 |
| 矩陣不生效 | Uniform 位置 -1 → 名稱拼寫錯誤或著色器優化移除未使用 uniform |
| GLEW 初始化失敗 | 須在 glutCreateWindow 後呼叫 glewInit() |