简述
在OpenGL中,可以将一个物体的渲染结果输出到不同的帧缓冲区域,实现多个的视口效果,着色器中提供了一个内置的输出变量gl_ViewportIndex来重定向输出,它的值也可以作为片元着色器的输入使用。多视口在三维建模软件中比较常见,如3DMAX。
在OpenGL中,可以将一个物体的渲染结果输出到不同的帧缓冲区域,实现多个的视口效果,着色器中提供了一个内置的输出变量gl_ViewportIndex来重定向输出,它的值也可以作为片元着色器的输入使用。多视口在三维建模软件中比较常见,如3DMAX。
在OpenGL应用程序中可以通过glViewportIndexedf()或glViewportIndexedfv()函数来设置,可以指定剪切坐标窗口的x和y坐标值。
void glViewportIndexedf(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) 功 能:设置视口索引及视口范围 返回值:void 参 数:index视口索引值,以0为开始值 x 视口位置x坐标,左下角坐标 y 视口位置y坐标,左下角坐标 w 视口宽度 h 视口高度 |
void glViewportIndexedfv(GLuint index, const GLfloat *v) 功 能:设置视口索引及视口范围 返回值:void 参 数:index视口索引值,以0为开始值 v 视口位置及大小数组,与函数glViewportIndexedf中后四个参数的信息一致 |
实现方法
应用程序
在应用程序中开启相关多视口功能
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
在窗口重绘事件中设置每个视口的位置和大小
应用程序
在应用程序中开启相关多视口功能
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
在窗口重绘事件中设置每个视口的位置和大小
glViewportIndexedf(0, 0.0f, 0.0f, width/2, height/2);
glViewportIndexedf(1, width/2, 0.0f, width/,, height/2);
glViewportIndexedf(2, 0.0f, height/2, width/2, height/2);
glViewportIndexedf(3, width/2, width/2, width/2, height/2);
glViewportIndexedf(1, width/2, 0.0f, width/,, height/2);
glViewportIndexedf(2, 0.0f, height/2, width/2, height/2);
glViewportIndexedf(3, width/2, width/2, width/2, height/2);
着色器
主要在几何着色器设置每个顶点的视口索引,需要生成四个实例,每个实例重定向到一个窗口来完成几何体的扩充,其他着色器按一般设置即可
几何着色器
for (int i = 0; i < gl_in.length(); i++)
{
gl_ViewportIndex = gl_InvocationID;
gs_color = colors[gl_InvocationID];
//顶点位置
gl_Position = projection * view[gl_InvocationID] * model * gl_in[i].gl_Position;
EmitVertex();
}
主要在几何着色器设置每个顶点的视口索引,需要生成四个实例,每个实例重定向到一个窗口来完成几何体的扩充,其他着色器按一般设置即可
几何着色器
for (int i = 0; i < gl_in.length(); i++)
{
gl_ViewportIndex = gl_InvocationID;
gs_color = colors[gl_InvocationID];
//顶点位置
gl_Position = projection * view[gl_InvocationID] * model * gl_in[i].gl_Position;
EmitVertex();
}
源码
顶点着色器
#version 410 layout (location = 0) in vec3 position; void main(void) { gl_Position = vec4(position, 1.0); };
几何着色器
#version 410 layout (triangles, invocations = 4) in; layout (triangle_strip, max_vertices = 3) out; out vec4 gs_color; uniform mat4 model; uniform mat4 projection; uniform mat4 view[4]; const vec4 colors[4] = vec4[4] ( vec4(1.0, 0.7, 0.3, 1.0), vec4(1.0, 0.2, 0.3, 1.0), vec4(0.1, 0.6, 1.0, 1.0), vec4(0.3, 0.7, 0.5, 1.0) ); void main(void) { for (int i = 0; i < gl_in.length(); i++) { gl_ViewportIndex = gl_InvocationID; gs_color = colors[gl_InvocationID]; //顶点位置 gl_Position = projection * view[gl_InvocationID] * model * gl_in[i].gl_Position; EmitVertex(); } };
片段着色器
#version 410 layout (location = 0) out vec4 color; in vec4 gs_color; void main(void) { color = gs_color; };程序
#include <glew/include/GL/glew.h> #include <glfw/include/glfw3.h> #include <string> #include <fstream> #include <sstream> #include <iostream> #include "./glm/glm.hpp" #include "./glm/gtc/matrix_transform.hpp" #include "./glm/gtc/type_ptr.hpp" #include "Camera.h" #include "Fountain.h" #define GLFW_STATIC #define WIDTH 800 #define HEIGHT 600 #if 1 void framebuffer_size_callback(GLFWwindow* window, int width, int height); int main() { std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl; // Init GLFW glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { std::cout << "Failed to initialize GLEW" << std::endl; return -1; } //设置视口 glViewport(0, 0, WIDTH, HEIGHT - 151); //着色器程序 Shader shader("./shader/portArray.vs", "./shader/portArray.fs", "./shader/portArray.gs"); float vertices[] = { // 位置 0.5f, -0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f }; //创建缓存对象 unsigned int VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); //绑定VAO glBindVertexArray(VAO); //绑定VBO glBindBuffer(GL_ARRAY_BUFFER, VBO); //把顶点数组复制到VBO glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 位置属性,第一个参数是着色器位置 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //开启多视口功能 glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); //刷新一下 framebuffer_size_callback(window, WIDTH, HEIGHT); //渲染循环 while (!glfwWindowShouldClose(window)) { glfwPollEvents(); glClearColor(0.2, 0.3, 0.3, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); //设置模型矩阵 glm::mat4 projection; projection = glm::perspective(glm::radians(45.0f), ((float)WIDTH / 2) / ((float)HEIGHT / 2), 0.1f, 10000.0f); shader.setMat4("projection", projection); //设置透视矩阵 glm::mat4 model; model = glm::translate(model, glm::vec3(0, 0, 0)); shader.setMat4("model", model); //设置视图矩阵 glm::mat4 view[4]; view[0] = glm::lookAt(glm::vec3(80, 110, 80), glm::vec3(0, 0, 0), glm::vec3(0.0f, 1.0f, 0.0f)); view[1] = glm::lookAt(glm::vec3(10, 130, 80), glm::vec3(0, 0, 0), glm::vec3(0.0f, 1.0f, 0.0f)); view[2] = glm::lookAt(glm::vec3(60, 50, 40), glm::vec3(0, 0, 0), glm::vec3(0.0f, 1.0f, 0.0f)); view[3] = glm::lookAt(glm::vec3(50, 98, 45), glm::vec3(0, 0, 0), glm::vec3(0.0f, 1.0f, 0.0f)); shader.setMat4("view[0]", view[0]); shader.setMat4("view[1]", view[1]); shader.setMat4("view[2]", view[2]); shader.setMat4("view[3]", view[3]); glBindVertexArray(VAO); //开始绘制 glDrawArrays(GL_TRIANGLES, 0,3); //解除绑定 glBindVertexArray(0); //交换缓存 glfwSwapBuffers(window); } glfwTerminate(); return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { const float wot = float(width) * 0.5f; const float hot = float(height) * 0.5f; glViewportIndexedf(0, 0.0f, 0.0f, wot, hot); glViewportIndexedf(1, wot, 0.0f, wot, hot); glViewportIndexedf(2, 0.0f, hot, wot, hot); glViewportIndexedf(3, wot, hot, wot, hot); } #endif效果