OpenGL 实现多通道
OpenGL Implementing MultiPass
我在将我在 Shadertoy 中成功实现的一些代码移植到桌面 OpenGL 时遇到问题,问题是我需要创建一个 FrameBufferObject FBO,以便我可以进行屏幕外计算,稍后将传递对于主要的 glsl 片段着色器,问题是这个缓冲区需要将自身作为纹理引用以获取之前的值,以便能够 运行 模拟。
我已经成功创建了FBO:
// Framebuffer configuration.
unsigned int frameBufferOne;
glGenFramebuffers(1, &frameBufferOne);
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferOne);
// Create a colour attachment texture.
unsigned int textureColourBufferOne;
glGenTextures(1, &textureColourBufferOne);
glBindTexture(GL_TEXTURE_2D, textureColourBufferOne);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColourBufferOne, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
并设法在我的渲染循环中调用它,以便我可以渲染到 FBO,然后将这些值传递到默认帧缓冲区:
// Render Loop.
while( !glfwWindowShouldClose( window ) )
{
// Input.
processInput( window );
// Render.
// Bind to frameBuffer and draw scene as normally would to colour texture.
glBindFramebuffer( GL_FRAMEBUFFER, frameBufferOne );
glClearColor( 0.2f, 0.3f, 0.1f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
bufferShader.use();
float currentFrame = glfwGetTime();
//Set the iTimeDelta uniform.
float deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
bufferShader.setFloat( "iTimeDelta", deltaTime );
// Set the iTime uniform.
float timeValue = currentFrame;
bufferShader.setFloat( "iTime", timeValue );
// Set the iResolution uniform.
bufferShader.setVec2( "iResolution", WIDTH, HEIGHT );
// Input iMouse.
double xPos, yPos;
glfwGetCursorPos( window, &xPos, &yPos );
yPos = HEIGHT - yPos;
bufferShader.setVec2( "iMouse", xPos, yPos );
glBindVertexArray( VAO );
glBindTexture( GL_TEXTURE_2D, textureColourBufferOne );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDisable( GL_DEPTH_TEST );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
ourShader.use();
ourShader.setVec2( "iResolution", WIDTH, HEIGHT );
// Set the iTime uniform.
ourShader.setFloat( "iTime", timeValue );
glBindVertexArray(VAO);
glBindTexture( GL_TEXTURE_2D, textureColourBufferOne );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glfwSwapBuffers( window );
glfwPollEvents();
frameCount++;
finalTime = time( NULL );
if( finalTime - initialTime > 0 )
{
std::cout << "FPS : " << frameCount / (finalTime - initialTime) << std::endl;
frameCount = 0;
initialTime = finalTime;
}
但我无法将缓冲区作为纹理渲染到自身,我知道它会输出未定义的行为,我应该使用 Ping-Pong 技术。
有人能指出我正确的方向吗?
But I am not able to render the buffer to itself as a texture, I understand that it outputs undefined behaviour and that I should be using a technique as Ping-Pong.
Can somebody point me in the right direction?
您必须创建 2 个帧缓冲区对象,就像您在问题中所做的那样:frameBufferOne
和 frameBufferTwo
.
这 2 个帧缓冲区对象中的每一个都必须附加一个纹理对象:textureColourBufferOne
和 textureColourBufferTwo
.
在程序的主循环中,您必须知道帧数是偶数还是奇数。
如果数字是偶数,那么你必须渲染到 textureColourBufferOne
并且渲染通道的输入是 textureColourBufferTwo
.
如果数字是奇数,那么您必须渲染到 textureColourBufferTwo
并且渲染过程的输入是 textureColourBufferOne
.
渲染的结果总是存储在属于当前帧的帧缓冲区的纹理中:
bool even = true;
while( !glfwWindowShouldClose( window ) )
{
.....
glBindFramebuffer( GL_FRAMEBUFFER, even ? frameBufferOne : frameBufferTwo );
glClearColor( 0.2f, 0.3f, 0.1f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
.....
glBindVertexArray( VAO );
glBindTexture( GL_TEXTURE_2D, even ? textureColourBufferTwo : textureColourBufferOne );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );
.....
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
.....
glBindVertexArray(VAO);
glBindTexture( GL_TEXTURE_2D, even ? textureColourBufferOne : textureColourBufferTwo );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glfwSwapBuffers( window );
glfwPollEvents();
even = !even;
.....
}
我在将我在 Shadertoy 中成功实现的一些代码移植到桌面 OpenGL 时遇到问题,问题是我需要创建一个 FrameBufferObject FBO,以便我可以进行屏幕外计算,稍后将传递对于主要的 glsl 片段着色器,问题是这个缓冲区需要将自身作为纹理引用以获取之前的值,以便能够 运行 模拟。
我已经成功创建了FBO:
// Framebuffer configuration.
unsigned int frameBufferOne;
glGenFramebuffers(1, &frameBufferOne);
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferOne);
// Create a colour attachment texture.
unsigned int textureColourBufferOne;
glGenTextures(1, &textureColourBufferOne);
glBindTexture(GL_TEXTURE_2D, textureColourBufferOne);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColourBufferOne, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
并设法在我的渲染循环中调用它,以便我可以渲染到 FBO,然后将这些值传递到默认帧缓冲区:
// Render Loop.
while( !glfwWindowShouldClose( window ) )
{
// Input.
processInput( window );
// Render.
// Bind to frameBuffer and draw scene as normally would to colour texture.
glBindFramebuffer( GL_FRAMEBUFFER, frameBufferOne );
glClearColor( 0.2f, 0.3f, 0.1f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
bufferShader.use();
float currentFrame = glfwGetTime();
//Set the iTimeDelta uniform.
float deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
bufferShader.setFloat( "iTimeDelta", deltaTime );
// Set the iTime uniform.
float timeValue = currentFrame;
bufferShader.setFloat( "iTime", timeValue );
// Set the iResolution uniform.
bufferShader.setVec2( "iResolution", WIDTH, HEIGHT );
// Input iMouse.
double xPos, yPos;
glfwGetCursorPos( window, &xPos, &yPos );
yPos = HEIGHT - yPos;
bufferShader.setVec2( "iMouse", xPos, yPos );
glBindVertexArray( VAO );
glBindTexture( GL_TEXTURE_2D, textureColourBufferOne );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDisable( GL_DEPTH_TEST );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
ourShader.use();
ourShader.setVec2( "iResolution", WIDTH, HEIGHT );
// Set the iTime uniform.
ourShader.setFloat( "iTime", timeValue );
glBindVertexArray(VAO);
glBindTexture( GL_TEXTURE_2D, textureColourBufferOne );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glfwSwapBuffers( window );
glfwPollEvents();
frameCount++;
finalTime = time( NULL );
if( finalTime - initialTime > 0 )
{
std::cout << "FPS : " << frameCount / (finalTime - initialTime) << std::endl;
frameCount = 0;
initialTime = finalTime;
}
但我无法将缓冲区作为纹理渲染到自身,我知道它会输出未定义的行为,我应该使用 Ping-Pong 技术。
有人能指出我正确的方向吗?
But I am not able to render the buffer to itself as a texture, I understand that it outputs undefined behaviour and that I should be using a technique as Ping-Pong.
Can somebody point me in the right direction?
您必须创建 2 个帧缓冲区对象,就像您在问题中所做的那样:frameBufferOne
和 frameBufferTwo
.
这 2 个帧缓冲区对象中的每一个都必须附加一个纹理对象:textureColourBufferOne
和 textureColourBufferTwo
.
在程序的主循环中,您必须知道帧数是偶数还是奇数。
如果数字是偶数,那么你必须渲染到 textureColourBufferOne
并且渲染通道的输入是 textureColourBufferTwo
.
如果数字是奇数,那么您必须渲染到 textureColourBufferTwo
并且渲染过程的输入是 textureColourBufferOne
.
渲染的结果总是存储在属于当前帧的帧缓冲区的纹理中:
bool even = true;
while( !glfwWindowShouldClose( window ) )
{
.....
glBindFramebuffer( GL_FRAMEBUFFER, even ? frameBufferOne : frameBufferTwo );
glClearColor( 0.2f, 0.3f, 0.1f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
.....
glBindVertexArray( VAO );
glBindTexture( GL_TEXTURE_2D, even ? textureColourBufferTwo : textureColourBufferOne );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );
.....
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
.....
glBindVertexArray(VAO);
glBindTexture( GL_TEXTURE_2D, even ? textureColourBufferOne : textureColourBufferTwo );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
glfwSwapBuffers( window );
glfwPollEvents();
even = !even;
.....
}