C++ OpenGL es 2.0三角形上的高斯模糊
我最近学习了opengl es 2.0,现在我尝试在自己生成的三角形上制作高斯模糊。我在网上有一些难以理解的例子,大多数都是在图像上应用模糊。我知道我必须使用帧缓冲区,但我不知道如何在此基础上绘制三角形并应用模糊。 是否可以在C++中看到一个完整完整的代码? 编辑:C++ OpenGL es 2.0三角形上的高斯模糊,c++,opengl-es,glsl,shader,gaussianblur,C++,Opengl Es,Glsl,Shader,Gaussianblur,我最近学习了opengl es 2.0,现在我尝试在自己生成的三角形上制作高斯模糊。我在网上有一些难以理解的例子,大多数都是在图像上应用模糊。我知道我必须使用帧缓冲区,但我不知道如何在此基础上绘制三角形并应用模糊。 是否可以在C++中看到一个完整完整的代码? 编辑: #include <stdio.h> #include <stdlib.h> #include <iostream> #define GLFW_INCLUDE_ES2 #include <
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define GLFW_INCLUDE_ES2
#include <GLFW/glfw3.h>
#include "shaders.hpp"
#include "camera.hpp"
unsigned int vbo, cbo, tbo;
GLuint _fbo, _fbo2, _tex, _tex2;
static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
GLuint pos, col, tex, normal;
camera * _camera = new camera();
static const GLfloat vertices[] = {
0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f
};
static const GLfloat colors[] = {
0.0f, 0.5f, 1.0f,
0.5f, 0.5f, 1.0f,
0.5f, 0.5f, 1.0f
};
static const GLfloat texture[] = {
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f
};
int main(void){
GLFWwindow* window;
shaders * shaderBasic;
GLuint pId;
glm::mat4 projection; static glm::mat4 view; static glm::mat4 model;
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
glfwMakeContextCurrent(window);
printf("GL_VERSION : %s\n", glGetString(GL_VERSION) );
printf("GL_RENDERER : %s\n", glGetString(GL_RENDERER) );
std::string vs, fs;
vs = "basic.vs";
fs = "basic.fs";
shaderBasic = new shaders(vs, fs);
shaderBasic->CompileShader();
shaderBasic->LinkShader();
pId = shaderBasic->getProgramId();
pos = glGetAttribLocation(pId, "position");
col = glGetAttribLocation(pId, "colors");
tex = glGetAttribLocation(pId, "tex");
fs = "lastBlur.fs";
shaders * blurShader;
GLuint pIdBlur;
blurShader = new shaders(vs, fs);
blurShader->CompileShader();
blurShader->LinkShader();
pIdBlur = blurShader->getProgramId();
_camera->setPositionCamera(glm::vec3(0, 0, -1));
_camera->setLookAtCamera(glm::vec3(0, 0, 0));
_camera->setFieldOfView(45);
_camera->setAspect(WIDTH, HEIGHT);
_camera->setViewport(WIDTH, HEIGHT);
_camera->getMatricies(projection, view, model);
glGenFramebuffers(1, &_fbo);
glGenTextures(1, &_tex);
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glBindTexture(GL_TEXTURE_2D, _tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH/2, HEIGHT/2, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _tex, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
else{
std::cout << "FRAMEBUFFER COMPLETE" << std::endl;
}
auto sampTex = glGetUniformLocation(pIdBlur, "texture0");
std::cerr << "sampTex : " << sampTex << std::endl;
glUniform1i(sampTex, 0);
while (!glfwWindowShouldClose(window)) {
// glViewport(0, 0, WIDTH, HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glClearColor(0.0f, 0.0f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// glViewport(0, 0, WIDTH/2, HEIGHT/2);
glUseProgram(pIdBlur);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(pos, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(pos);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &cbo);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer(col, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(col);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &tbo);
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(texture), texture, GL_STATIC_DRAW);
glVertexAttribPointer(tex, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(tex);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(pId);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _tex);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwPollEvents();
glfwSwapBuffers(window);
}
glDeleteBuffers(1, &vbo);
glfwTerminate();
return EXIT_SUCCESS;
}
通常,需要将要模糊的场景绘制为具有附加纹理的帧缓冲区对象(FBO)
- 创建一个帧缓冲区
- 创建空纹理(数据参数应为null)
- 绑定帧缓冲区和纹理
- 将纹理作为颜色附加到帧缓冲区
- 绑定主缓冲区(通常索引为0)
- 绑定纹理
- 使用模糊着色器将纹理绘制到主缓冲区
- 创建绘制并显示三角形的场景
- 创建一个FBO,绘制到它,然后在主缓冲区上绘制FBO纹理
- 创建通过纹理绘制和显示模糊图像的场景
- 创建绘制场景的FBO,然后从主缓冲区上的FBO绘制模糊纹理
如果您发现自己在上述任何一点上遇到了麻烦,您可能想问一个具体的问题。我想您已经交换了
pIdBlur
和pId
我将为您介绍高斯模糊着色器,它有两个过程。这是一个近似值,它首先在第一遍中沿X轴模糊,在第二遍中沿Y轴模糊。这将产生更好的强模糊性能。
“模糊”着色器使用“模糊”选项。对于这两个过程,使用相同的着色器程序,对这两个过程进行单独的方向设置,存储在uniformvec2 u_dir
中。模糊效果的强度可随[0.0,1.0]范围内的均匀变量float u_sigma
而变化
模糊顶点着色器
precision mediump float;
attribute vec2 inPos;
varying vec2 pos;
void main()
{
pos = inPos;
gl_Position = vec4( inPos, 0.0, 1.0 );
}
模糊片段着色器
precision mediump float;
varying vec2 pos;
uniform sampler2D u_texture;
uniform vec2 u_textureSize;
uniform float u_sigma;
uniform vec2 u_dir;
float CalcGauss( float x, float sigma )
{
if ( sigma <= 0.0 )
return 0.0;
return exp( -(x*x) / (2.0 * sigma) ) / (2.0 * 3.14157 * sigma);
}
void main()
{
vec2 texC = pos.st * 0.5 + 0.5;
vec4 texCol = texture2D( u_texture, texC );
vec4 gaussCol = vec4( texCol.rgb, 1.0 );
vec2 step = u_dir / u_textureSize;
for ( int i = 1; i <= 32; ++ i )
{
float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
if ( weight < 1.0/255.0 )
break;
texCol = texture2D( u_texture, texC + step * float(i) );
gaussCol += vec4( texCol.rgb * weight, weight );
texCol = texture2D( u_texture, texC - step * float(i) );
gaussCol += vec4( texCol.rgb * weight, weight );
}
gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
gl_FragColor = vec4( gaussCol.rgb, 1.0 );
}
必须创建一个顶点阵列对象,该对象包含一个四边形,稍后将在整个视口上绘制,用于屏幕空间模糊过程:
GLuint screenVAO;
glGenVertexArrays( 1, &screenVAO );
glBindVertexArray( screenVAO );
GLuint quadBuf;
glGenBuffers( 1, &quadBuf );
glBindBuffer( GL_ARRAY_BUFFER, quadBuf );
GLfloat screenRect[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };
glBufferData( GL_ARRAY_BUFFER, 8 * sizeof( float ), screenRect, GL_STATIC_DRAW );
glEnableVertexAttribArray( attrInxPos );
glVertexAttribPointer( attrInxPos, 2, GL_FLOAT, GL_FALSE, 0, nullptr );
必须创建两个帧缓冲区,并将纹理附着到其颜色平面。在第一个场景中,绘制场景。这个
第二个用于第一个模糊过程。第二次模糊过程直接绘制到绘图缓冲区
GLuint texObj[2];
GLuint fbObj[2];
glGenTextures(2, texObj);
glGenFramebuffers(2, fbObj);
glActiveTexture(GL_TEXTURE0);
for ( int i = 0; i < 2; i ++ )
{
glBindTexture(GL_TEXTURE_2D, texObj[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[i]);
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texObj[i], 0 );
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer( GL_RENDERBUFFER, renderbuffer );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer );
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
并使用着色器程序绘制对象:
glUseProgram(pId);
现在绘制场景的对象
.....
glDrawArrays(GL_TRIANGLES, 0, 3);
第二步是第一次模糊过程。必须使用模糊程序,并且必须绑定第二帧缓冲区。
释放第1帧缓冲区后,可以使用附加到其颜色平面的纹理作为模糊着色器的输入。注意,纹理不能同时作为源和目标,这将导致未定义的行为。
要将纹理绑定到着色器,必须将纹理绑定到纹理单元,并将纹理单元的索引指定给着色器的统一采样器
int texUnitIndex = 1;
GLfloat texSize = { width, height };
GLfloat dirX[] = { 1.0f, 0.0f };
GLfloat sigma = .....; // 0.0 <= sigma <= 1.0
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[1]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(pIdBlur);
glActiveTexture(GL_TEXTURE0 + texUnitIndex);
glBindTexture(GL_TEXTURE_2D, texObj[0]);
glUniform1i(locTexture, texUnitIndex);
glUniform2fv(locTexSize, texSize);
glUniform2fv(locTexSize, dirX);
glUniform1f(locTexSize, sigma);
第二个也是最后一个模糊过程类似于第一个模糊过程。第一个模糊过程的目标纹理是源纹理,目标是绘图缓冲区。必须为视口的Y轴设置模糊方向
GLfloat dirY[] = { 0.0f, 1.0f };
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texObj[1]);
glUniform2fv(locTexSize, dirY);
另见以下问题的答案:
(函数loadscene(){
变量调整大小、gl、progDraw、progBlur、vp_大小、blurFB;
var canvas,camera,bufCube={},bufQuad={};
光泽度=10.0,辉光=10.0,西格玛=0.8,半径=1.0;
函数渲染(deltaMS){
var滑块刻度=100;
sigma=document.getElementById(“sigma”).value/sliderScale;
radius=document.getElementById(“radius”).value/sliderScale;
vp_size=[canvas.width,canvas.height];
摄像机更新(vp_尺寸);
总帐启用(总帐深度测试);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//设置帧缓冲区
gl.bindFramebuffer(gl.FRAMEBUFFER,blurFB[0]);
gl.视口(0,0,blurFB[0]。宽度,blurFB[0]。高度);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//设置视图投影和模型
var prjMat=camera.Perspective();
var viewMat=camera.LookAt();
var modelMat=RotateAxis(IdentM44(),分形(deltaMS/13000.0)*2.0*Math.PI,0);
modelMat=旋转轴(modelMat,分形(deltaMS/17000.0)*2.0*Math.PI,1);
//设置绘图着色器
ShProg.用法(progDraw);
ShProg.SetM44(prograw,“u_projectionMat44”,prjMat);
ShProg.SetM44(progDraw,“u_modelViewMat44”,乘法(viewMat,modelMat));
ShProg.SetF1(程序图,“亮度”,亮度);
//画场景
VertexBuffer.Draw(bufCube);
//设置blur-X帧缓冲区并绑定frambuffer纹理
gl.bindFramebuffer(gl.FRAMEBUFFER,blurFB[1]);
gl.视口(0,0,blurFB[1]。宽度,blurFB[1]。高度);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var-texUnit=1;
gl.activeTexture(gl.TEXTURE0+texUnit);
gl.bindTexture(gl.TEXTURE\u 2D,blurFB[0].color0\u纹理);
//设置blur-X着色器
程序使用(程序模糊);
ShProg.SetI1(程序模糊,“u_纹理”,texUnit)
ShProg.SetF2(程序模糊,“u_纹理化”,vp_尺寸);
ShProg.SetF1(程序模糊,“u_西格玛”,西格玛)
ShProg.SetF1(程序模糊,“u_半径”,半径)
ShProg.SetF2(progBlur,“u_dir”[1.0,0.0])
//绘制全屏空间
gl.EnableVertexAttributeArray(progBlur.inPos);
gl.bindBuffer(gl.ARRAY\u BUFFER,bufQuad.pos);
顶点
.....
glDrawArrays(GL_TRIANGLES, 0, 3);
int texUnitIndex = 1;
GLfloat texSize = { width, height };
GLfloat dirX[] = { 1.0f, 0.0f };
GLfloat sigma = .....; // 0.0 <= sigma <= 1.0
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[1]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(pIdBlur);
glActiveTexture(GL_TEXTURE0 + texUnitIndex);
glBindTexture(GL_TEXTURE_2D, texObj[0]);
glUniform1i(locTexture, texUnitIndex);
glUniform2fv(locTexSize, texSize);
glUniform2fv(locTexSize, dirX);
glUniform1f(locTexSize, sigma);
glBindVertexArray( screenVAO );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
GLfloat dirY[] = { 0.0f, 1.0f };
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texObj[1]);
glUniform2fv(locTexSize, dirY);