向具有帧缓冲区的纹理发出绘图(纹理为空白)
Issue drawing to textures with framebuffer (texture blank)
在此之前,我会说我对这些主题还很陌生,最近几天我一直在为一个学校项目给自己上速成班。我很抱歉这太长了,但由于我不确定问题出在哪里,我想我会尽量彻底。
我试图使用帧缓冲区绘制一些RGBA纹理,这些纹理稍后用于其他绘制(我使用纹理中的值作为矢量来绘制粒子——纹理存储值,如它们的位置和速度)。
然而,据我所知,绘制后的纹理是空白的。纹理中的采样值会返回(0、0、0和1)。我后来的绘制过程似乎也证实了这一点,因为所有粒子都在原点重叠绘制(这一观察结果基于我的混合函数和一些硬编码的测试颜色值)。
我将OpenGL 4与SDL2和glew一起使用。
我将尝试以有序的方式发布所有相关内容:
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 1。
我已经调试了大约20-30个小时,在这里查找了十几个不同的教程和其他问题,但在过去的几个小时里,我觉得自己没有任何进展。
这里有什么突出的地方可以解释为什么纹理看起来是空白/黑色的,或者任何其他需要解决的问题?我使用这个项目来学习着色器,所以我对这一切都很陌生。任何帮助都将不胜感激。
这是通过完全重写代码来解决的。
我仍然不能100%确定问题出在哪里,但我想我可能有一些不匹配的启用/禁用调用。
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- SFML纹理像播放器
- OpenGL大的3D纹理(>2GB)非常慢
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 着色器纹理值与创建纹理时写入的值不同
- OpenGL将纹理四边形渲染为(0,0)
- 宽度为奇数的16位纹理为片状
- 使用 CUDA 和纹理进行图像减法
- 在不使用统一的情况下将纹理传递给 GLSL 着色器?
- 将使用太多的纹理插值器 - 带旋转的着色器
- dx11 渲染到纹理仅显示透明颜色
- OpenGL 4.3 错误地将第 4 个纹理坐标映射到与第 3 个纹理坐标相同的位置
- 如何使用 DXGI 格式DXGI_FORMAT_R1_UNORM创建 2D 纹理?
- 纹理单位重叠?渲染了错误的纹理
- SFML 纹理变换(放大)
- SDL2 二维纹理分配/池化
- Qt OpenGL 渲染到纹理性能问题
- 向具有帧缓冲区的纹理发出绘图(纹理为空白)
- Cinder & C++:镜像纹理和高效绘图问题
- OpenGL 3.1 使用索引绘图渲染纹理时出现问题