Render To Texture Using OpenGL is not working but normal rendering works just fine
Posted
by
Franky Rivera
on Game Development
See other posts from Game Development
or by Franky Rivera
Published on 2014-08-20T12:48:48Z
Indexed on
2014/08/20
16:37 UTC
Read the original article
Hit count: 313
things I initialize at the beginning of the program I realize not all of these pertain to my issue I just copy and pasted what I had //overall initialized
//things openGL related I initialize earlier on in the project
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
glClearDepth( 1.0f );
glEnable(GL_ALPHA_TEST);
glEnable( GL_STENCIL_TEST );
glEnable(GL_DEPTH_TEST);
glDepthFunc( GL_LEQUAL );
glEnable(GL_CULL_FACE);
glFrontFace( GL_CCW );
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
//we also initialize our shader programs
//(i added some shader program functions for definitions)
//this enum list is else where in code
//i figured it would help show you guys more about my
//shader compile creation function right under this enum list VVVVVV
/*enum eSHADER_ATTRIB_LOCATION
{
VERTEX_ATTRIB = 0,
NORMAL_ATTRIB = 2,
COLOR_ATTRIB,
COLOR2_ATTRIB,
FOG_COORD,
TEXTURE_COORD_ATTRIB0 = 8,
TEXTURE_COORD_ATTRIB1,
TEXTURE_COORD_ATTRIB2,
TEXTURE_COORD_ATTRIB3,
TEXTURE_COORD_ATTRIB4,
TEXTURE_COORD_ATTRIB5,
TEXTURE_COORD_ATTRIB6,
TEXTURE_COORD_ATTRIB7
}; */
//if we fail making our shader leave
if( !testShader.CreateShader( "SimpleShader.vp", "SimpleShader.fp", 3,
VERTEX_ATTRIB, "vVertexPos",
NORMAL_ATTRIB, "vNormal",
TEXTURE_COORD_ATTRIB0, "vTexCoord" ) )
return false;
if( !testScreenShader.CreateShader( "ScreenShader.vp", "ScreenShader.fp", 3,
VERTEX_ATTRIB, "vVertexPos",
NORMAL_ATTRIB, "vNormal",
TEXTURE_COORD_ATTRIB0, "vTexCoord" ) )
return false;
SHADER PROGRAM FUNCTIONS
bool CShaderProgram::CreateShader( const char* szVertexShaderName,
const char* szFragmentShaderName, ... )
{
//here are our handles for the openGL shaders
int iGLVertexShaderHandle = -1, iGLFragmentShaderHandle = -1;
//get our shader data
char *vData = 0, *fData = 0;
int vLength = 0, fLength = 0;
LoadShaderFile( szVertexShaderName, &vData, &vLength );
LoadShaderFile( szFragmentShaderName, &fData, &fLength );
//data
if( !vData )
return false;
//data
if( !fData )
{
delete[] vData;
return false;
}
//create both our shader objects
iGLVertexShaderHandle = glCreateShader( GL_VERTEX_SHADER );
iGLFragmentShaderHandle = glCreateShader( GL_FRAGMENT_SHADER );
//well we got this far so we have dynamic data to clean up
//load vertex shader
glShaderSource( iGLVertexShaderHandle, 1, (const char**)(&vData), &vLength );
//load fragment shader
glShaderSource( iGLFragmentShaderHandle, 1, (const char**)(&fData), &fLength );
//we are done with our data delete it
delete[] vData;
delete[] fData;
//compile them both
glCompileShader( iGLVertexShaderHandle );
//get shader status
int iShaderOk;
glGetShaderiv( iGLVertexShaderHandle, GL_COMPILE_STATUS, &iShaderOk );
if( iShaderOk == GL_FALSE )
{
char* buffer;
//get what happend with our shader
glGetShaderiv( iGLVertexShaderHandle, GL_INFO_LOG_LENGTH, &iShaderOk );
buffer = new char[iShaderOk];
glGetShaderInfoLog( iGLVertexShaderHandle, iShaderOk, NULL, buffer );
//sprintf_s( buffer, "Failure Our Object For %s was not created", szFileName );
MessageBoxA( NULL, buffer, szVertexShaderName, MB_OK );
//delete our dynamic data
free( buffer );
glDeleteShader(iGLVertexShaderHandle);
return false;
}
glCompileShader( iGLFragmentShaderHandle );
//get shader status
glGetShaderiv( iGLFragmentShaderHandle, GL_COMPILE_STATUS, &iShaderOk );
if( iShaderOk == GL_FALSE )
{
char* buffer;
//get what happend with our shader
glGetShaderiv( iGLFragmentShaderHandle, GL_INFO_LOG_LENGTH, &iShaderOk );
buffer = new char[iShaderOk];
glGetShaderInfoLog( iGLFragmentShaderHandle, iShaderOk, NULL, buffer );
//sprintf_s( buffer, "Failure Our Object For %s was not created", szFileName );
MessageBoxA( NULL, buffer, szFragmentShaderName, MB_OK );
//delete our dynamic data
free( buffer );
glDeleteShader(iGLFragmentShaderHandle);
return false;
}
//lets check to see if the fragment shader compiled
int iCompiled = 0;
glGetShaderiv( iGLVertexShaderHandle, GL_COMPILE_STATUS, &iCompiled );
if( !iCompiled )
{
//this shader did not compile leave
return false;
}
//lets check to see if the fragment shader compiled
glGetShaderiv( iGLFragmentShaderHandle, GL_COMPILE_STATUS, &iCompiled );
if( !iCompiled )
{
char* buffer;
//get what happend with our shader
glGetShaderiv( iGLFragmentShaderHandle, GL_INFO_LOG_LENGTH, &iShaderOk );
buffer = new char[iShaderOk];
glGetShaderInfoLog( iGLFragmentShaderHandle, iShaderOk, NULL, buffer );
//sprintf_s( buffer, "Failure Our Object For %s was not created", szFileName );
MessageBoxA( NULL, buffer, szFragmentShaderName, MB_OK );
//delete our dynamic data
free( buffer );
glDeleteShader(iGLFragmentShaderHandle);
return false;
}
//make our new shader program
m_iShaderProgramHandle = glCreateProgram();
glAttachShader( m_iShaderProgramHandle, iGLVertexShaderHandle );
glAttachShader( m_iShaderProgramHandle, iGLFragmentShaderHandle );
glLinkProgram( m_iShaderProgramHandle );
int iLinked = 0;
glGetProgramiv( m_iShaderProgramHandle, GL_LINK_STATUS, &iLinked );
if( !iLinked )
{
//we didn't link
return false;
}
//NOW LETS CREATE ALL OUR HANDLES TO OUR PROPER LIKING
//start from this parameter
va_list parseList;
va_start( parseList, szFragmentShaderName );
//read in number of variables if any
unsigned uiNum = 0;
uiNum = va_arg( parseList, unsigned );
//for loop through our attribute pairs
int enumType = 0;
for( unsigned x = 0; x < uiNum; ++x )
{
//specify our attribute locations
enumType = va_arg( parseList, int );
char* name = va_arg( parseList, char* );
glBindAttribLocation( m_iShaderProgramHandle, enumType, name );
}
//end our list parsing
va_end( parseList );
//relink specify
//we have custom specified our attribute locations
glLinkProgram( m_iShaderProgramHandle );
//fill our handles
InitializeHandles( );
//everything went great
return true;
}
void CShaderProgram::InitializeHandles( void )
{
m_uihMVP = glGetUniformLocation( m_iShaderProgramHandle, "mMVP" );
m_uihWorld = glGetUniformLocation( m_iShaderProgramHandle, "mWorld" );
m_uihView = glGetUniformLocation( m_iShaderProgramHandle, "mView" );
m_uihProjection = glGetUniformLocation( m_iShaderProgramHandle, "mProjection" );
/////////////////////////////////////////////////////////////////////////////////
//texture handles
m_uihDiffuseMap = glGetUniformLocation( m_iShaderProgramHandle, "diffuseMap" );
if( m_uihDiffuseMap != -1 )
{
//store what texture index this handle will be in the shader
glUniform1i( m_uihDiffuseMap, RM_DIFFUSE+GL_TEXTURE0 ); (0)+
}
m_uihNormalMap = glGetUniformLocation( m_iShaderProgramHandle, "normalMap" );
if( m_uihNormalMap != -1 )
{
//store what texture index this handle will be in the shader
glUniform1i( m_uihNormalMap, RM_NORMAL+GL_TEXTURE0 ); (1)+
}
}
void CShaderProgram::SetDiffuseMap( const unsigned& uihDiffuseMap )
{ (0)+
glActiveTexture( RM_DIFFUSE+GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, uihDiffuseMap );
}
void CShaderProgram::SetNormalMap( const unsigned& uihNormalMap )
{ (1)+
glActiveTexture( RM_NORMAL+GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, uihNormalMap );
}
//MY 2 TEST SHADERS also my math order is correct it pertains to my matrix ordering in my math library once again i've tested the basic rendering. rendering to the screen works fine ----------------------------------------SIMPLE SHADER-------------------------------------
//vertex shader looks like this
#version 330
in vec3 vVertexPos;
in vec3 vNormal;
in vec2 vTexCoord;
uniform mat4 mWorld; // Model Matrix
uniform mat4 mView; // Camera View Matrix
uniform mat4 mProjection;// Camera Projection Matrix
out vec2 vTexCoordVary; // Texture coord to the fragment program
out vec3 vNormalColor;
void main( void )
{
//pass the texture coordinate
vTexCoordVary = vTexCoord;
vNormalColor = vNormal;
//calculate our model view projection matrix
mat4 mMVP = (( mWorld * mView ) * mProjection );
//result our position
gl_Position = vec4( vVertexPos, 1 ) * mMVP;
}
//fragment shader looks like this
#version 330
in vec2 vTexCoordVary;
in vec3 vNormalColor;
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
out vec4 fragColor[2];
void main( void )
{
//CORRECT
fragColor[0] = texture( normalMap, vTexCoordVary );
fragColor[1] = vec4( vNormalColor, 1.0 );
};
----------------------------------------SCREEN SHADER-------------------------------------
//vertext shader looks like this
#version 330
in vec3 vVertexPos; // This is the position of the vertex coming in
in vec2 vTexCoord; // This is the texture coordinate....
out vec2 vTexCoordVary; // Texture coord to the fragment program
void main( void )
{
vTexCoordVary = vTexCoord;
//set our position
gl_Position = vec4( vVertexPos.xyz, 1.0f );
}
//fragment shader looks like this
#version 330
in vec2 vTexCoordVary; // Incoming "varying" texture coordinate
uniform sampler2D diffuseMap;//the tile detail texture
uniform sampler2D normalMap; //the normal map from earlier
out vec4 vTheColorOfThePixel;
void main( void )
{
//CORRECT
vTheColorOfThePixel = texture( normalMap, vTexCoordVary );
};
.Class RenderTarget Main Functions
//here is my render targets create function
bool CRenderTarget::Create( const unsigned uiNumTextures,
unsigned uiWidth,
unsigned uiHeight,
int iInternalFormat,
bool bDepthWanted )
{
if( uiNumTextures <= 0 )
return false;
//generate our variables
glGenFramebuffers(1, &m_uifboHandle);
// Initialize FBO
glBindFramebuffer(GL_FRAMEBUFFER, m_uifboHandle);
m_uiNumTextures = uiNumTextures;
if( bDepthWanted )
m_uiNumTextures += 1;
m_uiTextureHandle = new unsigned int[uiNumTextures];
glGenTextures( uiNumTextures, m_uiTextureHandle );
for( unsigned x = 0; x < uiNumTextures-1; ++x )
{
glBindTexture( GL_TEXTURE_2D, m_uiTextureHandle[x]);
// Reserve space for our 2D render target
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, iInternalFormat, uiWidth, uiHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, GL_TEXTURE_2D, m_uiTextureHandle[x], 0);
}
//if we need one for depth testing
if( bDepthWanted )
{
glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_uiTextureHandle[uiNumTextures-1], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_uiTextureHandle[uiNumTextures-1], 0);*/
// Must attach texture to framebuffer. Has Stencil and depth
glBindRenderbuffer(GL_RENDERBUFFER, m_uiTextureHandle[uiNumTextures-1]);
glRenderbufferStorage(GL_RENDERBUFFER, /*GL_DEPTH_STENCIL*/GL_DEPTH24_STENCIL8, TEXTURE_WIDTH, TEXTURE_HEIGHT );
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiTextureHandle[uiNumTextures-1]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_uiTextureHandle[uiNumTextures-1]);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//everything went fine
return true;
}
void CRenderTarget::Bind( const int& iTargetAttachmentLoc,
const unsigned& uiWhichTexture,
const bool bBindFrameBuffer )
{
if( bBindFrameBuffer )
glBindFramebuffer( GL_FRAMEBUFFER, m_uifboHandle );
if( uiWhichTexture < m_uiNumTextures )
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + iTargetAttachmentLoc, m_uiTextureHandle[uiWhichTexture], 0);
}
void CRenderTarget::UnBind( void )
{
//default our binding
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
}
//this is all in a test project so here's my straight forward rendering function for testing
this render function does basic rendering steps keep in mind i have already tested my textures i have already tested my box thats being rendered all basic rendering works fine its just when i try to render to a texture then display it in a render surface that it does not work. Also I have tested my render surface it is bound exactly to the screen coordinate space
void TestRenderSteps( void )
{
//Clear the color and the depth
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//bind the shader program
glUseProgram( testShader.m_iShaderProgramHandle );
//1) grab the vertex buffer related to our rendering
glBindBuffer( GL_ARRAY_BUFFER, CVertexBufferManager::GetInstance()->GetPositionNormalTexBuffer().GetBufferHandle() );
//2) how our stream will be split here ( 4 bytes position, ..ext )
CVertexBufferManager::GetInstance()->GetPositionNormalTexBuffer().MapVertexStride();
//3) set the index buffer if needed
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, CIndexBuffer::GetInstance()->GetBufferHandle() );
//send the needed information into the shader
testShader.SetWorldMatrix( boxPosition );
testShader.SetViewMatrix( Static_Camera.GetView( ) );
testShader.SetProjectionMatrix( Static_Camera.GetProjection( ) );
testShader.SetDiffuseMap( iTextureID );
testShader.SetNormalMap( iTextureID2 );
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, buffers);
//bind to our render target
//RM_DIFFUSE, RM_NORMAL are enums (0 && 1)
renderTarget.Bind( RM_DIFFUSE, 1, true );
renderTarget.Bind( RM_NORMAL, 1, false); //false because buffer is already bound
//i clear here just to clear the texture to make it a default value of white
//by doing this i can see if what im rendering to my screen is just drawing to the screen
//or if its my render target defaulted
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//i have this box object which i draw
testBox.Draw();
//the draw call looks like this
//my normal rendering works just fine so i know this draw is fine
// glDrawElementsBaseVertex( m_sides[x].GetPrimitiveType(),
// m_sides[x].GetPrimitiveCount() * 3,
// GL_UNSIGNED_INT,
// BUFFER_OFFSET(sizeof(unsigned int) * m_sides[x].GetStartIndex()),
// m_sides[x].GetStartVertex( ) );
//we unbind the target back to default
renderTarget.UnBind();
//i stop mapping my vertex format
CVertexBufferManager::GetInstance()->GetPositionNormalTexBuffer().UnMapVertexStride();
//i go back to default in using no shader program
glUseProgram( 0 );
//now that everything is drawn to the textures
//lets draw our screen surface and pass it our 2 filled out textures
//NOW RENDER THE TEXTURES WE COLLECTED TO THE SCREEN QUAD
//bind the shader program
glUseProgram( testScreenShader.m_iShaderProgramHandle );
//1) grab the vertex buffer related to our rendering
glBindBuffer( GL_ARRAY_BUFFER, CVertexBufferManager::GetInstance()->GetPositionTexBuffer().GetBufferHandle() );
//2) how our stream will be split here
CVertexBufferManager::GetInstance()->GetPositionTexBuffer().MapVertexStride();
//3) set the index buffer if needed
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, CIndexBuffer::GetInstance()->GetBufferHandle() );
//pass our 2 filled out textures (in the shader im just using the diffuse
//i wanted to see if i was rendering anything before i started getting into other techniques
testScreenShader.SetDiffuseMap( renderTarget.GetTextureHandle(0) ); //SetDiffuseMap definitions in shader program class
testScreenShader.SetNormalMap( renderTarget.GetTextureHandle(1) ); //SetNormalMap definitions in shader program class
//DO the draw call drawing our screen rectangle
glDrawElementsBaseVertex( m_ScreenRect.GetPrimitiveType(),
m_ScreenRect.GetPrimitiveCount() * 3,
GL_UNSIGNED_INT,
BUFFER_OFFSET(sizeof(unsigned int) * m_ScreenRect.GetStartIndex()),
m_ScreenRect.GetStartVertex( ) );*/
//unbind our vertex mapping
CVertexBufferManager::GetInstance()->GetPositionTexBuffer().UnMapVertexStride();
//default to no shader program
glUseProgram( 0 );
}
Last words:
1) I can render my box just fine
2) i can render my screen rect just fine
3) I cannot render my box into a texture then display it into my screen rect
4) This entire project is just a test project I made to test different rendering practices. So excuse any "ugly-ish" unclean code. This was made just on a fly run through when I was trying new test cases.
© Game Development or respective owner