openGL贝塞尔曲面细分

本文档详细介绍了OpenGL中的曲面细分概念,特别是针对贝塞尔曲面的细分过程。通过曲面细分控制着色器(TCS)和评估着色器(TES),文章阐述了如何使用OpenGL内置变量进行曲面细分级别的指定和控制点的传递。代码示例展示了如何在顶点着色器中硬编码控制点,并在TCS和TES中进行处理,最终在片段着色器中应用纹理。文章还包含了C++/OpenGL应用程序的代码,用于创建和渲染基于控制点的曲面。
摘要由CSDN通过智能技术生成

openGL系列文章目录

前言

现在让我们扩展我们的程序,使它将我们简单的矩形网格转换为贝塞尔曲面。细分网格
应该为我们提供了足够的顶点来对曲面进行采样(如果我们想要更多的话,我们可以增加
内部/外部细分级别)。我们现在需要的是通过管线发送控制点,然后使用这些控制点执行计
算以将细分网格转换为我们所需的贝塞尔曲面。
假设我们希望建立一个立方体贝塞尔曲面,我们将需要16 个控制点。我们可以通过VBO
从C++端发送它们,或者我们可以在顶点着色器中硬编码写死它们。图12.4 概述了来自C++端的控制点的过程。
在这里插入图片描述
图1

一、贝塞尔曲面细分原理

现在是更准确地解释曲面细分控制着色器(TCS)如何工作的好时机。与顶点着色器类
似,TCS 对每个传入顶点执行一次。另外,回想一下第2 章,OpenGL 提供了一个名为
gl_VertexID 的内置变量,它保存一个计数器,指示顶点着色器当前正在执行哪次调用。曲
面细分控制着色器中存在一个类似的内置变量gl_InvocationID。
曲面细分的一个强大功能是TCS(以及TES)着色器可以同时访问数组中的所有控制
点顶点。首先,当每个调用都可以访问所有顶点时,TCS 对每个顶点执行一次可能会让人
感到困惑。在每个TCS 调用中,冗余地在赋值语句中指定曲面细分级别也是违反直觉的。
尽管所有这些看起来都很奇怪,但这样做是因为曲面细分的架构设计使得TCS 调用可以
并行运行。
OpenGL 提供了几个用于TCS 和TES 着色器的内置变量。我们已经提到过的是
gl_InvocationID,当然还有gl_TessLevelInner 和gl_TessLevelOuter。以下是一些最有用的内
置变量的更多细节和描述。
曲面细分控制着色器(TCS)内置变量。
􀀠 gl_in[ ]——包含每个传入的控制点顶点的数组——每个传入顶点是一个数组元素。
可以使用“.”表示法将特定顶点属性作为字段进行访问。一个内置属性是gl_
Position——因此,输入顶点“i”的位置可以通过gl_in[i].gl_Position 访问。
􀀠 gl_out[ ]——用于将输出控制点的顶点发送到TES 的一个数组——每个输出顶点是
一个数组元素。可以使用“.”表示法将特定顶点属性作为字段进行访问。一个内
置属性是gl_Position——因此,输出顶点“i”的位置可以通过gl_out[i].gl_Position
访问。􀀠 gl_InvocationID——整型ID 计数器,指示TCS 当前正在执行哪个调用。一个常见
的用途是用于传递顶点属性;例如,将当前调用的顶点位置从TCS 传递到TES 可
以用如下方式完成:gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_
Position。
曲面细分评估着色器(TES)内置变量。
􀀠 gl_in[ ]——包含每个传入的控制点顶点的数组——每个传入顶点是一个数组元素。
可以使用“.”表示法将特定顶点属性作为字段进行访问。一个内置属性是gl_
Position——因此,输入顶点“i”的位置可以通过gl_in[i].gl_Position 访问。
􀀠 gl_Position——曲面细分网格顶点的输出位置,可能在TES 中被修改。重要的是要
注意gl_Position 和gl_in[xxx].gl_Position 是不同的——gl_Position 是起源于曲面细
分器的输出顶点的位置,而gl_in[xxx].gl_Position 是一个从TCS 进入TES 的控制点
顶点位置。
值得注意的是,TCS 中的输入和输出控制点顶点属性是数组。不同的是,TES 中的输入
控制点顶点和顶点属性是数组,但输出顶点是标量。此外,很容易混淆哪些顶点来自于控
制点,哪些顶点是细分建立的,然后移动以形成结果曲面。总而言之,TCS 的所有顶点输
入和输出都是控制点,而在TES 中,gl_in[ ]保存输入控制点,gl_TessCoord 保存输入的细
分网格点,gl_Position 保存用于渲染的输出表面顶点。
我们的曲面细分控制着色器现在有两个任务:指定曲面细分级别并将控制点从顶点着色
器传递到评估着色器。然后,评估着色器可以根据贝塞尔控制点修改网格点(gl_TessCoords)
的位置。
程序12.2 显示了所有4 个着色器——顶点、TCS、TES 和片段——用于指定控制点补丁,
生成平坦的曲面细分顶点网格,在控制点指定的曲面上重新定位这些顶点,并使用纹理图
像绘制生成的曲面。它还显示了C++/OpenGL 应用程序的相关部分,特别是在display()函数
中。在此示例中,控制点源自顶点着色器(它们在那里硬编码写死),而不是从C++/OpenGL
应用程序进入OpenGL 管线。代码后面会讲述其他详细信息。

