Недавно я пытался узнать о современных OpenGL / GLSL, и это привело меня к теме FBO, и я столкнулся с загадочной проблемой.
В моей программе я инициализирую FBO, а затем отменяю привязку. Пока все работает. Затем я связываю FBO и отображаю на нем свою сцену. Теперь я получаю пустой экран при запуске этой программы, но это нормально — я не отображаю вывод. Однако, когда я пытаюсь это сделать или пытаюсь что-то сделать, я все равно получаю черный экран. Я могу заставить это работать, только если я не связываю FBO во время основного цикла.
У меня были FBO, работающие на Java, с использованием LWJGL, и это второй раз, когда я пытался отрисовать FBO на C ++ с SDL, и оба раза я сталкивался с одной и той же ошибкой.
Что это не так:
Кроме того, glChackFramebufferStatus (GL_FRAMEBUFFER) возвращает GL_FRAMEBUFFER_COMPLETE, а glGetError () возвращает 0.
Кроме того, я понимаю, что есть несколько вещей, которые я не сделал, которые были бы разумными (например, буфер глубины), которые не влияют на эту ошибку. Я заполню их позже.
Вот код:
main.cpp:
#include <iostream>
#include "GLee.h"#define GLM_FORCE_RADIANS
#include "matrices.h" //Replaces built-in matrices, functions behave the same as legacy OGL
#include "functions.h" //Camera, works very well
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>#include <SDL/SDL_opengl.h>
#include <SDL/SDL_mouse.h>
#include <math.h>
#include <SDL/SDL_opengl.h>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
#include <cstdio>
#include <cstdlib>#include <GL/gl.h>
#include <GL/glu.h>//#include <SDL/SDL_video.h>
using namespace std;
unsigned int grass, crate, FBOTex;
int ground, monkey;
bool mousein = true;
matrices pipeline;
int frame;
#include <GL/gl.h>
#include <GL/glu.h>
#include "TexLoader.h" //Loads textures - I've never had issues with this header
#include "ModelLoader.h" //Loads models (OBJ), again, works like a treat
#include "shader.h" //Includes the shader class, which has been proven to work
#include "Material.h" //Used in lighting calculations
texProperties linear = texProperties(GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, 16);
texProperties pixellated = texProperties(GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, 16); //Properties for textures loaded by the texture loader.
shader* mainShader;
shader* postProcess; //The FBO shader
material simpleMaterial = material(0.2, 0.2, 0.2, 0.6, 0.6, 0.6, 0.1,0.1,0.1, 1000),
littleShine = material(0.2, 0.2, 0.2, 0.6, 0.6, 0.6, 0.1,0.1,0.1, 5),
monkeyMtl = material(0.2, 0.2, 0.2, 0.6, 0.6, 0.6, 0.3,0.3,0.3, 50);
//monkeyMtl = material(0.2, 0.2, 0.2, 0.6, 0.6, 0.6, 1,1,1, 5);
SDL_Surface* loadTextureData(const char* fileName){ //For creating icons
SDL_Surface* tex;
if((tex = IMG_Load(fileName))){
cout<<"Texture Found! Tex: "<<fileName<<endl;
}
return tex;
}
unsigned int createTexture(int w, int h, bool isDepth){ //Create texture for FBO
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, isDepth?GL_DEPTH_COMPONENT:GL_RGBA8, w, h, 0, isDepth?GL_DEPTH_COMPONENT:GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
int i;
i = glGetError();
if(i != 0){
cout<<"Texture creation error! Error code: "<<i<<endl;
}
glBindTexture(GL_TEXTURE_2D, 0);
return textureID;
}
unsigned int fbo; //The FBO ID
unsigned int renderTexture; //The ID of the output texture for the FBO
void init(){
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
const unsigned char* text = glGetString(GL_VERSION); //OpenGL 4
cout<<"GL version: "<<text<<endl;
SDL_WM_GrabInput(SDL_GRAB_ON);
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
SDL_WM_SetCaption("OGL!", "OGL!!");
//SDL_WM_IconifyWindow();
SDL_Surface* icon = loadTextureData("Logo.png");
SDL_WM_SetIcon(icon, NULL);
glClearColor(0.0, 0.0, 0.0, 1);
pipeline.matrixMode(PROJECTION_MATRIX);
pipeline.loadIdentity();
pipeline.perspective(45, 1280.0/720.0, 0.1, 5000.0); //Similar to legacy OGL
pipeline.matrixMode(MODEL_MATRIX);
SDL_FreeSurface(icon);
mainShader = new shader("vertex.vert", "fragment.frag"); //These shader files load+compile fine
postProcess = new shader("PostProcess.vert", "PostProcess.frag");
grass = getTexture("Textures/Grass.png", linear);
crate = getTexture("Textures/Crate.png", linear);
ground = loadModel("Models/Plane.obj");
monkey = loadModel("Models/Monkey.obj");
float amb[3] {0.2, 0.2, 0.2};
float diff[3] {0.6, 0.6, 0.6};
float spec[3] {1, 1, 1};
//////////FBO Creation///////////
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);//This bind function works
renderTexture = createTexture(1920, 1080, false);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0);
int i = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(i != GL_FRAMEBUFFER_COMPLETE){//I get no errors here...
cout<<"FBO is not complete!"<<endl;
}
cout<<"glGetError() = "<<glGetError()<<endl; //Prints 0
glBindFramebuffer(GL_FRAMEBUFFER, 0); //This unbind works perfectly
}
void display(){ //The drawing part of the main loop
cout<<"FBO Number: "<<fbo<<endl; //Returns 1, as it should
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
mainShader->bindShader();
mainShader->setUniformFloat3("lspecular", 1,1,1); //Lighting stuff...
mainShader->setUniformFloat3("lambient", 0.2,0.2,0.2);
mainShader->setUniformFloat3("ldiffuse", 0.6,0.6,0.6);
mainShader->setUniformFloat3("lightPos", 0,500,0);
mainShader->setUniformSampler("texture", 0);
mainShader->setUniformFloat("constantAttenuation", 0.0);
mainShader->setUniformFloat("linearAttenuation", 0.0);
mainShader->setUniformFloat("quadraticAttenuation", 0.000002);
littleShine.addToShader(*mainShader); //Sets material for lighting
pipeline.matrixMode(PROJECTION_MATRIX);
pipeline.loadIdentity();
pipeline.perspective(45, 1280.0/720.0, 0.1, 5000.0); //3D projection
pipeline.matrixMode(VIEW_MATRIX);
pipeline.loadIdentity();
control(0.2, 0.2, mousein, pipeline); //Controls camera
updateCamera(pipeline); //Updates matrices
pipeline.updateMatrices(mainShader->getHandle()); //Updates shader matrices
glBindTexture(GL_TEXTURE_2D, grass);
pipeline.matrixMode(MODEL_MATRIX);
//pipeline.loadIdentity();
glCallList(ground);
pipeline.translate(0, 1, -5);
pipeline.rotatef(frame, 0, 1, 0);
pipeline.updateMatrices(mainShader->getHandle());
monkeyMtl.addToShader(*mainShader);
glBindTexture(GL_TEXTURE_2D, crate);
glCallList(monkey);
glBindFramebuffer(GL_FRAMEBUFFER, 0); ///////DOESN'T UNBIND!! Still get black screen
//glClear(GL_COLOR_BUFFER_BIT);
pipeline.matrixMode(MODEL_MATRIX);
pipeline.loadIdentity();
pipeline.matrixMode(VIEW_MATRIX);
pipeline.loadIdentity();
//pipeline.translate(0, 0, -5);
pipeline.matrixMode(PROJECTION_MATRIX);
pipeline.loadIdentity();
pipeline.ortho(1920, 0, 0, 1080, 1, -1);//Clear matrices, set orthographic view
//mainShader->unbindShader();
postProcess->bindShader(); //Binds the post-processing shader
postProcess->setUniformSampler("texture", 0); //Texture sampler
pipeline.updateMatrices(postProcess->getHandle());
glBindTexture(GL_TEXTURE_2D, renderTexture); //Bind the FBO's output as a texture
glBindFramebuffer(GL_FRAMEBUFFER, 0); //Tried a second time to unbind FBO, to no avail...
glBegin(GL_QUADS);
glColor3f(1.0, 1.0, 1.0); //Makes no difference
glTexCoord2f(0,0); /////Draw FBO texture to screen, fails
glVertex2f(0,0);
glTexCoord2f(1,0);
glVertex2f(1920,0);
glTexCoord2f(1,1);
glVertex2f(1920,1080);
glTexCoord2f(0,1);
glVertex2f(0,1080);
glEnd();
}
void update(){
frame++;
}
int main(int args, char* argv[]){
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_PNG);
SDL_Delay(150);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_Surface* screen = SDL_SetVideoMode(1920, 1080, 32, SDL_SWSURFACE|SDL_OPENGL|SDL_FULLSCREEN);
bool running = true;
Uint32 start;
SDL_Event event;
init();
while(running){
start = SDL_GetTicks();
while(SDL_PollEvent(&event)){
switch(event.type){
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym){
default:
break;
case SDLK_ESCAPE:
running = false;
break;
case SDLK_p:
mousein = false;
SDL_ShowCursor(SDL_ENABLE);
SDL_WM_GrabInput(SDL_GRAB_OFF);
break;
}
break;
case SDL_KEYUP:
break;
case SDL_MOUSEBUTTONDOWN:
mousein = true;
SDL_ShowCursor(SDL_DISABLE);
SDL_WM_GrabInput(SDL_GRAB_ON);
break;
}
}
update();
display();
SDL_GL_SwapBuffers();
if(1000/60 > (SDL_GetTicks() - start)){
SDL_Delay(1000/60 - (SDL_GetTicks() - start));
}
}
delete mainShader;
SDL_Quit();
//cout << "Hello world!" << endl;
return 0;
}
PostProcess.vert:
#version 130
varying vec2 texCoord;
varying vec3 position;
varying vec3 normal;
//Matrices, passed in to shader
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;void main(){
gl_Position = modelViewProjectionMatrix * gl_Vertex;
normal = normalMatrix * gl_Normal;
texCoord = gl_MultiTexCoord0.st;
position = vec3(modelViewMatrix * gl_Vertex);
}
PostProcess.frag:
#version 130
uniform sampler2D texture;
varying vec2 texCoord;
varying vec3 position;
varying vec3 normal;
void main(){
gl_FragColor = texture(texture, texCoord); //Draw the textur, also tried texture2D...
//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); //I've tried drawing white to the screen - it failed
}
Я действительно не знаю, что здесь происходит. Я думаю, это что-то простое, но как я пропустил это дважды?
Я решил это!
По какой-то причине файл material.cpp все испортил. По какой-то причине, когда я использовал функцию material.addToShader (шейдер), он не рендерился, но когда я сам добавил униформу или изменил параметр на указатель на шейдер, он, казалось, работал отлично.
Произошла ошибка 1281, вызванная этой проблемой. Почему это так, я понятия не имею, но, по крайней мере, сейчас это решено!
Вы не вызываете glClear, когда оконный фрейм-буфер связан. Пытаться:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);