OPenGL--几何着色器的应用(多视口输出)

简述
在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);
在窗口重绘事件中设置每个视口的位置和大小

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);
着色器
主要在几何着色器设置每个顶点的视口索引,需要生成四个实例,每个实例重定向到一个窗口来完成几何体的扩充,其他着色器按一般设置即可
几何着色器
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
效果

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值