I am having difficulty writing an application to simulate some fluid dynamics. Forgetting the context specific stuff, my problem right now seems to be with the general setup of using the GPU for general purpose calculations.
My Fluid class has a 2D grid of vertices, each containing its integral ordinal (X,Y). I try to store this info in a vertex buffer object (m_VBO_GridIndices).
I want to pass the vertex coordinate to the shader, have it do some calculations, and store the result somewhere. As I understand it, it can’t write to a texture, but it can write to a frame buffer object which can then be converted to a 2D texture, which is what I need. Each texel in the texture will contain a calculation result.
When I call Fluid::EvaluateWaves(), the glDrawElements raises an “invalid framebuffer operation”. I am fairly certain I am not setting up the state correctly.
// Constructor...
Fluid::Fluid(
GLuint const Width,
GLuint const Height,
GLfloat const DistanceBetweenVertices,
GLfloat const EvaluationInterval,
GLfloat const WaveSpeed,
GLfloat const Viscosity)
: m_Width(Width),
m_Height(Height),
m_ProgramObject(0),
m_GVA_VertexIndices(0),
m_FrameBufferObject(0),
m_RenderBufferObject(0),
m_BufferSwitch(GL_FALSE),
m_VBO_GridIndices(0)
{
// Reserve texture names...
// Z-displacement...
glGenTextures(2, m_TextureID_Z);
// Normals...
glGenTextures(2, m_TextureID_Normals);
// Tangents...
glGenTextures(2, m_TextureID_Tangents);
// Check for OpenGL errors...
PrintOpenGLErrors();
// Install fluid vertex and fragment shader calculators...
// The vertex shaders...
GLchar const *ppVertexShaders[] = { "fluid.glslv" };
// The fragment shaders...
GLchar const *ppFragmentShaders[] = { "fluid.glslf" };
// Generic vertex attribute names...
GLchar const *ppGVA[] = { "VertexIndex" };
// Generic vertex attribute ID space...
GLuint GVA_Indices[sizeof(ppGVA)];
// Compile and link...
m_ProgramObject = InstallProgram(
ppVertexShaders,
sizeof(ppVertexShaders) / sizeof(ppVertexShaders[0]),
ppFragmentShaders,
sizeof(ppFragmentShaders) / sizeof(ppFragmentShaders[0]),
ppGVA,
sizeof(ppGVA) / sizeof(ppGVA[0]),
GVA_Indices);
// Store the GVA indices...
m_GVA_VertexIndices = GVA_Indices[0];
// Initialize vertex IDs in grid...
// Calculate required storage space for all vertex IDs...
GLuint const Storage = m_Width * m_Height * sizeof(GLuint) * 2;
// Allocate on stack...
GLuint GridIDs[m_Height][m_Width][2];
// Initialize vertex numbers across the grid...
for(GLuint CurrentY = 0; CurrentY < m_Height; ++CurrentY)
for(GLuint CurrentX = 0; CurrentX < m_Width; ++CurrentX)
{
// Store grid index...
GridIDs[CurrentY][CurrentX][0] = CurrentX;
GridIDs[CurrentY][CurrentX][1] = CurrentY;
}
// Initialize vertex buffer object with vertex IDs...
// Allocate...
glGenBuffers(1, &m_VBO_GridIndices);
// Select...
glBindBuffer(GL_ARRAY_BUFFER, m_VBO_GridIndices);
// Commit grid indices to card...
glBufferData(GL_ARRAY_BUFFER, Storage, &GridIDs, GL_STATIC_DRAW);
glVertexAttribPointer(m_GVA_VertexIndices, 2, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
// Initialize frame and render buffers objects...
// Generate frame and render buffer objects...
glGenFramebuffers(1, &m_FrameBufferObject);
glGenRenderbuffers(1, &m_RenderBufferObject);
// Initialize the render buffer object...
// Select...
glBindRenderbuffer(GL_RENDERBUFFER, m_RenderBufferObject);
// Allocate storage...
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
m_Width, m_Height);
// Initalize the frame buffer object...
// Select frame buffer object...
glBindFramebuffer(GL_FRAMEBUFFER, m_FrameBufferObject);
// Attach render buffer object to frame buffer object...
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, m_RenderBufferObject);
// Select the Z-displacement texture map...
glBindTexture(GL_TEXTURE_2D, m_TextureID_Z[m_BufferSwitch]);
// Specify texture location...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0,
GL_RGBA, GL_FLOAT, NULL);
// Attach the Z-displacement texture map to the frame buffer object...
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, m_TextureID_Z[m_BufferSwitch], 0);
// Go back to regular frame buffer rendering
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Check for OpenGL errors...
PrintOpenGLErrors();
}
// Re-evaluate the waves, but must be called at constant interval...
void Fluid::EvaluateWaves()
{
// Variables...
GLint Viewport[4] = { 0, 0, 0, 0 };
/* Variables...
GLint ActiveTextureUnit = 0;
// Remember the current texture unit...
glGetIntegerv(GL_ACTIVE_TEXTURE, &ActiveTextureUnit);*/
// Remember the original viewport dimensions...
glGetIntegerv(GL_VIEWPORT, Viewport);
// Make sure no texture selected...
glBindTexture(GL_TEXTURE_2D, 0);
// Redirect render output to our framebuffer object...
glBindFramebuffer(GL_FRAMEBUFFER, m_FrameBufferObject);
// Resize to size of grid...
glViewport(0, 0, m_Width, m_Height);
// Enable required vertex arrays...
glEnableVertexAttribArray(m_GVA_VertexIndices);
// Install shader...
glUseProgram(m_ProgramObject);
// Select the grid indices...
glBindBuffer(GL_ARRAY_BUFFER, m_VBO_GridIndices);
// Send vertex grid indices to shader...
glDrawElements(GL_POINTS, m_Width * m_Height, GL_UNSIGNED_INT, NULL);
// Disable required vertex arrays...
glDisableVertexAttribArray(m_GVA_VertexIndices);
// Restore normal framebuffer rendering...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Restore viewport to original dimensions...
glViewport(Viewport[0], Viewport[1], Viewport[2], Viewport[3]);
}
// Deconstructor...
Fluid::~Fluid()
{
}
Any help is appreciated.
Kip