Hi!
I need to render to a texture, but it doesn’t display anything, only the clear color of the render texture is displayed, here is my source code.
I try to keep a compatibility with old opengl versions, so, I’ve modified the SFML class like this. (because the name of the function change in modern opengl)
[code=cpp]
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided ‘as-is’, without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include “renderTextureImplFBO.h”
#include “…/…/…/include/odfaeg/Graphics/renderTarget.h”
#include “…/…/…/include/odfaeg/Graphics/texture.h”
#include “glCheck.h”
#include <SFML/System/Err.hpp>
#include <iostream>
using namespace sf;
namespace odfaeg {
namespace graphic {
namespace priv
{
////////////////////////////////////////////////////////////
RenderTextureImplFBO::RenderTextureImplFBO() :
m_frameBuffer(0),
m_depthBuffer(0)
{
}
////////////////////////////////////////////////////////////
RenderTextureImplFBO::~RenderTextureImplFBO()
{
ensureGlContext();
// Destroy the depth buffer
if (m_depthBuffer)
{
GLuint depthBuffer = static_cast<GLuint>(m_depthBuffer);
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3)
glCheck(glDeleteRenderbuffers(1, &depthBuffer));
else
glCheck(glDeleteRenderbuffersEXT(1, &depthBuffer));
}
// Destroy the frame buffer
if (m_frameBuffer)
{
GLuint frameBuffer = static_cast<GLuint>(m_frameBuffer);
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3)
glCheck(glDeleteFramebuffers(1, &frameBuffer));
else
glCheck(glDeleteFramebuffersEXT(1, &frameBuffer));
}
// Delete the context
delete m_context;
}
////////////////////////////////////////////////////////////
bool RenderTextureImplFBO::isAvailable()
{
ensureGlContext();
// Make sure that GLEW is initialized
priv::ensureGlewInit();
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3)
return true;
return GLEW_EXT_framebuffer_object != 0;
}
////////////////////////////////////////////////////////////
bool RenderTextureImplFBO::create(unsigned int width, unsigned int height, ContextSettings settings, unsigned int textureId)
{
// Create the context
m_context = new Context(settings, width, height);
// Create the framebuffer object
GLuint frameBuffer = 0;
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3)
glCheck(glGenFramebuffers(1, &frameBuffer));
else
glCheck(glGenFramebuffersEXT(1, &frameBuffer));
m_frameBuffer = static_cast<unsigned int>(frameBuffer);
if (!m_frameBuffer)
{
err() << "Impossible to create render texture (failed to create the frame buffer object)" << std::endl;
return false;
}
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3)
glCheck(glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer));
else
glCheck(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_frameBuffer));
// Create the depth buffer if requested
if (settings.depthBits > 0)
{
GLuint depth = 0;
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3)
glCheck(glGenRenderbuffers(1, &depth));
else
glCheck(glGenRenderbuffersEXT(1, &depth));
m_depthBuffer = static_cast<unsigned int>(depth);
if (!m_depthBuffer)
{
err() << "Impossible to create render texture (failed to create the attached depth buffer)" << std::endl;
return false;
}
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3) {
glCheck(glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer));
glCheck(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height));
glCheck(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer));
} else {
glCheck(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer));
glCheck(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height));
glCheck(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer));
}
}
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3) {
glCheck(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0));
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glCheck(glDrawBuffers(1, DrawBuffers));
} else {
// Link the texture to the frame buffer
glCheck(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0));
}
if (RenderTarget::getMajorVersion() >= 3 && RenderTarget::getMinorVersion() >= 3) {
// A final check, just to be sure.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glCheck(glBindFramebuffer(GL_FRAMEBUFFER, 0));
err() << "Impossible to create render texture (failed to link the target texture to the frame buffer)" << std::endl;
return false;
}
} else {
// A final check, just to be sure...
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
glCheck(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
err() << "Impossible to create render texture (failed to link the target texture to the frame buffer)" << std::endl;
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////
bool RenderTextureImplFBO::activate(bool active)
{
return m_context->setActive(active);
}
////////////////////////////////////////////////////////////
void RenderTextureImplFBO::updateTexture(unsigned int)
{
glFlush();
}
}
} // namespace priv
} // namespace sf
I'm trying to draw a tile on a render texture, and then, drawing the whole texture on the window, so, the code is like this :
int main(int argc, char* argv[])
{
RenderWindow window (sf::VideoMode (800, 600), “Test”, sf::Style::Default, sf::ContextSettings(0, 0, 4, 3, 3));
const std::string vertexShader =
“#version 330 core
"
“layout (location = 0) in vec4 position;”
“layout (location = 1) in vec4 color;”
“layout (location = 2) in vec2 uv;”
“layout (location = 3) in vec3 normals;”
“uniform mat4 projMatrix;”
“uniform mat4 viewMatrix;”
“uniform mat4 modelMatrix;”
“uniform mat4 texMatrix;”
“out vec4 f_color;”
“out vec2 f_uv;”
“void main() {”
" gl_Position = projMatrix * viewMatrix * modelMatrix * position;”
" f_uv = (texMatrix * vec4(uv.xy, 0, 0)).xy;"
" f_color = color;"
“}”;
const std::string fragmentShader =
“#version 330 core
"
“layout (location = 0) out vec4 color;”
“uniform sampler2D texSampler;”
“in vec2 f_uv;”
“in vec4 f_color;”
“void main() {”
" vec4 texel = texture (texSampler, f_uv);”
" color = f_color * texel;"
“}”;
Texture tex;
tex.loadFromFile(“tilesets/herbe.png”);
Tile tile (&tex, Vec3f(0, 0, 0), Vec3f(100, 50, 0), sf::IntRect(0, 0, 100, 50));
tile.move(Vec3f(100, 100, 0));
Shader simpleShader;
simpleShader.loadFromMemory(vertexShader, fragmentShader);
Matrix4f projMatrix = window.getView().getProjMatrix().getMatrix().transpose();
Matrix4f viewMatrix = window.getView().getViewMatrix().getMatrix().transpose();
Matrix4f modelMatrix = tile.getTransform().getMatrix().transpose();
Matrix4f texMatrix = tex.getTextureMatrix().transpose();
simpleShader.setParameter(“projMatrix”, projMatrix);
simpleShader.setParameter(“viewMatrix”, viewMatrix);
simpleShader.setParameter(“modelMatrix”, modelMatrix);
simpleShader.setParameter(“texMatrix”, texMatrix);
simpleShader.setParameter(“texSampler”, Shader::CurrentTexture);
RenderStates states;
states.shader = &simpleShader;
RenderTexture rt;
rt.create(window.getSize().x, window.getSize().y, window.getSettings());
rt.setView(window.getView());
rt.clear(sf::Color::White);
rt.draw(tile, states);
rt.display();
const Texture& rtex = rt.getTexture();
Tile tile2 (&rtex, Vec3f(0, 0, 0), Vec3f(rt.getView().getSize().x, rt.getView().getSize().y, 0), sf::IntRect(0, 0, rt.getView().getSize().x, rt.getView().getSize().y));
tile2.setCenter(window.getView().getPosition());
simpleShader.setParameter(“projMatrix”, rt.getView().getProjMatrix().getMatrix().transpose());
simpleShader.setParameter(“viewMatrix”, rt.getView().getViewMatrix().getMatrix().transpose());
simpleShader.setParameter(“modelMatrix”, tile2.getTransform().getMatrix().transpose());
simpleShader.setParameter(“texMatrix”, rtex.getTextureMatrix().transpose());
while (window.isOpen()) {
window.clear();
window.draw(tile2, states);
window.display();
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
}
}
return 0;
}
But only the clear color of the render texture (white) is displayed all over the screen, but if I display the tile directly on the window it works so it means that all my other classes are correct.
Have I made something wrong when creating the render texture or in my shader code ?
I've never used FBO with modern opengl. :/
So I've followed this tuorial [http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/](http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/) but everything seems to be correct. :/
PS : The source code of the tutorial works so I've doing something wrong but I can't find what...