二、代码

1.主程序c++

#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <SOIL2\soil2.h>
#include <string>
#include <iostream>
#include <fstream>
#include <glm\gtc\type_ptr.hpp> // glm::value_ptr
#include <glm\gtc\matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
#include "Utils.h"
using namespace std;

float toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }

#define numVAOs 1

float cameraX, cameraY, cameraZ;
float terLocX, terLocY, terLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];

// variable allocation for display
GLuint mvpLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvpMat;

float tessInner = 30.0f;
float tessOuter = 20.0f;

GLuint floorTexture;

void init(GLFWwindow* window) {
	renderingProgram = Utils::createShaderProgram("vertShader.glsl", "tessCShader.glsl", "tessEShader.glsl", "fragShader.glsl");
	cameraX = 0.0f; cameraY = 0.0f; cameraZ = 4.0f;
	terLocX = 0.0f; terLocY = 0.0f; terLocZ = 0.0f;

	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);

	floorTexture = Utils::loadTexture("floor_color.jpg");
	
	glGenVertexArrays(numVAOs, vao);
	glBindVertexArray(vao[0]);
}

void display(GLFWwindow* window, double currentTime) {
	glClear(GL_DEPTH_BUFFER_BIT);
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(renderingProgram);

	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));

	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(terLocX, terLocY, terLocZ));
	mMat = glm::rotate(mMat, toRadians(30.0f), glm::vec3(1.0f, 0.0f, 0.0f));
	mMat = glm::rotate(mMat, toRadians(100.0f), glm::vec3(0.0f, 1.0f, 0.0f));
	mvpMat = pMat * vMat * mMat;

	mvpLoc = glGetUniformLocation(renderingProgram, "mvp_matrix");

	glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvpMat));

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, floorTexture);

	glFrontFace(GL_CCW);

	glPatchParameteri(GL_PATCH_VERTICES, 16);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glDrawArrays(GL_PATCHES, 0, 16);
}

void window_size_callback(GLFWwindow* win, int newWidth, int newHeight) {
	aspect = (float)newWidth / (float)newHeight;
	glViewport(0, 0, newWidth, newHeight);
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);
}

