glClearColor是否整理了我的整个纹理?

时间:2016-04-11 19:21:51

标签: opengl

我正在使用一个简单的OpenGL应用程序,我之前有一个二十面体并将其更改为渲染到纹理,然后在屏幕上绘制该纹理。不知何故,在渲染到纹理的过程中,当我调用glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);时,我的整个纹理都被我的glClearColor着色。以下是我所拥有的全部内容:

#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream>
#include <fstream>
#include <Windows.h>

using namespace std;

void SetupRenderTarget();
void EnableLighting();
GLuint LoadProgram(char*, char*);
void draw();
float UpdateDelta();
unsigned long getFileLength(ifstream&);
GLuint compileshader(char* file, GLenum shader_type);
int loadshader(char*, GLchar**, unsigned long*);

GLuint quad_vertexbuffer;
GLuint frame = 0;
GLuint FrameBuffer = 0;
GLuint texID = 0;
GLuint timeID = 0;
GLuint renderedTexture;

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(100, 500);
    glutCreateWindow("Hello World");
    glutDisplayFunc(draw);

    glewInit();

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_MULTISAMPLE);
  glEnable(GL_TEXTURE_2D);
  glViewport(0, 0, 300, 300);
    EnableLighting();
  SetupRenderTarget();

  frame = LoadProgram((char*)"passthrough.shader", (char*)"framebuffer.shader");
  texID = glGetUniformLocation(frame, "renderedTexture");
  timeID = glGetUniformLocation(frame, "time");

    glutMainLoop();
    return 0;
}

void SetupRenderTarget() {
  glGenFramebuffers(1, &FrameBuffer);
  glBindFramebuffer(GL_FRAMEBUFFER, FrameBuffer);
  glGenTextures(1, &renderedTexture);
  glBindTexture(GL_TEXTURE_2D, renderedTexture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 300, 300, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

  GLuint DepthBuffer;
  glGenRenderbuffers(1, &DepthBuffer);
  glBindRenderbuffer(GL_RENDERBUFFER, DepthBuffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 300, 300);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, DepthBuffer);

  glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
  GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
  glDrawBuffers(1, DrawBuffers);

  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
    cout << "Frame Buffer Error!" << endl;
    return;
  }

  cout << "Frame Buffer Setup" << endl;
}

void EnableLighting() {
    float light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    float light_position[] = { -1.0, 1.0, 1.0, 0.0 };
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_COLOR_MATERIAL);
}

GLuint LoadProgram(char* vertex, char* fragment) {
  GLuint ProgramObject = 0;
  GLuint v, f;
  if (vertex != 0) v = compileshader(vertex, GL_VERTEX_SHADER);
  if (fragment != 0) f = compileshader(fragment, GL_FRAGMENT_SHADER);

    ProgramObject = glCreateProgram();
  if (v != -1) glAttachShader(ProgramObject, v);
  if (f != -1) glAttachShader(ProgramObject, f);

    cout << "Linking Shader..." << endl;
    glLinkProgram(ProgramObject);

    cout << "Done!" << endl;
    return ProgramObject;
}

GLuint compileshader(char* file, GLenum shader_type) {
  cout << "Loading Shader: " << file << endl;
  char* src;
  unsigned long src_length = 0;
  int err = loadshader(file, &src, &src_length);
  if (err != 0) return -1;// something went wrong

  cout << "Creating Shader..." << endl;
  GLuint shader = glCreateShader(shader_type);
  cout << "Loading Shader..." << endl;
  glShaderSourceARB(shader, 1, (const char**)&src, (const int*)&src_length);
  cout << "Compiling Shader..." << endl;
  glCompileShaderARB(shader);
  delete[] src;

  GLint compiled;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
  if (!compiled) {
    GLint blen = 0;
    GLsizei slen = 0;

    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &blen);
    if (blen > 1) {
      GLchar* compiler_log = (GLchar*)malloc(blen);
      glGetInfoLogARB(shader, blen, &slen, compiler_log);
      cout << "Compiler Log:" << endl << compiler_log << endl;
      free(compiler_log);
    } else {
      cout << "Compile error but could not get log!" << endl;
    }
    return -1;
  }
  return shader;
}

