Ich werde vorweg sagen, dass ich ziemlich neu zu diesen Themen bin, und habe mir die letzten Tage einen Crash-Kurs für ein Schulprojekt gegeben. Ich entschuldige mich, dass das ziemlich lang ist, aber da ich mir nicht sicher bin, wo das Problem liegt, dachte ich, ich würde versuchen, gründlich zu sein.Ausgabe Zeichnung zu Texturen mit Framebuffer (Textur leer)
Ich versuche einen Framebuffer zu verwenden, um einige RGBA-Texturen zu zeichnen, die später für andere Zeichnungen verwendet werden (Ich benutze die Werte in den Texturen als Vektoren, um Partikel zu zeichnen - Texturen speichern Werte wie ihre Position und Geschwindigkeit).
Wie ich jedoch sagen kann, sind die Texturen nach dem Zeichnen leer. Sampling-Werte in der Textur gibt zurück (0, 0, 0, 1). Dies scheint auch durch mein späteres Zeichenverfahren bestätigt zu sein, da es erscheint, dass alle Partikel im Ursprung überlappend gezeichnet werden (diese Beobachtung basiert auf meiner Mischfunktion und einigen hartcodierten Testfarbwerten).
Ich benutze OpenGL 4 mit SDL2 und glew.
Ich werde versuchen, alles, was relevant in geordneter Weise zu schreiben:
Die Framebuffer-Klasse erstellt den Framebuffer und Attaches (3) Texturen. Es hat:
GLuint buffer_id_
, dass der Bildpuffer der ID ist, auf 0 initialisiert, unsigned int width, height
, die die Breite und Höhe der Texturen in Pixeln sind, numTextures
, das ist, wie viele Texturen in dem für den Bildpuffer (wieder zu erstellen Fall 3) und std::vector<GLuint> textures_
für alle Texturen, die dem Framebuffer zugeordnet sind.
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;
}
zwei passende Framebuffer werden durch das Partikelsystem hergestellt, so daß man als Eingabe für den Shader-Programme verwendet werden können, und das andere als Ausgabe.
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();
}
Dann versuche ich, einen Anfangszustand zu dem ersten Bildpuffer zu zeichnen:
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]);
}
Sie können hier sehen, ist auch, wo ich versuche, einige Pixelwerte erhalten, die alle return (0, 0, 0 , 1).
// 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);
Vertex meine eigene Klasse, die ich nicht denken tun Ich werde hier zeigen müssen:
Der hier verwendete full_size_quad_ durch definiert ist. Es glugs und glBinds nur das Vertex-Array und die Puffer.
Der Shader hier hat dies für den Vertex-Shader verwendet:
#version 400 core
in vec3 inVertexPos;
void main() {
gl_Position = vec4(inVertexPos, 1.0);
}
und dies für die Fragment-Shader:
#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 ist die Breite und Höhe der Texturen in Pixeln, festgelegt durch :
init_shader_->use();
glUniform2f(init_uniform_ids_[constants::init::Uniforms::U_RESOLUTION]->id, particle_texture_width_, particle_texture_height_);
aus Neugier habe ich versucht zu ändern position = vec4(pos, 1.0);
dif Werte, aber mein Pixel-Druck ergab immer noch 0 0 0 1.
Ich habe das jetzt für ungefähr 20-30 Stunden debuggen, und habe ein Dutzend oder so verschiedene Tutorials und andere Fragen hier nachgeschlagen, aber die letzten paar Stunden habe ich nicht das Gefühl, dass ich irgendeinen Boden gewonnen habe.
Irgendetwas hier heraus für warum die Texturen scheinen, frei zu sein/Schwarzes oder irgendein Ding, das Adressierung benötigt? Ich habe dieses Projekt benutzt, um etwas über Shader zu lernen, also bin ich ziemlich neu in all dem. Jede Hilfe würde immens geschätzt werden.
Die Verwendung der Konstanten 'GL_MAX_COLOR_ATTACHMENTS' zur Steuerung der Zuweisung von Puffern und Anzahl der Iterationen einer Schleife ist *** FALSCH ***. Dies ist eine ID, die Sie abfragen, um die tatsächliche Anzahl herauszufinden, es ist nicht in seiner Grundform ein Limit irgendeiner Art, es wird eine Zahl so groß sein, dass Sie wahrscheinlich Laufzeitprobleme bekommen werden, die versuchen, eine Schleife zuzuweisen und auszuführen viele Male :) Fragen Sie zuerst den Wert ab. –
@ AndonM.Coleman Danke für den Fang. Jetzt frage ich es mit 'glGetIntegerv (GL_MAX_COLOR_ATTACHMENTS, & maxAttach);'. Ich glaube, ich hatte nur Glück, dass ich immer nur 3 Texturen bekam, also hatte ich bis jetzt noch nie Probleme damit. – Claytorpedo
Keine Änderung, nehme ich an? Das zweite Problem, das Ihnen in den Sinn kommt, ist, dass Sie eine Textur zum Lesen gebunden haben, die bereits an Ihren aktiven Framebuffer zum Schreiben angehängt ist. Das Binden der Textur, während sie gerade aktiv ist, als Image-Attachment des Framebuffers, ist unwahrscheinlich, dass sie etwas Gutes bewirkt. Sie erhalten möglicherweise inkohärente Werte zurück. Um Pixeldaten vom aktuell gebundenen FBO zurück zu lesen, wird erwartet, 'glReadPixels (...)' zu verwenden, wobei der Lesepuffer auf den entsprechenden Farbanhang eingestellt ist. –