以下是一個使用 OpenGL 和 GLSL 在頂點著色器中動態調整裁剪平面引數的簡單程式碼示例:
// OpenGL 初始化程式碼
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
GLFWwindow* window;
// 初始化 GLFW
void initGLFW() {
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(800, 600, "Dynamic Clip Plane Example", nullptr, nullptr);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
}
// 初始化 GLEW
void initGLEW() {
glewExperimental = GL_TRUE;
if (glewInit()!= GLEW_OK) {
std::cerr << "Failed to initialize GLEW" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
}
// 頂點著色器程式碼
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 clipPlane; // 裁剪平面引數
out vec3 fragPosition;
void main() {
fragPosition = vec3(model * vec4(position, 1.0));
// 計算頂點到裁剪平面的距離
float distance = dot(vec4(fragPosition, 1.0), clipPlane);
// 如果頂點在裁剪平面背面,則將其位置設定為一個無效值(這裡簡單設定為很大的負值)
if (distance < 0.0) {
gl_Position = vec4(-10000.0, -10000.0, -10000.0, 1.0);
} else {
gl_Position = projection * view * model * vec4(position, 1.0);
}
}
// 片段著色器程式碼
#version 330 core
in vec3 fragPosition;
out vec4 color;
void main() {
color = vec4(fragPosition, 1.0);
}
// 渲染迴圈函式
void renderLoop() {
while (!glfwWindowShouldClose(window)) {
// 處理輸入
glfwPollEvents();
// 動態更新裁剪平面引數(這裡只是簡單的示例,你可以根據實際需求更新)
float clipPlaneParameters[4] = {0.5, 0.5, -0.5, -0.5};
glUniform4fv(glGetUniformLocation(yourShaderProgram, "clipPlane"), 1, clipPlaneParameters);
// 清除顏色和深度緩衝區
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 使用你的著色器程式進行渲染
glUseProgram(yourShaderProgram);
// 繪製物體(這裡假設你已經有了一個簡單的物體繪製程式碼)
// 例如:繪製一個三角形
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO);
// 交換前後緩衝區
glfwSwapBuffers(window);
}
}
// 主函式
int main() {
initGLFW();
initGLEW();
// 編譯和連結著色器程式
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 clipPlane;
out vec3 fragPosition;
void main() {
fragPosition = vec3(model * vec4(position, 1.0));
float distance = dot(vec4(fragPosition, 1.0), clipPlane);
if (distance < 0.0) {
gl_Position = vec4(-10000.0, -10000.0, -10000.0, 1.0);
} else {
gl_Position = projection * view * model * vec4(position, 1.0);
}
}
)";
const char* fragmentShaderSource = R"(
#version 330 core
in vec3 fragPosition;
out vec4 color;
void main() {
color = vec4(fragPosition, 1.0);
}
)";
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
glCompileShader(vertexShader);
// 檢查頂點著色器編譯錯誤
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cerr << "Vertex Shader Compilation Failed: " << infoLog << std::endl;
glfwTerminate();
return -1;
}
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
glCompileShader(fragmentShader);
// 檢查片段著色器編譯錯誤
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
std::cerr << "Fragment Shader Compilation Failed: " << infoLog << std::endl;
glfwTerminate();
return -1;
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// 檢查著色器程式連結錯誤
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
std::cerr << "Shader Program Linking Failed: " << infoLog << std::endl;
glfwTerminate();
return -1;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 設定你的著色器程式
glUseProgram(shaderProgram);
// 獲取 uniform 變數的位置
GLint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
// 設定模型、檢視和投影矩陣(這裡只是簡單的示例矩陣,你需要根據實際情況設定)
glm::mat4 modelMatrix = glm::mat4(1.0f);
glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 projectionMatrix = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
// 進入渲染迴圈
renderLoop();
// 清理資源
glfwTerminate();
return 0;
}
在上述程式碼中:
- 首先初始化
GLFW
和GLEW
,建立一個 OpenGL 視窗。 - 在頂點著色器中,定義了一個
uniform
變數clipPlane
來接收裁剪平面的引數。在main
函式中,計算每個頂點到裁剪平面的距離,如果頂點在裁剪平面背面,則將其位置設定為一個無效值,使其在渲染時被裁剪掉。 - 在片段著色器中,簡單地將頂點位置作為顏色輸出,以便在螢幕上顯示。
- 在
renderLoop
函式中,動態更新裁剪平面引數,並進行渲染操作。
請注意,上述程式碼只是一個簡單的示例,實際應用中你需要根據具體需求進一步完善和擴充套件程式碼,例如處理更多的輸入、載入模型資料等。並且確保你的 OpenGL 環境已經正確配置,並且支援 GLSL
的相關特性。