我正在使用一个简单的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(如果一切顺利,使用compileshader
和loadshader
。它似乎也正常工作。
draw
是问题的关键所在。我将其设置为使用FrameBuffer
,我设置了清晰的颜色(使用x是因为我已经厌倦了将每个参数的值从0.0更改为1.0并再次返回),我清楚,我为我设置了颜色二十面体,现在场景完全呈现在框架中。
然后我开始使用我的程序并切换到0的实际“绘制到屏幕”帧缓冲区,我清除了带黑色的缓冲区(这个清楚似乎并不重要我设置它,它没有影响),我绘制一个没有光线的白色四边形,并将光线和程序恢复为下一个循环。
在执行此操作期间,我没有得到编译器错误或警告。问题是当我将二十面体渲染到帧缓冲区时调用glClear()
时,该颜色会调整整个纹理。我想将x
var设置为0,这样我就会在鲜绿色的形状后面留下黑色背景,但整个纹理会变黑。
这是通过仅更改x
var:
x = 1.0f;
x = 0.5f;
x = 0.1f;
据我了解,形状背后的背景应该是变暗以反映清晰的颜色而不是形状本身。它应该保持与第一张图像中显示的绿色一样鲜艳。
为什么我的清晰颜色会影响二十面体的绘制方式以及如何修复它?
我在Win7 x64上使用Visual Studio和NupenGL库进行编译,而glGetString(GL_VERSION)
表示4.3。
答案 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(我认为)根本不会是绿色的!