I started with opengl texturing and everything was working well. Now I am trying to load a bmp and make white part transparent using glEnable(GL_BLEND); and glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
This is my source code:
float kSpeedForw=0.0f;
GLuint texture[1];
CCamera g_Camera;
GLfloat xrot = 0;
GLfloat yrot = 0;
GLfloat zrot = 0;
bool g_bFullScreen = true;
HWND g_hWnd;
RECT g_rRect;
HDC g_hDC;
HGLRC g_hRC;
HINSTANCE g_hInstance;
float jump = -0.1;
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f };
void Init(HWND hWnd)
{
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); // Position The Light
glEnable(GL_LIGHT1); // Enable Light One
glColor4f(1.0f, 1.0f, 1.0f, 0.5); // Full Brightness. 50% Alpha
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
g_hWnd = hWnd;
GetClientRect(g_hWnd, &g_rRect);
InitializeOpenGL(g_rRect.right, g_rRect.bottom);
g_Camera.PositionCamera(0, 1.5f, 6, 0, 1.5f, 5, 0, 1, 0);
ShowCursor(false);
}
GLuint LoadTexture(const char * filename)
{
glEnable(GL_TEXTURE_2D);
GLuint texture;
int width, height;
unsigned char * data;
FILE * file;
file = fopen(filename, "rb");
if (file == NULL) return 0;
if (filename=="Data/weed.bmp"){
width = 200;
height = 200;
}
if (filename == "Data/gun.bmp"){
width = 300;
height = 300;
}
data = (unsigned char *)malloc(width * height * 3);
fread(data, width * height * 3, 1, file);
fclose(file);
for (int i = 0; i < width * height; ++i)
{
int index = i * 3;
unsigned char B, R;
B = data[index];
R = data[index + 2];
data[index] = R;
data[index + 2] = B;
}
if (filename == "Data/weed.bmp"){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
free(data);
}
if (filename == "Data/gun.bmp"){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3,width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
return texture;
}
WPARAM MainLoop() // main function
{
MSG msg;
Init(g_hWnd);
glClearColor(0, 0, 255, 0);
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (LockFrameRate(60))
{
g_Camera.SetViewByMouse();
kSpeedForw = 0;
if (jump > -0.1)jump-=0.01;
CheckForMovement();
g_Camera.MoveCamera(kSpeedForw, jump);
RenderScene();
}
}
DeInit();
return(msg.wParam);
}
void RenderScene()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glDisable(GL_BLEND);
glEnable(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(g_Camera.m_vPosition.x, g_Camera.m_vPosition.y, g_Camera.m_vPosition.z,
g_Camera.m_vView.x, g_Camera.m_vView.y, g_Camera.m_vView.z,
g_Camera.m_vUpVector.x, g_Camera.m_vUpVector.y, g_Camera.m_vUpVector.z);
GLuint texture;
texture = LoadTexture("Data/weed.bmp");
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
float i = 0;
glColor3f(1,1,1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-10 + i / 5, 0, 10 - i / 5);
glTexCoord2f(50.0f, 0.0f);
glVertex3f(-10 + i / 5, 0, -10 + i / 5);
glTexCoord2f(50.0f, 50.0f);
glVertex3f(10 - i / 5, 0, -10 + i / 5);
glTexCoord2f(0.0f, 50.0f);
glVertex3f(10 - i / 5, 0, 10 - i / 5);
glEnd();
////////////////////////////////////////////////////////////HUD
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SMOOTH);
glEnable(GL_BLEND); // Turn Blending On
int vPort[4];
glGetIntegerv(GL_VIEWPORT, vPort);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
GLuint ruka;
ruka = LoadTexture("Data/gun.bmp");
glBindTexture(GL_TEXTURE_2D, ruka);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(450,0);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(450,450);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0,450);
glEnd();
SwapBuffers(g_hDC);
}
The code works well for loading and rendering the platform(weed.bmp) and it also loads and renders gun fine. But big part of gun.bmp is white. I was hoping to get that part transparent. I was also hoping to add more HUD features, which would also need to be partly transparent.
My gun.bmp file: https://drive.google.com/file/d/0BxxlNcAI0eh9cHZGd1ZfMTFwYmM/view?usp=sharing
If you know a solution of this problem please post it. Thanks
You load image as GL_RGB, you want GL_RGBA to have an alpha channel.
Also, you need a 32 bits Bitmap (8 bits/channel × 4 channels = 32 bits).
Essentially, I'm rendering a raw buffer of pixels onto a texture, which is wrapped onto a quad.
My GL initiation code:
void INITOGL(int xres, int yres){
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
//gluOrtho2D(0, xres, 0, yres);
}
Render loop code:
void RenderCycle(){
register MSG msg = {0};
while(1){
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glEnable(GL_TEXTURE_2D);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
//glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//GL_LINEAR
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE/*GL_DECAL*/);
glTexImage2D( GL_TEXTURE_2D, 0, 3, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer);//viewport virtual size
glClear(GL_COLOR_BUFFER_B
IT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(0, 0, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f( 800, 0, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f( 800, 600, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f( 0, 600, 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
SwapBuffers(hdc);
}
}
The resize function:
void ResizeViewport(int height, int width){
if(!height)height++;
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
//gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_PROJECTION);
glViewport(0,0,width,height);
//gluOrtho2D(0, width, 0, height);
glLoadIdentity();
}
The buffer that holds the RGB data is just set to red using a for loop, and this is the output.
Have I improperly set my viewport, not scaled something correctly, or am I just completely missing something? If you need any more information, just ask. I have given all of the opengl sided code, the rest shouldn't make a difference. In theory, it should render red to the entire screen.
I want to do volume rendering using programmable pipeline (using glsl) and no fixed pipelines. I implement it with 2 passes with 2 shader programs, exitPointProg and rayCastProg. the first pass is to get the exit points (i.e. the back face) of a cube bounding box which will be used as a texture in the next pass which doing the raycasting. the idea to do the raycasting volume rendering comes from here. I think I have done the most of the things right cause I have implemented this with fixed pipeline combined with the programmable pipeline. the things that confused me is that I achieved the result with the very first frame, and with a flash the display on the screen turn totally white (I set the glClearColor(1.0f, 1.0f, 1.0f, 1.0f). I think there maybe some wrong with the switch of the shader programs or the FBO. here is what I do in the render() function.
1st pass, render to a fbo with exitPoints texture bound to it to get the exit points of cube bounding box, using shader program exitPointProg.
2ed pass, mapped the exitPoints texture (bound to GL_TEXTURE1) into the shader program rayCastProg as a uniform sampler2D variable which will used in the shader.
here is the setupFBO and render and two subroutines:
the setupFBO() function:
void SimpleRayCasting::setupFBO()
{
GLuint textureHandles[1];
glGenTextures(1, textureHandles);
entryPoints = textureHandles[0];
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, exitPoints);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
GLuint depthRenderBuffer;
glGenRenderbuffers(1, &depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
exitPoints, 0/* level */);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
depthRenderBuffer);
checkFramebufferState(__FILE__, __LINE__);
GLenum drawbufs[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawbufs);
glBindFramebuffer(GL_FRAMEBUFFER,0);
}
the render() function:
void SimpleRayCasting::render()
{
getExitPoints();
GLUtils::checkForOpenGLError(__FILE__,__LINE__);
rayCasting();
GLUtils::checkForOpenGLError(__FILE__,__LINE__);
}
the getExitPoints() function:
void SimpleRayCasting::getExitPoints()
{
// render to the texture
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
// checkFramebufferState(__FILE__, __LINE__);
glClearColor(0.2f, 0.2f, 0.2f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
exitPointsProg.use();
// note that the model will recalculated.
model = mat4(1.0f);
model *= glm::rotate(angle , vec3(0.0f,1.0f,0.0f));
model *= glm::rotate(90.0f, vec3(1.0f, 0.0f, 0.0f));
model *= glm::translate(vec3(-0.5f, -0.5f, -0.5f));
view = glm::lookAt(vec3(0.0f,0.0f,2.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = mat4(1.0f);
projection = glm::perspective(60.0f, (float)width/(float)height,0.01f, 400.0f);
setMatrices(exitPointsProg);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
drawBoundBox();
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
the rayCasting function:
void SimpleRayCasting::rayCasting()
{
// Directly render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rayCastProg.use();
model = mat4(1.0f);
model *= glm::rotate(angle, vec3(0.0f,1.0f,0.0f));
model *= glm::rotate(90.0f, vec3(1.0f, 0.0f, 0.0f));
model *= glm::translate(vec3(-0.5f, -0.5f, -0.5f));
view = glm::lookAt(vec3(0.0f,0.0f,2.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = mat4(1.0f);
projection = glm::perspective(60.0f, (float)width/(float)height,0.01f, 400.0f);
setMatrices(rayCastProg);
rayCastProg.setUniform("StepSize", stepSize);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, exitPoints);
rayCastProg.setUniform("ExitPoints", 1);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_3D, volume_to);
rayCastProg.setUniform("VolumeTex", 4);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_1D, transferFunc_to);
rayCastProg.setUniform("TransferFunc", 5);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
drawBoundBox();
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
I am using a class inherited from QGLWidget in Qt. As I have mentioned early, I got the right result with just the 1st frame and quickly it flash away and turn totally white. I don't know what's wrong with this, is there something wrong with the switch of the shader program or the FBO thing? I have been working on this a long time and can't figure it out, any help will be appreciated!
edit to ask
is there any demo or tutorial demonstrate how to use multiple glsl shader programs with FBO?
I must be missing something obvious in using FBO :
I call TMyForm::Init() once at the start of my application :
class TMyForm
{ ...
private:
Gluint mTextureId, mFboId;
int mWidth, mHeight;
}
void TMyForm::Init()
{
mWidth = 1920;
mHeight = 1080;
...
// create a texture object
glEnable(GL_TEXTURE_2D);
glClearColor ( 0.0, 0.0, 0.0, 1.0 );
glGenTextures(1, &mTextureId);
glBindTexture(GL_TEXTURE_2D, mTextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a framebuffer object
glGenFramebuffersEXT(1, &mFboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFboId);
// attach the texture to FBO color attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mTextureId, 0);
// switch back to window-system-provided framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
And in the Draw() function I send the buffer to a card (the rendered scene is ok) and to a preview window (all black or all white depending if I switch back to default window context or the fbo context) :
void TMyForm::Draw()
{
// set rendering destination to FBO
glEnable(GL_TEXTURE_2D);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFboId);
//---
glViewport(-1920, -1080, 1920 * 2, 1080 * 2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(double(-iWidth)*viewport_ratio, double(iWidth)*viewport_ratio, double(-iHeight), double(iHeight), 1000.0, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Render();
glFlush();
//--- 1 : send to card
delete[] mBufferPlayout;
mBufferPlayout = NULL;
try
{
mBufferPlayout = new GLubyte [mWidth * mHeight * 4];
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0,0, mWidth, mHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, mBufferPlayout);
DisplayFrame(mBufferPlayout);
}
catch (TSCDbException &e) { ShowMessage(GetLastError()); }
//--- 2 : Texturing to the preview window :
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, mTextureId);
//glGenerateMipmapEXT(GL_TEXTURE_2D);
int iWidthPreview = mWidth / 2; // ie 960
int iHeightPreview = mHeight / 2; // ie 540
glViewport(-iWidthPreview, -iHeightPreview, iWidthPreview * 2, iHeightPreview * 2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(double(-iWidthPreview), double(iWidthPreview), double(-iHeightPreview), double(iHeightPreview), 1000.0, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -50000.0);
mxIncrust0 = 0.0; myIncrust0 = 0.0;
mxIncrust1 = iWidthPreview; myIncrust1 = iHeightPreview;
glBegin(GL_QUADS);
glColor4ub(255,255,255,255);
glTexCoord2d(0.0, 0.0); glVertex2d(mxIncrust0, myIncrust0);
glTexCoord2d(0.0, 1.0); glVertex2d(mxIncrust0, myIncrust1);
glTexCoord2d(1.0,1.0); glVertex2d(mxIncrust1, myIncrust1);
glTexCoord2d(1.0,0.0); glVertex2d(mxIncrust1, myIncrust0);
glEnd();
glDisable(GL_TEXTURE_2D);
glFlush();
//---
SwapBuffers(ghDC);
}
So my problem is the "part 2" which does not do what I wish : texturing the fbo content to the current window.
I tried changing the "glTexCoord2d" with no success.
I created 4 textures and attach them to FBO, named fbo_texture0 - fbo_texture3. All of them are successfully created, as given by the following screenshot:
image 1
Now, i wanted to create the 5th texture which is obtained from the previous textures (fbo_texture0 - fbo_texture3) using GLSL. For now, i just want to copy the first texture into the fifth texture. Unfortunately, here is what i got:
image 2
The question is:
How can i access these fbo textures in GLSL?
How can i create the 5th texture? (or copy from the first texture to the fifth texture?)
Here's the complete code of the program (in case needed):
#include <windows.h>
#include <GL/glew.h> // Include the GLEW header file
#include <GL/glut.h> // Include the GLUT header file
#include <iostream> // Allow us to print to the console
using namespace std;
bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (0-255)
unsigned int fbo; // The frame buffer object
unsigned int fbo_depth; // The depth buffer for the frame buffer object
unsigned int fbo_texture0; // The texture object to write our frame buffer object to
unsigned int fbo_texture1;
unsigned int fbo_texture2;
unsigned int fbo_texture3;
unsigned int fbo_texture4;
GLhandleARB shaderProgram;
GLhandleARB vertexShader;
GLhandleARB fragmentShader;
int window_width = 500; // The width of our window
int window_height = 500; // The height of our window
void initFrameBufferDepthBuffer(void) {
glGenRenderbuffers(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth
glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth); // Bind the fbo_depth render buffer
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window
glBindRenderbuffer(GL_RENDERBUFFER, 0); // Unbind the render buffer
}
void initFrameBufferTextures(void) {
glGenTextures(1, &fbo_texture0); // Generate one ture
glBindTexture(GL_TEXTURE_2D, fbo_texture0); // Bind the ture fbo_texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard ture with the width and height of our window
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &fbo_texture1); // Generate one ture
glBindTexture(GL_TEXTURE_2D, fbo_texture1); // Bind the ture fbo_texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard ture with the width and height of our window
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &fbo_texture2); // Generate one ture
glBindTexture(GL_TEXTURE_2D, fbo_texture2); // Bind the ture fbo_texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard ture with the width and height of our window
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &fbo_texture3); // Generate one ture
glBindTexture(GL_TEXTURE_2D, fbo_texture3); // Bind the ture fbo_texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard ture with the width and height of our window
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &fbo_texture4); // Generate one ture
glBindTexture(GL_TEXTURE_2D, fbo_texture4); // Bind the ture fbo_texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard ture with the width and height of our window
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
void printInfoLog(GLhandleARB obj)
{
int infologLength = 0;
int charsWritten = 0;
char* infoLog;
glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
if (infologLength > 0)
{
infoLog = (char*)malloc(infologLength);
glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void initFrameBuffer(void) {
initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer
initFrameBufferTextures(); // Initialize our frame buffer ture
glGenFramebuffers(1, &fbo); // Generate one frame buffer and store the ID in fbo
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // Bind our frame buffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture0, 0);// Attach the ture fbo_texturen to the color buffer in our frame buffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fbo_texture1, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, fbo_texture2, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, fbo_texture3, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, fbo_texture4, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); // Check that status of our generated frame buffer
if (status != GL_FRAMEBUFFER_COMPLETE) // If the frame buffer does not report back as complete
{
cout << "Couldn't create frame buffer" << endl; // Output an error to the console
exit(0); // Exit the application
}
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer
}
void init(void) {
//glEnable(GL_TEXTURE_2D); // Enable turing so we can bind our frame buffer ture
glEnable(GL_DEPTH_TEST); // Enable depth testing
initFrameBuffer(); // Create our frame buffer object
}
void keyOperations (void) {
if (keyStates['a']) { // If the a key has been pressed
// Perform 'a' key operations
}
}
void renderTextures(void) {
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set the clear colour
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear the depth and colour buffers
glLoadIdentity();// Reset the modelview matrix
glTranslatef(0.0f, 0.0f, -5.0f);
//Add ambient light
GLfloat ambientColor[] = {0.2f, 0.2f, 0.2f, 1.0f}; //Color(0.2, 0.2, 0.2)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
//Add positioned light
GLfloat lightColor0[] = {0.5f, 0.5f, 0.5f, 1.0f}; //Color (0.5, 0.5, 0.5)
GLfloat lightPos0[] = {4.0f, 0.0f, 8.0f, 1.0f}; //Positioned at (4, 0, 8)
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
//Add directed light
GLfloat lightColor1[] = {0.5f, 0.2f, 0.2f, 1.0f}; //Color (0.5, 0.2, 0.2)
//Coming from the direction (-1, 0.5, 0.5)
GLfloat lightPos1[] = {-1.0f, 0.5f, 0.5f, 0.0f};
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_DEPTH_TEST);
glutSolidTeapot(2.0);
glColor3f(0.1,0.2,0.7);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glClearColor(0.5f, 0.5f, 0.0f, 1.0f); // Set the clear colour
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear the depth and colour buffers
glLoadIdentity();// Reset the modelview matrix
glTranslatef(0.0f, 0.0f, -5.0f);
glutSolidTorus(0.80, 1.6, 50, 100);
glColorMaterial ( GL_FRONT_AND_BACK, GL_EMISSION ) ;
glEnable ( GL_COLOR_MATERIAL ) ;
glDrawBuffer(GL_COLOR_ATTACHMENT2);
glClearColor(0.5f, 0.0f, 0.0f, 1.0f); // Set the clear colour
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear the depth and colour buffers
glLoadIdentity();// Reset the modelview matrix
glTranslatef(0.0f, 0.0f, -2.0f);
glutSolidTetrahedron();
glColorMaterial ( GL_FRONT_AND_BACK, GL_EMISSION ) ;
glEnable ( GL_COLOR_MATERIAL ) ;
glDrawBuffer(GL_COLOR_ATTACHMENT3);
glClearColor(0.5f, 0.0f, 0.3f, 1.0f); // Set the clear colour
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear the depth and colour buffers
glLoadIdentity();// Reset the modelview matrix
glTranslatef(0.0f, 0.0f, -2.0f);
glutSolidOctahedron();
glColorMaterial ( GL_FRONT_AND_BACK, GL_EMISSION ) ;
glEnable ( GL_COLOR_MATERIAL ) ;
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our ture
glActiveTexture(GL_TEXTURE0);
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture0);
glUniform1i(glGetUniformLocation(shaderProgram, "tex0"), 0);
glActiveTexture(GL_TEXTURE1);
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture1);
glUniform1i(glGetUniformLocation(shaderProgram, "tex1"), 1);
glActiveTexture(GL_TEXTURE2);
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture2);
glUniform1i(glGetUniformLocation(shaderProgram, "tex2"), 2);
glActiveTexture(GL_TEXTURE3);
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture3);
glUniform1i(glGetUniformLocation(shaderProgram, "tex3"), 3);
glPopAttrib(); // Restore our glEnable and glViewport states
glutSwapBuffers();
}
static char* textFileRead(const char *fileName) {
char* text;
if (fileName != NULL) {
FILE *file = fopen(fileName, "rt");
if (file != NULL) {
fseek(file, 0, SEEK_END);
int count = ftell(file);
rewind(file);
if (count > 0) {
text = (char*)malloc(sizeof(char) * (count + 1));
count = fread(text, sizeof(char), count, file);
text[count] = '\0';
}
fclose(file);
}
}
return text;
}
void initShader(){
char* vsSource = textFileRead("./shader/multitexture.vs");
char* fsSource = textFileRead("./shader/multitexture.fs");
printf("%s\n",fsSource);
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, (const GLchar **)(&vsSource), NULL);
glCompileShader(vertexShader);
printInfoLog(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, (const GLchar **)(&fsSource), NULL);
glCompileShader(fragmentShader);
printInfoLog(fragmentShader);
delete [] vsSource;
delete [] fsSource;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
}
void display (void) {
keyOperations(); // Perform any key presses
glUseProgram(0);
renderTextures(); // Render our teapot scene into our frame buffer
GLsync s = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glUseProgram(shaderProgram);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations
glTranslatef(-4.7f, 1.0f, -4.0f);
glWaitSync(s, 0, GL_TIMEOUT_IGNORED);
glDeleteSync(s);
glBindTexture(GL_TEXTURE_2D, fbo_texture0); // Bind our frame buffer ture
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
glBindTexture(GL_TEXTURE_2D, 0); // Unbind any tures
glLoadIdentity();
glTranslatef(-2.5f, 1.0f, -4.0f);
glBindTexture(GL_TEXTURE_2D, fbo_texture1); // Bind our frame buffer ture
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
glBindTexture(GL_TEXTURE_2D, 0); // Unbind any tures
glLoadIdentity();
glTranslatef(-0.3f, 1.0f, -4.0f);
glBindTexture(GL_TEXTURE_2D, fbo_texture2); // Bind our frame buffer ture
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
glBindTexture(GL_TEXTURE_2D, 0); // Unbind any tures
glLoadIdentity();
glTranslatef(1.9f, 1.0f, -4.0f);
glBindTexture(GL_TEXTURE_2D, fbo_texture3); // Bind our frame buffer ture
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
glBindTexture(GL_TEXTURE_2D, 0); // Unbind any tures
glLoadIdentity();
glTranslatef(4.1f, 1.0f, -4.0f);
glBindTexture(GL_TEXTURE_2D, fbo_texture4); // Bind our frame buffer ture
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
glBindTexture(GL_TEXTURE_2D, 0); // Unbind any tures
glutSwapBuffers();
}
void reshape (int width, int height) {
glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window
glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed
glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes
glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly
}
void keyPressed (unsigned char key, int x, int y) {
keyStates[key] = true; // Set the state of the current key to pressed
}
void keyUp (unsigned char key, int x, int y) {
keyStates[key] = false; // Set the state of the current key to not pressed
}
int main (int argc, char **argv) {
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); // Set up a basic display buffer (only single buffered for now)
glutInitWindowSize (1280, 500); // Set the width and height of the window
glutInitWindowPosition (100, 100); // Set the position of the window
glutCreateWindow ("OpenGL FBO"); // Set the title for the window
if (GLEW_OK != glewInit()) {
std::cout << "Couldn't initialize GLEW" << std::endl;
exit(0);
}
initShader();
init();
glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering
glutIdleFunc(display); // Tell GLUT to use the method "display" for rendering
glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping
glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses
glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events
glutMainLoop(); // Enter GLUT's main loop
}
Here is the vertex shader:
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}
And here is the fragment shader:
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform sampler2D tex3;
void main(void)
{
gl_FragColor = texture2D(tex0, gl_TexCoord[0].st);
}
EDIT #1
After modifying the code as suggested by #Damon (the code has been edited as well) , here's the screenshot of the result:
image 3
Now, I don't really know what the problem actually is. I tried to change the fragment shader to access another texture e.g. gl_FragColor = texture2D(tex2, gl_TexCoord[0].st); but i still got the same display as above. So i think it is definitely not the modelview/projection problem.
EDIT #2
The problem still left unclear. However, I tried to give only one glActiveTexture(GL_TEXTUREn); command at the program, and comment out other glActiveTexture command (without shader modification), and got the following result:
image 4 Only glActiveTexture(GL_TEXTURE0);activated.
image 5 Only glActiveTexture(GL_TEXTURE1);activated.
image 6 Only glActiveTexture(GL_TEXTURE2);activated.
image 7 Only glActiveTexture(GL_TEXTURE3);activated.
When at least 2 glActiveTexture(GL_TEXTUREn); activated, i got the same result as image 5. That left me wondering what the problem actually is.
initShader compiles and links a shader. You seem to be binding the textures to texture units within renderTextures in an OK manner, too (after unbinding the FBO, which is important to sync). So far so good, but I can't find glUseProgram anywhere in the code. That would mean the rendering falls back to fixed function, which does not have any textures bound at that time.
The fragment shader reads only from tex0, so of course you wouldn't expect to see tex1-tex3 anyway (but I guess that's just the minimum working example code).
Other than that, it looks OK from what I can see by reading over the code in 5 mins.
(As a sidenote: init calls glEnable(GL_TEXTURE_2D), this is not strictly wrong, but useless as soon as you use a shader, see this.)
How about this:
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // Bind our frame buffer for rendering
glDrawBuffer(GL_COLOR_ATTACHMENT4);
glBindTexture(GL_TEXTURE_2D, fbo_texture0); // bind texture that is rendered in 0-th attachment
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
glEnd();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
You just render into 4th attachment with binded texture from 0-th attachment.