int main(void) {
	if (!glfwInit()) { exit(EXIT_FAILURE); }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(800, 800, "Chapter12 - program2", NULL, NULL);
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);

	glfwSetWindowSizeCallback(window, window_size_callback);

	init(window);

	while (!glfwWindowShouldClose(window)) {
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

## 2.着色器代码
1.顶点着色器

```cpp
#version 430

out vec2 tc;

uniform mat4 mvp_matrix;
layout (binding = 0) uniform sampler2D tex_color;

void main(void)
{	const vec4 vertices[] =
		vec4[] (vec4(-1.0, 0.5, -1.0, 1.0),
				vec4(-0.5, 0.5, -1.0, 1.0),
				vec4( 0.5, 0.5, -1.0, 1.0),
				vec4( 1.0, 0.5, -1.0, 1.0),
				
				vec4(-1.0, 0.0, -0.5, 1.0),
				vec4(-0.5, 0.0, -0.5, 1.0),
				vec4( 0.5, 0.0, -0.5, 1.0),
				vec4( 1.0, 0.0, -0.5, 1.0),
				
				vec4(-1.0, 0.0,  0.5, 1.0),
				vec4(-0.5, 0.0,  0.5, 1.0),
				vec4( 0.5, 0.0,  0.5, 1.0),
				vec4( 1.0, 0.0,  0.5, 1.0),
				
				vec4(-1.0,-0.5,  1.0, 1.0),
				vec4(-0.5, 0.3,  1.0, 1.0),
				vec4( 0.5, 0.3,  1.0, 1.0),
				vec4( 1.0, 0.3,  1.0, 1.0));
				
	tc = vec2((vertices[gl_VertexID].x + 1.0)/2.0, (vertices[gl_VertexID].z + 1.0)/2.0);

	gl_Position = vertices[gl_VertexID];
}

2.片元着色器
#version 430

in vec2 tes_out;
out vec4 color;
uniform mat4 mvp_matrix;

layout (binding=0) uniform sampler2D tex_color;

void main(void)
{
color = texture(tex_color, tes_out);
}

3.曲面细分着色器

#version 430

in vec2 tc[];
out vec2 tcs_out[];

uniform mat4 mvp_matrix;
layout (binding=0) uniform sampler2D tex_color;
layout (vertices = 16) out;

void main(void)
{	int TL = 32;  // tessellation levels
	if (gl_InvocationID ==0)
	{	gl_TessLevelOuter[0] = TL;
		gl_TessLevelOuter[2] = TL;
		gl_TessLevelOuter[1] = TL;
		gl_TessLevelOuter[3] = TL;
		gl_TessLevelInner[0] = TL;
		gl_TessLevelInner[1] = TL;
	}
	tcs_out[gl_InvocationID] = tc[gl_InvocationID];
	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
#version 430

layout (quads, equal_spacing,ccw) in;

uniform mat4 mvp_matrix;
layout (binding = 0) uniform sampler2D tex_color;

in vec2 tcs_out[];
out vec2 tes_out;

void main (void)
{	vec3 p00 = (gl_in[0].gl_Position).xyz;
	vec3 p10 = (gl_in[1].gl_Position).xyz;
	vec3 p20 = (gl_in[2].gl_Position).xyz;
	vec3 p30 = (gl_in[3].gl_Position).xyz;
	vec3 p01 = (gl_in[4].gl_Position).xyz;
	vec3 p11 = (gl_in[5].gl_Position).xyz;
	vec3 p21 = (gl_in[6].gl_Position).xyz;
	vec3 p31 = (gl_in[7].gl_Position).xyz;
	vec3 p02 = (gl_in[8].gl_Position).xyz;
	vec3 p12 = (gl_in[9].gl_Position).xyz;
	vec3 p22 = (gl_in[10].gl_Position).xyz;
	vec3 p32 = (gl_in[11].gl_Position).xyz;
	vec3 p03 = (gl_in[12].gl_Position).xyz;
	vec3 p13 = (gl_in[13].gl_Position).xyz;
	vec3 p23 = (gl_in[14].gl_Position).xyz;
	vec3 p33 = (gl_in[15].gl_Position).xyz;

	float u = gl_TessCoord.x;
	float v = gl_TessCoord.y;
	
	// cubic Bezier basis functions
	float bu0 = (1.0-u)  * (1.0-u)  * (1.0-u);	//(1-u)^3
	float bu1 = 3.0 * u * (1.0-u) * (1.0-u);	//3u(1-u)^2  
	float bu2 = 3. * u * u * (1.0-u);			//3u^2(1-u)
	float bu3 = u * u * u;						//u^3
	float bv0 = (1.0-v)  * (1.0-v)  * (1.0-v);	//(1-v)^3
	float bv1 = 3.0 * v * (1.0-v) * (1.0-v);	//3v(1-v)^2  
	float bv2 = 3. * v * v * (1.0-v);			//3v^2(1-v)
	float bv3 = v * v * v;						//v^3
	
	// output the position of this vertex in the tessellated patch
	vec3 outputPosition =
		  bu0 * ( bv0*p00 + bv1*p01 + bv2*p02 + bv3*p03 )
		+ bu1 * ( bv0*p10 + bv1*p11 + bv2*p12 + bv3*p13 )
		+ bu2 * ( bv0*p20 + bv1*p21 + bv2*p22 + bv3*p23 )
		+ bu3 * ( bv0*p30 + bv1*p31 + bv2*p32 + bv3*p33 );
	gl_Position = mvp_matrix * vec4(outputPosition,1.0f);   // shows bezier curve
//	gl_Position = mvp_matrix * vec4(u,0,v,1);               // shows original grid (pick one)
	
	// output the interpolated texture coordinates
	vec2 tc1 = mix(tcs_out[0], tcs_out[3], gl_TessCoord.x);
	vec2 tc2 = mix(tcs_out[12], tcs_out[15], gl_TessCoord.x);
	vec2 tc = mix(tc2, tc1, gl_TessCoord.y);
	tes_out = tc;
}

效果

在这里插入图片描述

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值