著色器代碼
Vertex Shader (triangle.vert)
#version 400
layout(location = 0) in vec3 vertexPosition;
uniform float loopDuration; // 週期 (秒)
uniform float time; // 經過時間 (秒)
void main() {
float timeScale = 2.0 * 3.14159 / loopDuration;
float currTime = mod(time, loopDuration);
vec4 offset = vec4(cos(currTime * timeScale) * 0.5,
sin(currTime * timeScale) * 0.5,
0.0, 0.0);
gl_Position = vec4(vertexPosition, 1.0) + offset;
}
Fragment Shader (triangle.frag)
#version 400
out vec4 fragColor;
uniform float fragLoopDuration; // 顏色變化週期
uniform float time;
const vec4 colorA = vec4(1.0, 0.0, 0.0, 1.0); // 紅
const vec4 colorB = vec4(0.0, 1.0, 0.0, 1.0); // 綠
void main() {
float t = mod(time, fragLoopDuration) / fragLoopDuration; // 0~1
fragColor = mix(colorA, colorB, t); // 線性插值
}
C 主程式關鍵片段
float positionData[] = { 0.8f, 0.0f, 0.0f, -0.8f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f };
// 僅位置屬性,顏色由 Fragment Shader 程序產生
GLuint vaoHandle, vboHandle;
GLint timeLoc, loopDurLoc, fragLoopDurLoc;
void initShader() {
// ... 編譯連結著色器 ...
glUseProgram(programHandle);
timeLoc = glGetUniformLocation(programHandle, "time");
loopDurLoc = glGetUniformLocation(programHandle, "loopDuration");
fragLoopDurLoc = glGetUniformLocation(programHandle, "fragLoopDuration");
}
void initVBO() {
glGenVertexArrays(1, &vaoHandle);
glGenBuffers(1, &vboHandle);
glBindVertexArray(vaoHandle);
glBindBuffer(GL_ARRAY_BUFFER, vboHandle);
glBufferData(GL_ARRAY_BUFFER, sizeof(positionData), positionData, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
void render() {
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vaoHandle);
float t = glutGet(GLUT_ELAPSED_TIME) / 1000.0f; // 秒
glUniform1f(timeLoc, t);
glUniform1f(loopDurLoc, 5.0f); // 位移週期 5 秒
glUniform1f(fragLoopDurLoc, 10.0f); // 顏色週期 10 秒
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glutSwapBuffers();
glutPostRedisplay();
}
核心技術點
- 時間驅動動畫:Uniform `time` 每幀更新,著色器內用 `mod` 實現週期性。
- 三角函數運動:`cos/sin` 產生圓周軌跡,振幅 0.5。
- 顏色插值:`mix(a, b, t)` 線性插值,`t` 為 0~1 正規化時間。
- 無 CPU 端幾何更新:所有動畫邏輯在 GPU 著色器完成,CPU 僅傳遞時間。
擴展方向
- 多物件不同時程:傳遞物件專屬 `timeOffset` uniform
- 緩動函數:`smoothstep`、`easeInOut` 替換線性 `t`
- 顏色空間:HSL 插值避免 RGB 中間灰暗
- 實例化渲染:`glDrawArraysInstanced` + `gl_InstanceID` 批次繪製千個三角形