I'm fairly experienced with opengl and GLSL. For my engine I wanted to implement deferred lighting, knowing it was not going to be a trivial task. After a few hours I was able to get things mostly working. Here is a screenshot of all the buffers I've rendered:
The upper left is the normals, the upper right is the albedo, the lower left is the position and the lower right is the final render. (There is only one light being rendered right now.)
I use various shaders to render all the things to a frame buffer. I had previously used a forward rendering lighting shader. To hopefully provide the same results, I used the same data from that vertex shader to render the different buffers. The light source moves and changes based on the position of my camera, unlike my forward renderer. Here is the code for the vertex shaders (the fragment ones just render the pixels they got from the vertex one)
Position shader:
varying vec4 pos;
void main(void)
{
gl_Position =gl_ModelViewProjectionMatrix*gl_Vertex;
pos = gl_ModelViewMatrix*gl_Vertex;
}
Normal shader
varying vec3 normal;
void main(void)
{
gl_Position =gl_ModelViewProjectionMatrix*gl_Vertex;
normal = normalize(gl_NormalMatrix*gl_Normal);
}
For the albedo I just use opengl's regular shader and just bind textures.
Here is the final light shader which is being rendered as a quad over the screen:
uniform sampler2D positionMap;
uniform sampler2D normalMap;
uniform sampler2D albedoMap;
varying vec2 texcoord;
uniform mat4 matrix;
void main()
{
vec3 position = vec3(texture2D(positionMap,texcoord));
vec3 normal = vec3(texture2D(normalMap,texcoord));
vec3 L = normalize(gl_LightSource[0].position.xyz - position);
float l = length(L)/5.0;
float att = 1.0/(l*l+l);
//render sun light
vec4 diffuselight = max(dot(normal,L), 0.0)*vec4(att,att,att,att);
diffuselight = clamp(diffuselight, 0.0, 1.0)*2.0;
vec4 amb = vec4(.2,.2,.2,0);
vec4 texture = texture2D(albedoMap,texcoord);
gl_FragColor = ((diffuselight)+amb)*texture;
}
This has a lot of functions that are referenced elsewhere, but I think you can get the general basis from the pictures and the code. This is the main rendering function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//render skybox
glLoadIdentity();
renderSkybox();
//skybox.renderObject();
glLoadIdentity();
renderViewModel();
renderCamera();
glMatrixMode(GL_MODELVIEW);
GLfloat position[] = {-Lighting.x,-Lighting.y,-Lighting.z,1};
glLightfv(GL_LIGHT0, GL_POSITION, position);
glDisable(GL_LIGHTING);
glm::mat4 modelView,projection,final;
glGetFloatv(GL_MODELVIEW_MATRIX, &modelView[0][0]);
glGetFloatv(GL_PROJECTION_MATRIX, &projection[0][0]);
final=modelView*projection;
Lighting.setupDepthImage();
glLoadIdentity();
for (int i = 0; i < objects.size(); i++)
{
objects[i].renderObjectForDepth();
}
Lighting.finishDepthImage();
//render the 3 buffers
//normal buffer
glBindFramebuffer(GL_FRAMEBUFFER, Lighting.Normal.frameBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int i = 0; i < objects.size(); i++)
{
objects[i].renderObjectWithProgram(Lighting.normalShader);
}
//albedo
glBindFramebuffer(GL_FRAMEBUFFER, Lighting.Albedo.frameBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int i = 0; i < objects.size(); i++)
{
objects[i].renderObjectWithProgram(0);
}
//position
glBindFramebuffer(GL_FRAMEBUFFER, Lighting.Position.frameBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int i = 0; i < objects.size(); i++)
{
objects[i].renderObjectWithProgram(Lighting.positionShader);
}
//go back to rendering directly to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
renderCamera();
glTranslatef(-test.position.x, test.position.y, -test.position.z);
test.updateParticle(1);
//render the buffers for debugging
renderViewModel();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1280, 800, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//render the full screen quad for the sun
glUseProgram(Lighting.sunShader);
glUniform1i(glGetUniformLocation(Lighting.sunShader,"normalMap"),0);
glUniform1i(glGetUniformLocation(Lighting.sunShader,"albedoMap"),1);
glUniform1i(glGetUniformLocation(Lighting.sunShader,"positionMap"),2);
glUniformMatrix4fv(glGetUniformLocation(Lighting.sunShader, "matrix"), 1, GL_FALSE, &final[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Lighting.Normal.texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Lighting.Albedo.texture);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, Lighting.Position.texture);
glBindFramebuffer(GL_FRAMEBUFFER, Lighting.debugFinal.frameBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(0, 0);
glTexCoord2f(1, 1);
glVertex2f(1280, 0);
glTexCoord2f(1, 0);
glVertex2f(1280, 800);
glTexCoord2f(0, 0);
glVertex2f(0, 800);
glEnd();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
//normals
glBindTexture(GL_TEXTURE_2D,Lighting.Normal.texture);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(0, 0);
glTexCoord2f(1, 1);
glVertex2f(640, 0);
glTexCoord2f(1, 0);
glVertex2f(640, 400);
glTexCoord2f(0, 0);
glVertex2f(0, 400);
glEnd();
//albedo
glBindTexture(GL_TEXTURE_2D,Lighting.Albedo.texture);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(640, 0);
glTexCoord2f(1, 1);
glVertex2f(1280, 0);
glTexCoord2f(1, 0);
glVertex2f(1280, 400);
glTexCoord2f(0, 0);
glVertex2f(640, 400);
glEnd();
//position
glBindTexture(GL_TEXTURE_2D,Lighting.Position.texture);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(0, 400);
glTexCoord2f(1, 1);
glVertex2f(640, 400);
glTexCoord2f(1, 0);
glVertex2f(640, 800);
glTexCoord2f(0, 0);
glVertex2f(0, 800);
glEnd();
//final image
glBindTexture(GL_TEXTURE_2D,Lighting.debugFinal.texture);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(640, 400);
glTexCoord2f(1, 1);
glVertex2f(1280, 400);
glTexCoord2f(1, 0);
glVertex2f(1280, 800);
glTexCoord2f(0, 0);
glVertex2f(640, 800);
glEnd();
View3D();
SDL_GL_SwapWindow(window);
glLoadIdentity();
There are a few unrelated things in here, just ignore them. As you saw, I get the light's position using GLSL's default method. I think that because I am in an orthographic view, something is screwing with the light's position. Could this be the problem, or is there something else, perhaps in the calculation of the normals,etc?
People will probably not find this useful but I have solved my problem. I was using the regular opengl lights for lighting in the shader. When I set the position I made the w value 1, which would make it a directional light, not a point light, and therefore gave the light moving behavior.
As a side not I changed the position to reconstruct from the depth buffer as well as a few other things to improve the G-buffer.
Related
I am trying to create a quick render to texture example using GLdc, a OpenGL implementation for the Sega Dreamcast. I have verified that both my Texture and Framebuffer Object are complete, yet the texture resulting from the framebuffer only has 1 white dot in it.
First, I generate an empty texture and prepare it to be written to.
func genTextures(){
glGenTextures(1, &renderedTexture[0]);
glBindTexture(GL_TEXTURE_2D, renderedTexture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smaller than texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
Next, I generate an FBO and bind the new texture we just created to it.
func genFBO() {
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, renderedTexture[0], 0);
}
At this point the FBO and the Texture should both be considered complete. The main loop is structured something like this:
int main(int argc, char **argv)
{
glKosInit();
InitGL(640, 480);
ReSizeGLScene(640, 480);
genTextures();
genFBO();
while(1) {
if(check_start())
break;
// I checked here for FBO and Texture completeness, both return True.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // bind to the FBO
DrawGLScene(); // Draw our cube to the FBO
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // back to default
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
ReSizeGLScene(640,480);
DrawGLUI(); //Draw the quad with the framebuffers texture
}
return 0;
}
Here are the two functions that draw geometry:
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(0.0f,0.0f,-5.0f); // move 5 units into the screen.
glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis
glRotatef(yrot,0.0f,1.0f,0.0f); // Rotate On The Y Axis
glRotatef(zrot,0.0f,0.0f,1.0f); // Rotate On The Z Axis
glBindTexture(GL_TEXTURE_2D, texture[0]); // choose the texture to use.
glBegin(GL_QUADS); // begin drawing a cube
// Draw my textured cube, works fine.
glEnd(); // done with the polygon.
xrot+=1.5f; // X Axis Rotation
yrot+=1.5f; // Y Axis Rotation
zrot+=1.5f; // Z Axis Rotation
glKosSwapBuffers();
}
void DrawGLUI(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, renderedTexture[0]);
glBegin(GL_QUADS);
//glColor3f(1.0f, 0.0f, 0.0);
glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
glTexCoord2f(0.0, 1.0); glVertex2f(0.0, 1.0);
glEnd();
glEnable(GL_DEPTH_TEST);
ReSizeGLScene(640,480);
glFlush();
}
The result is
Where I would like to have the cube rendered to a texture then that texture applied to the quad in the upper right corner...
The size of the viewport must be adjusted to the size of the framebuffer with glViewport when the framebuffer is switched:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glViewport(0, 0, 128, 128);
// [...]
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glViewport(0, 0, 640, 480);
// [...]
Hey I can't get my texture to show up and I have no idea what's wrong. Tutorials haven't helped. Here's my code:
Player p();
//The glutDisplayFunc();
void display() {
glPushMatrix();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
//Load png with SOIL
playerTex = loadTex("Data/Sprites/player.png");
p.draw();
glFlush();
glPopMatrix(); }
//Load texture
GLuint loadTex(const char* c) {
GLuint temp = SOIL_load_OGL_texture(
c,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
);
if (0 == temp)
{
printf("SOIL loading error: '%s'\n", SOIL_last_result());
//return 0;
}
glBindTexture(GL_TEXTURE_2D, temp);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return temp; }
//Player object's draw function
void player::draw() {
glEnable(GL_TEXTURE_2D);
glBegin(GL_TRIANGLES);
glColor3f(0, 0, 0);
glTexCoord2f(0.0, 0.0);
glVertex2f(x, y);
glTexCoord2f(0.0, 1.0);
glVertex2f(x + spriteW, y);
glTexCoord2f(1.0, 1.0);
glVertex2f(x + spriteW, y + spriteL);
glEnd();}
spriteX = 0, spriteY = 0, spriteW = 400, spriteL = 400, x = 0, y = 0
This is the output I get:
Output Window
As you can see the BLACK triangle shows up fine, but with no texture
Texture coordinates should be in the range 0..1, they are not texel coordinates. Divide by the texture width and height to convert from texel coordinates to texture coordinates.
You also have the color set to black with the following line:
glColor3f(0, 0, 0);
Don't do that. Use white (or change TEXTURE_ENV_MODE, but that doesn't seem necessary).
glColor3f(1, 1, 1);
The color is multiplied by the texture color. You might as well move it outside the glBegin() glEnd() block:
glColor(1, 1, 1);
glBegin(...);
...
glEnd();
I'm currently porting a game of which the code is very obfuscated due to porting from C to Java.
My problem is that some users report a black screen and no other problems (sound is working fine e.g.), with no errors showing a problem. On my pc it runs fine, and it makes for a hell of debugging.
I was wondering if anyone can post a (list of) reason(s) this might be occurring. I've read somewhere one of the issues could be using a 32 bits Java on a 64 bits system.
My code below, also opensourced at: https://code.google.com/p/jake2t/
private void renderSideBySide() {
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sbsFboId);
// Render side by side
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glViewport(0,0,width,height);
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDisable(GL_CULL_FACE);
int shaderId = sbsShader.getId();
glDisable(GL_TEXTURE_2D);
ARBShaderObjects.glUseProgramObjectARB(shaderId);
if (postFboTextureLocation[0] < 0) {
postFboTextureLocation[0] = ARBShaderObjects.glGetUniformLocationARB(shaderId, "leftTexture");
}
if (postFboTextureLocation[1] < 0) {
postFboTextureLocation[1] = ARBShaderObjects.glGetUniformLocationARB(shaderId, "rightTexture");
}
if (postFboDepthTextureLocation[0] < 0) {
postFboDepthTextureLocation[0] = ARBShaderObjects.glGetUniformLocationARB(shaderId, "leftDepthTexture");
}
if (postFboDepthTextureLocation[1] < 0) {
postFboDepthTextureLocation[1] = ARBShaderObjects.glGetUniformLocationARB(shaderId, "rightDepthTexture");
}
// Load the images with the colors and the depth values
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, postFboTextureId[0]);
ARBShaderObjects.glUniform1iARB(postFboTextureLocation[0], 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, postFboTextureId[1]);
ARBShaderObjects.glUniform1iARB(postFboTextureLocation[1], 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, postFboDepthTexture[0]);
ARBShaderObjects.glUniform1iARB(postFboDepthTextureLocation[0], 2);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, postFboDepthTexture[1]);
ARBShaderObjects.glUniform1iARB(postFboDepthTextureLocation[1], 3);
glBegin (GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2i (0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex2i (width, 0);
glTexCoord2f(1.0f, 1.0f);
glVertex2i (width, height);
glTexCoord2f(0.0f, 1.0f);
glVertex2i (0, height);
glEnd();
ARBShaderObjects.glUseProgramObjectARB(0);
// Rendering with warping
glPopMatrix();
glPopAttrib();
unbindFBO();
}
public void drawPostFBOs() {
renderSideBySide();
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glViewport(0,0,width,height);
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
int shaderId = riftShader.getId();
ARBShaderObjects.glUseProgramObjectARB(shaderId);
if (sbsFboTextureLocation < 0) {
sbsFboTextureLocation = ARBShaderObjects.glGetUniformLocationARB(shaderId, "tex");
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sbsFboTextureId);
ARBShaderObjects.glUniform1iARB(sbsFboTextureLocation, 0);
glBegin (GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2i (0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex2i (width, 0);
glTexCoord2f(1.0f, 1.0f);
glVertex2i (width, height);
glTexCoord2f(0.0f, 1.0f);
glVertex2i (0, height);
glEnd();
ARBShaderObjects.glUseProgramObjectARB(0);
glPopMatrix();
glPopAttrib();
}
The common problems that OpenGL 3+ programmer doesn't consider when coding are:
OpenGL Extensions
use of ARB and EXT extension.
use of correct OGL extension.
use multiple implementation of different OGL extensions. Here is an example using C++:
#ifndef _MESA_INVERT_
/*** ... some codes here ... ***/
#else
/*** ... alt some codes here ... ***/
#endif
Check if the video card support the following extension using:
glxinfo - Linux and MacOS X based system.
glview - Windows based system.
I've begun switching my rendering code to support shaders, and that all works fine when rendering to the back buffer. So now I'm working towards rendering to FBOs, but all I get are white textures for both the color and normals.
Here is my FBO creation code:
void RenderTarget_GL::CreateFBO (void)
{
// if the machine supports the GL FBO extension
if (s_supportfbo)
{
// Create FBO
glGenFramebuffersEXT(1, &m_fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
// Create default texture buffer
char *buffer = new char [static_cast<int>(g_window->GetWidth() * m_screenWidth) * static_cast<int>(g_window->GetHeight() * m_screenHeight) * 4];
std::memset(buffer, 0, static_cast<int>(g_window->GetWidth() * m_screenWidth) * static_cast<int>(g_window->GetHeight() * m_screenHeight) * 4);
// Create Render Texture
glGenTextures(1, &m_rendertexture);
glBindTexture(GL_TEXTURE_2D, m_rendertexture);
glTexImage2D(GL_TEXTURE_2D, 0, 4, static_cast<int>(g_window->GetWidth() * m_screenWidth), static_cast<int>(g_window->GetHeight() * m_screenHeight), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// Bind Render Texture to FBO
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_rendertexture, 0);
// Create Normal Texture if this FBO will be rendering normals
if (m_hasnormal)
{
glGenTextures(1, &m_normaltexture);
glTexImage2D(GL_TEXTURE_2D, 0, 4, static_cast<int>(g_window->GetWidth() * m_screenWidth), static_cast<int>(g_window->GetHeight() * m_screenHeight), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// Bind Normal Texture to FBO
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_normaltexture, 0);
}
// UnBind FBO and cleanup default buffer
delete [] buffer;
Clear();
}
}
And the code I use to set the current render target:
void RenderTarget_GL::Set (void)
{
if (s_supportfbo && g_glgraphics->GetShaderEnabled())
{
static const GLenum buffer1[] = {GL_COLOR_ATTACHMENT0_EXT};
static const GLenum buffer2[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
if (m_hasnormal)
glDrawBuffers(2, buffer2);
else
glDrawBuffers(1, buffer1);
}
}
And finally, my actual drawing code:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Setup the camera transformation
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
if (m_camera)
m_camera->GLMatrix();
else
m_defaultCam.GLMatrix();
// Setup Render Target
if (m_shaderenabled)
{
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0,0,g_window->GetWidth(),g_window->GetHeight());
m_initialpass->Set();
}
// Draw All Objects with their per-object shaders
// Clear render target and shader bindings
if (m_shaderenabled)
{
glPopAttrib();
RenderTarget_GL::Clear();
Shader_GL::ClearShaderBinding();
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
// Draw Scene
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_initialpass->GetColorTexture());
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();
Texture_GL::ClearTextureBinding();
glPopMatrix();
// Swap Buffers
GL_TEXTURE_MIN_FILTER is GL_NEAREST_MIPMAP_LINEAR by default. Supply mipmaps or switch to GL_LINEAR or GL_NEAREST.
The OpenGL Wiki has more.
To make my maze type game faster I decided to put my drawed ball inside a texture, because i have to draw it otherwise once for every room and I'm drawing it like a concave polygon using the stencil buffer, it takes more time than using a texture. The problem is, that I'm getting it inside a texture correctly from the back buffer when I'm rendering the third frame since the start of the game and my question is, why is it like so?
When I'm using a texture from the thirst frame, I'm having texture with solid white color, so it has nothing inside. When I'm using textures from the second frame, then I have only the black background of the desired texture and when I take the texture from the third frame, then I have desired texture. For frame count I use the static variable "done" inside the "drawTexture" function.
Copying from the first frame:
Copying from the second frame:
Copying from the third frame (desired outcome):
void DrawBall::drawTexture(float imageD) {
static int done = 0;
if (done < 3) {
drawToTexture(imageD);
done++;
}
glEnable(GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture);
glColor3f(1, 1, 1);
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0); glVertex3f (0.0, 0.0, -imageD);
glTexCoord2f (1.0, 0.0); glVertex3f (5.0, 0.0, -imageD);
glTexCoord2f (1.0, 1.0); glVertex3f (5.0, 5.0, -imageD);
glTexCoord2f (0.0, 1.0); glVertex3f (0.0, 5.0, -imageD);
glEnd ();
glDisable(GL_TEXTURE_2D);
}
void DrawBall::drawToTexture(float imageD) {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, (int*) viewport);
int textureWidth = 64;
int textureHeight = 64;
texture = genEmptyTexture(textureWidth, textureHeight);
glViewport(0, 0, textureWidth, textureHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
This function calculates the vertexes for the ball
inside a vector<vector<float>> variable "test"
*/
_calculateCircleVertexes(0.0f, 0.0f, -2.0f, 0.249f, &test, 20);
_displayBall(&test, 0.0f, 0.0f, 0.5f, -2.0f, &*smallBallColor);
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, textureWidth, textureHeight, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)viewport[2] / (GLfloat)viewport[3], 1.0f, imageD + 10.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
GLuint DrawBall::genEmptyTexture(unsigned int width, unsigned int height) {
GLuint txtIndex;
glGenTextures(1, &txtIndex);
glBindTexture(GL_TEXTURE_2D, txtIndex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
return txtIndex;
}
void DrawBall::_displayBall(vector<vector<GLfloat>> *vertexes, GLfloat x, GLfloat y
, GLfloat imageW, GLfloat imageD, color *color) {
glTranslatef(x, y, imageD);
glClearStencil(0);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NEVER, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glBegin(GL_POLYGON);
vector<vector<GLfloat>>::iterator it = vertexes->begin();
for (; it != vertexes->end(); it++) {
glVertex3f((*it)[0], (*it)[1], 0.0f);
}
glEnd();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glColor3f(color->r, color->g, color->b);
glBegin(GL_QUADS);
glVertex3f(-(imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), (imageW / 2.0f), 0.0f);
glVertex3f(-(imageW / 2.0f), (imageW / 2.0f), 0.0f);
glEnd();
glDisable(GL_STENCIL_TEST);
glTranslatef(x, y, -imageD);
}
You should not use the window framebuffer (which includes both back- and frontbuffer) for render to texture operations. It just breaks to easily (you've experienced it). Instead use a so called Framebuffer Object, with the texture as rendering target.
Well, Datenwolf, thank you for your suggestion, you are probably right but I just want to use the advanced stuff as less as possible and I found my mistakes. I didn't get the desired outcome before the second frame because I didn't have yet enabled stencil test. Before the first frame I didn't get the desired outcome because in the window creation Windows sends WM_SIZE message and I had the draw message inside it but at that time the OpenGL isn't set up properly yet.