void draw() {
  static float mytime = 0;
    float delta = UpdateDelta();
  mytime += delta;

  glBindFramebuffer(GL_FRAMEBUFFER, FrameBuffer);
  glViewport(0, 0, 300, 300);

  glLoadIdentity();
  float x = 0.5f;
  glClearColor(x, x, x, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(0, 1, 0);

    glRotatef(45, 0, 1, 0);
    glutSolidIcosahedron();

  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  glViewport(0, 0, 300, 300);

  glUseProgram(frame);
  glUniform1i(texID, 0);
  glUniform1f(timeID, mytime * 10);

  glLoadIdentity();
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glColor3f(1, 1, 1);
  glDisable(GL_LIGHTING);

  glBegin(GL_QUADS);
  glTexCoord2f(0.0f, 0.0f);
  glVertex3f(-1.0f, -1.0f, 0.0f);  // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0f, 0.0f);
  glVertex3f(1.0f, -1.0f, 0.0f);  // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0f, 1.0f);
  glVertex3f(1.0f, 1.0f, 0.0f);  // Top Right Of The Texture and Quad
  glTexCoord2f(0.0f, 1.0f);
  glVertex3f(-1.0f, 1.0f, 0.0f);  // Top Left Of The Texture and Quad
  glEnd();

  glEnable(GL_LIGHTING);
  glUseProgram(0);

    glFlush();
    glutSwapBuffers();
    glutPostRedisplay();
}

float UpdateDelta() {
    static int time_since_start = 0;
    static int last = 0;
    time_since_start = glutGet(GLUT_ELAPSED_TIME);

    float ret = (time_since_start - last) / 1000.0f;
    last = time_since_start;
    return ret;
}

unsigned long getFileLength(ifstream& file) {
    if (!file.good()) return 0;

    unsigned long pos = (unsigned long)file.tellg();
    file.seekg(0, ios::end);
    unsigned long len = (unsigned long)file.tellg();
    file.seekg(ios::beg);

    return len;
}

int loadshader(char* filename, GLchar** ShaderSource, unsigned long* len) {
    ifstream file;
    file.open(filename, ios::in); // opens as ASCII!
    if (!file) return -1;

    *len = getFileLength(file);

    if (*len == 0) return -2;   // Error: Empty File

    *ShaderSource = (GLchar*) new char[*len + 1];
    if (*ShaderSource == 0) return -3;   // can't reserve memory

                                         // len isn't always strlen cause some characters are stripped in ascii read...
                                         // it is important to 0-terminate the real length later, len is just max possible value... 
    (*ShaderSource)[*len] = 0;

    unsigned int i = 0;
    while (file.good()) {
        (*ShaderSource)[i] = file.get();       // get character from file.
        if (!file.eof()) {
            i++;
        }
    }
    (*ShaderSource)[i] = 0;  // 0-terminate it at the correct position
    file.close();

    return 0; // No Error
}

我正在部分关注this tutorial并使用它的着色器。

passthrough.shader:

#version 330 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;

// Output data ; will be interpolated for each fragment.
out vec2 UV;

void main() {
  gl_Position = vec4(vertexPosition_modelspace, 1);
  UV = (vertexPosition_modelspace.xy + vec2(1, 1)) / 2.0;
}

和framebuffer.shader:

#version 330 core

in vec2 UV;

out vec3 color;

uniform sampler2D renderedTexture;
uniform float time;

void main() {
  color = texture(renderedTexture, UV.xy).rgb; // no change to image
  //color = texture(renderedTexture, UV + 0.005*vec2(sin(time + 300.0*UV.x), cos(time + 300.0*UV.y))).xyz; // wibbly-wobbly version from tutorial
}

好的,我知道这是很多代码,所以这里简短而且甜蜜,因为我明白发生了什么。

SetupRenderTarget创建一个与窗口大小相同的颜色和深度缓冲区(300x300)。

EnableLighting只是定位并点亮场景。它似乎工作得很好,除了提供一个有趣的东西之外,与其他问题无关。

LoadProgram读取向量和片段源文件,编译它们,将它们放在同一个程序中,链接该程序并返回程序ID(如果一切顺利,使用compileshaderloadshader 。它似乎也正常工作。

draw是问题的关键所在。我将其设置为使用FrameBuffer,我设置了清晰的颜色(使用x是因为我已经厌倦了将每个参数的值从0.0更改为1.0并再次返回),我清楚,我为我设置了颜色二十面体,现在场景完全呈现在框架中。

然后我开始使用我的程序并切换到0的实际“绘制到屏幕”帧缓冲区,我清除了带黑色的缓冲区(这个清楚似乎并不重要我设置它,它没有影响),我绘制一个没有光线的白色四边形,并将光线和程序恢复为下一个循环。

在执行此操作期间,我没有得到编译器错误或警告。问题是当我将二十面体渲染到帧缓冲区时调用glClear()时,该颜色会调整整个纹理。我想将x var设置为0,这样我就会在鲜绿色的形状后面留下黑色背景,但整个纹理会变黑。

这是通过仅更改x var:

生成的一些图像

x = 1.0f;

x = 1

x = 0.5f;

x = 0.5

x = 0.1f;

x = 0.1

据我了解,形状背后的背景应该是变暗以反映清晰的颜色而不是形状本身。它应该保持与第一张图像中显示的绿色一样鲜艳。

为什么我的清晰颜色会影响二十面体的绘制方式以及如何修复它?

我在Win7 x64上使用Visual Studio和NupenGL库进行编译,而glGetString(GL_VERSION)表示4.3。

1 个答案:

答案 0 :(得分:0)

由于在绘制ICO时未使用着色器,因此使用默认管道。 glEnable(GL_TEXTURE_2D);指示管道使用纹理。你绑定了哪种纹理?

原来你绑定了渲染的纹理glBindTexture(GL_TEXTURE_2D, renderedTexture);,并且永远不会通过调用glBindTexture(GL_TEXTURE_2D, 0);来解除它。所以你正在绘制一个ICO,它从你绘制的内容中获取纹理数据,当时只包含背景颜色(x,x,x)

从技术上讲,我认为在写入纹理时从纹理读取会导致未定义的行为。因此,即使这次行为“正确”,也不要指望这种行为能够始终如一地运作。

另外,您应该知道glEnable(GL_COLOR_MATERIAL);会使您的纹理与颜色混合,所以没有那个调用,ICO(我认为)根本不会是绿色的!