我会先说这是我对这些话题的新手,并且在过去几天为学校项目提供了速成课程。我很抱歉这很长,但由于我不确定问题出在哪里,我想我会尽量彻底。
我正在尝试使用帧缓冲区来绘制一些RGBA纹理,这些纹理稍后用于其他绘图(我使用纹理中的值作为矢量来绘制粒子 - 纹理存储值,例如它们的位置和速度)。
然而,正如我所知,我绘制后的纹理是空白的。纹理中的采样值返回(0,0,0,1)。这似乎也可以通过我后来的绘图程序得到证实,因为它出现所有粒子都在原点被重叠绘制(这个观察基于我的混合函数和一些硬编码的测试颜色值)
我正在使用带有SDL2的OpenGL 4和glew。
我会尝试以有序的方式发布所有相关内容:
framebuffer类创建framebuffer并附加(3)纹理。 它有:
GLuint buffer_id_
这是帧缓冲区的id,初始化为0,unsigned int width, height
,它是纹理的宽度和高度,以像素为单位numTextures
,这是要为其创建的纹理数量帧缓冲区(在本例中为3),以及与帧缓冲区关联的所有纹理的std::vector<GLuint> textures_
。
bool Framebuffer::init() {
assert( numTextures <= GL_MAX_COLOR_ATTACHMENTS );
// Get the buffer id.
glGenFramebuffers( 1, &buffer_id_ );
glBindFramebuffer( GL_FRAMEBUFFER, buffer_id_ );
// Generate the textures.
for (unsigned int i = 0; i < numTextures; ++i) {
GLuint tex;
glGenTextures( 1, &tex );
glBindTexture(GL_TEXTURE_2D, tex);
// Give empty image to OpenGL.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, 0);
// Use GL_NEAREST, since we don't want any kind of averaging across values:
// we just want one pixel to represent a particle's data.
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// This probably isn't necessary, but we don't want to have UV coords past the image edges.
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
textures_.push_back(tex);
}
glBindTexture(GL_TEXTURE_2D, 0);
// Bind our textures to the framebuffer.
GLenum drawBuffers[GL_MAX_COLOR_ATTACHMENTS];
for (unsigned int i = 0; i < numTextures; ++i) {
GLenum attach = GL_COLOR_ATTACHMENT0 + i;
glFramebufferTexture(GL_FRAMEBUFFER, attach, textures_[i], 0);
drawBuffers[i] = attach;
}
glDrawBuffers( numTextures, drawBuffers );
if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ) {
std::cerr << "Error: Failed to create framebuffer." << std::endl;
return false;
}
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
return true;
}
两个匹配的帧缓冲区由粒子系统构成,因此一个可以用作着色器程序的输入,另一个可以用作输出。
bool AmbientParticleSystem::initFramebuffers() {
framebuffers_[0] = new Framebuffer(particle_texture_width_, particle_texture_height_, NUM_TEXTURES_PER_FRAMEBUFFER);
framebuffers_[1] = new Framebuffer(particle_texture_width_, particle_texture_height_, NUM_TEXTURES_PER_FRAMEBUFFER);
return framebuffers_[0]->init() && framebuffers_[1]->init();
}
然后我尝试将初始状态绘制到第一个帧缓冲区:
void AmbientParticleSystem::initParticleDrawing() {
glBindFramebuffer( GL_FRAMEBUFFER, framebuffers_[0]->getBufferID() );
// Store the previous viewport.
GLint prevViewport[4];
glGetIntegerv( GL_VIEWPORT, prevViewport );
glViewport( 0, 0, particle_texture_width_, particle_texture_height_ );
glClear( GL_COLOR_BUFFER_BIT );
glDisable( GL_DEPTH_TEST );
glBlendFunc( GL_ONE, GL_ZERO);
init_shader_->use(); // This sets glUseProgram to the init shader.
GLint attrib = init_variable_ids_[constants::init::Variables::IN_VERTEX_POS]->id;
glEnableVertexAttribArray( attrib );
glBindBuffer( GL_ARRAY_BUFFER, full_size_quad_->getBufferID() );
glVertexAttribPointer( attrib, full_size_quad_->vertexSize,
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 ); // Array buffer offset
glDrawArrays( GL_TRIANGLES, 0, full_size_quad_->numVertices );
// Here I'm just printing some sample values to confirm it is blank/black.
glBindTexture( GL_TEXTURE_2D, framebuffers_[0]->getTexture(0) );
GLfloat *pixels = new GLfloat[particle_texture_width_ * particle_texture_height_ * 4];
glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels);
std::cout << "some pixel entries:\n";
std::cout << "pixel0: " << pixels[0] << " " << pixels[1] << " " << pixels[2] << " " << pixels[3] << std::endl;
std::cout << "pixel10: " << pixels[40] << " " << pixels[41] << " " << pixels[42] << " " << pixels[43] << std::endl;
std::cout << "pixel100: " << pixels[400] << " " << pixels[401] << " " << pixels[402] << " " << pixels[403] << std::endl;
std::cout << "pixel10000: " << pixels[40000] << " " << pixels[40001] << " " << pixels[40002] << " " << pixels[40003] << std::endl;
// They all print 0, 0, 0, 1
delete pixels;
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDisableVertexAttribArray( attrib );
init_shader_->stopUsing();
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
// Return the viewport to its previous state.
glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3] );
}
你可以看到这里也是我尝试获取一些像素值的地方,它们都返回(0,0,0,1)。
此处使用的full_size_quad_由以下内容定义:
// Create quad for textures to draw onto.
static const GLfloat quad_array[] = {
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
std::vector<GLfloat> quad(quad_array, quad_array + 18);
full_size_quad_ = new VertexBuffer(3, 6, quad);
VertexBuffer是我自己的类,我不会认为我需要在这里展示。它只是glGens和glBinds顶点数组和缓冲区。
此处使用的着色器对顶点着色器具有此功能:
#version 400 core
in vec3 inVertexPos;
void main() {
gl_Position = vec4(inVertexPos, 1.0);
}
和片段着色器:
#version 400 core
layout(location = 0) out vec4 position;
layout(location = 1) out vec4 velocity;
layout(location = 2) out vec4 other;
uniform vec2 uResolution;
// http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
float rand(vec2 seed) {
return fract(sin(dot(seed.xy,vec2(12.9898,78.233))) * 43758.5453);
}
void main() {
vec2 uv = gl_FragCoord.xy/uResolution.xy;
vec3 pos = vec3(uv.x, uv.y, rand(uv));
vec3 vel = vec3(-2.0, 0.0, 0.0);
vec4 col = vec4(1.0, 0.3, 0.1, 0.5);
position = vec4(pos, 1.0);
velocity = vec4(vel, 1.0);
other = col;
}
uResolution是纹理的宽度和高度,以像素为单位,设置为:
init_shader_->use();
glUniform2f( init_uniform_ids_[constants::init::Uniforms::U_RESOLUTION]->id, particle_texture_width_, particle_texture_height_ );
出于好奇,我尝试将position = vec4(pos, 1.0);
更改为不同的值,但我的像素打印仍为0 0 0 1。
我现在已经调试了大约20到30个小时,在这里查了十几个不同的教程和其他问题,但过去几个小时我觉得我没有任何理由。
这里有什么东西可以解释为什么纹理看起来是空白/黑色,还是其他需要解决的东西?我正在使用这个项目来了解着色器,所以我对这一切都很陌生。任何帮助都会非常感激。
答案 0 :(得分:0)
通过完全重写代码解决了这个问题。
我仍然不能100%确定问题出在哪里,但我想我可能会遇到一些不匹配的启用/禁用来电。