简述
在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
效果