我已經拉了很長一段時間的頭髮現在得到渲染紋理功能使用opengl工作使用c &。我使用的是glfw3和opengl es2的一個子集(所以後來我可以使用emscripten編譯這個程序到webgl)。我還沒有得到emscripten部分,因爲當我運行這個程序「本機」時,它只顯示我清除的主要opengl緩衝區的顏色(而不是我附加到fbo的紋理)。渲染紋理
我完成了所有的教程走了,StackOverflow上對這個問題的問題,我能找到(的OpenGL ES/WebGL的),一些比較全面的教程/問題我提到的地方:我覺得我
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/
https://open.gl/framebuffers
http://in2gpu.com/2014/09/24/render-to-texture-in-opengl/
http://stackoverflow.com/questions/8439697/opengl-es-2-0-render-to-texture
http://stackoverflow.com/questions/9629763/opengl-render-to-texture-via-fbo-incorrect-display-vs-normal-texture/9630654#9630654
http://www.gamedev.net/topic/660287-fbo-render-to-texture-not-working/
隨後所有的步驟和建議,它們的價格..
我FBO建立相關的功能是:
// generate a FBO to draw in
glGenFramebuffers(1, &fbo);
// The actual texture to attach to the fbo which we're going to render to
glGenTextures(1, &texture);
// make our fbo active
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, texture);
// Create an empty 512x512 texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
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);
// Set "texture" as our colour attachement #0
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
// Set the list of draw buffers.
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
// Always check that our framebuffer is ok
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
error_callback(-1, "Cannot initialize framebuffer");
}
// Render to the texture (should show up as a blue square)
glViewport(0, 0, 512, 512);
glClearColor(0, 0, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
// unbind textures and buffers
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// upload quad data
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
繪製相關的代碼我的FBO是:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, 1024, 768);
glClearColor(1.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(u_texture, 0);
// Bind buffer with quad data for vertex shader
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(a_position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), BUFFER_OFFSET(0));
glEnableVertexAttribArray(a_position);
glDrawArrays(GL_TRIANGLES, 0, 6);
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
這裏是我使用一個最小的自包含版本的完整代碼:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// include some standard libraries
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// include support libraries including their implementation
#define SHADER_IMPLEMENTATION
#include "shaders.h"
#define BUFFER_OFFSET(i) ((void*)(i))
char *VERTEX_SHADER_SRC =
"#version 100\n"
"attribute vec4 a_position;\n"
"varying vec2 v_uvcoord;\n"
"void main() {\n"
" gl_Position = a_position;\n"
" v_uvcoord = (a_position.xy + 0.5) * 2;\n"
"}\n";
char *FRAGMENT_SHADER_SRC =
"#version 100\n"
"precision mediump float;\n"
"varying vec2 v_uvcoord;\n"
"uniform sampler2D u_texture;\n"
"void main() {\n"
" gl_FragColor = texture2D(u_texture, v_uvcoord);\n"
" //test: gl_FragColor = vec4(0,0,1,1);\n"
"}\n";
GLuint shader_program = NO_SHADER;
GLFWwindow* window;
// Shader attributes
GLuint a_position = -1;
GLuint u_texture = -1;
// FBO
GLuint fbo = 0;
// Target texture
GLuint texture;
// The fullscreen quad's VBO
GLuint vbo;
// The NDC quad vertices
static const GLfloat quad_data[] = {
-0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f,
};
// function for logging errors
void error_callback(int error, const char* description) {
// output to stderr
fprintf(stderr, "%i: %s\n", error, description);
};
void load_shaders() {
GLuint vertexShader = NO_SHADER, fragmentShader = NO_SHADER;
shaderSetErrorCallback(error_callback);
vertexShader = shaderCompile(GL_VERTEX_SHADER, VERTEX_SHADER_SRC);
fragmentShader = shaderCompile(GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SRC);
shader_program = shaderLink(2, vertexShader, fragmentShader);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
a_position = glGetAttribLocation(shader_program, "a_position");
u_texture = glGetUniformLocation(shader_program, "u_texture");
};
void load_objects() {
// generate a FBO to draw in
glGenFramebuffers(1, &fbo);
// The actual texture to attach to the fbo which we're going to render to
glGenTextures(1, &texture);
// make our fbo active
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, texture);
// Create an empty 512x512 texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
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);
// Set "texture" as our colour attachement #0
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
// Set the list of draw buffers.
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
// Always check that our framebuffer is ok
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
error_callback(-1, "Cannot initialize framebuffer");
}
// Render to the texture (should show up as a blue square)
glViewport(0, 0, 512, 512);
glClearColor(0, 0, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
// unbind textures and buffers
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// upload quad data
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
};
void draw_objects() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, 1024, 768);
glClearColor(1.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(u_texture, 0);
// Bind buffer with quad data for vertex shader
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(a_position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), BUFFER_OFFSET(0));
glEnableVertexAttribArray(a_position);
glDrawArrays(GL_TRIANGLES, 0, 6);
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
static void do_render() {
glUseProgram(shader_program);
draw_objects();
glUseProgram(0);
// swap our buffers around so the user sees our new frame
glfwSwapBuffers(window);
glfwPollEvents();
}
void unload_objects() {
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, &texture);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo);
};
void unload_shaders() {
if (shader_program != NO_SHADER) {
glDeleteProgram(shader_program);
shader_program = NO_SHADER;
};
};
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
};
int main(void) {
// tell GLFW how to inform us of issues
glfwSetErrorCallback(error_callback);
// see if we can initialize GLFW
if (!glfwInit()) {
exit(EXIT_FAILURE);
};
// create our window
window = glfwCreateWindow(1024, 768, "Hello GL", NULL, NULL);
if (window) {
GLenum err;
// make our context current
glfwMakeContextCurrent(window);
// init GLEW
glewExperimental=1;
err = glewInit();
if (err != GLEW_OK) {
error_callback(err, glewGetErrorString(err));
exit(EXIT_FAILURE);
};
// tell GLFW how to inform us of keyboard input
glfwSetKeyCallback(window, key_callback);
// load, compile and link our shader(s)
load_shaders();
// load our objects
load_objects();
//emscripten_set_main_loop(do_render, 0, 1);
while (!glfwWindowShouldClose(window)) {
do_render();
};
// close our window
glfwDestroyWindow(window);
};
// lets be nice and cleanup
unload_objects();
unload_shaders();
// the end....
glfwTerminate();
};
以供參考使用的着色器的lib:
/********************************************************
* shaders.h - shader library by Bastiaan Olij 2015
*
* Public domain, use as you say fit, disect, change,
* or otherwise, all at your own risk
*
* This library is given as a single file implementation.
* Include this in any file that requires it but in one
* file, and one file only, proceed it with:
* #define SHADER_IMPLEMENTATION
*
* Note that OpenGL headers need to be included before
* this file is included as it uses several of its
* functions.
*
* This library does not contain any logic to load
* shaders from disk.
*
* Revision history:
* 0.1 09-03-2015 First version with basic functions
*
********************************************************/
#ifndef shadersh
#define shadersh
// standard libraries we need...
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// and handy defines
#define NO_SHADER 0xFFFFFFFF
enum shaderErrors {
SHADER_ERR_UNKNOWN = -1,
SHADER_ERR_NOCOMPILE = -2,
SHADER_ERR_NOLINK = -3
};
#ifdef __cplusplus
extern "C" {
#endif
typedef void(* ShaderError)(int, const char*);
void shaderSetErrorCallback(ShaderError pCallback);
GLuint shaderCompile(GLenum pShaderType, const GLchar* pShaderText);
GLuint shaderLink(GLuint pNumShaders, ...);
#ifdef __cplusplus
};
#endif
#ifdef SHADER_IMPLEMENTATION
ShaderError shaderErrCallback = NULL;
// sets our error callback method which is modelled after
// GLFWs error handler so you can use the same one
void shaderSetErrorCallback(ShaderError pCallback) {
shaderErrCallback = pCallback;
};
// Compiles the text in pShaderText and returns a shader object
// pShaderType defines what type of shader we are compiling
// i.e. GL_VERTEX_SHADER
// On failure returns NO_SHADER
// On success returns a shader ID that can be used to link our program.
// Note that you must discard the shader ID with glDeleteShader
// You can do this after a program has been successfully compiled
GLuint shaderCompile(GLenum pShaderType, const GLchar * pShaderText) {
GLint compiled = 0;
GLuint shader;
const GLchar *stringptrs[1];
// create our shader
shader = glCreateShader(pShaderType);
// compile our shader
stringptrs[0] = pShaderText;
glShaderSource(shader, 1, stringptrs, NULL);
glCompileShader(shader);
// check our status
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint len = 0;
char type[50];
switch (pShaderType) {
case GL_VERTEX_SHADER: {
strcpy(type, "vertex");
} break;
case GL_TESS_CONTROL_SHADER: {
strcpy(type, "tessellation control");
} break;
case GL_TESS_EVALUATION_SHADER: {
strcpy(type, "tessellation evaluation");
} break;
case GL_GEOMETRY_SHADER: {
strcpy(type, "geometry");
} break;
case GL_FRAGMENT_SHADER: {
strcpy(type, "fragment");
} break;
default: {
strcpy(type, "unknown");
} break;
};
glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &len);
if ((len > 1) && (shaderErrCallback != NULL)) {
GLchar* compiler_log;
// allocate enough space for our prefix and error
compiler_log = (GLchar*) malloc(len+50);
// write out our prefix first
sprintf(compiler_log, "Error compiling %s shader: ", type);
// append our error
glGetShaderInfoLog(shader, len, 0, &compiler_log[strlen(compiler_log)]);
// and inform our calling logic
shaderErrCallback(SHADER_ERR_NOCOMPILE, compiler_log);
free(compiler_log);
} else if (shaderErrCallback != NULL) {
char error[250];
sprintf(error,"Unknown error compiling %s shader", type);
shaderErrCallback(SHADER_ERR_UNKNOWN, error);
};
glDeleteShader(shader);
shader = NO_SHADER;
};
return shader;
};
// Links any number of programs into a shader program
// To compile and link a shader:
// ----
// GLuint vertexShader, fragmentShader, shaderProgram;
// vertexShader = shaderCompile(GL_VERTEX_SHADER, vsText);
// fragmentShader = shaderCompile(GL_FRAGMENT_SHADER, vsText);
// shaderProgram = shaderLink(2, vertexShader, fragmentShader);
// glDeleteShader(vertexShader);
// glDeleteShader(fragmentShader);
// ----
// Returns NO_SHADER on failure
// Returns program ID on success
// You must call glDeleteProgram to cleanup the program after you are done.
GLuint shaderLink(GLuint pNumShaders, ...) {
GLuint program;
va_list shaders;
int s;
// create our shader program...
program = glCreateProgram();
// now add our compiled code...
va_start(shaders, pNumShaders);
for (s = 0; s < pNumShaders && program != NO_SHADER; s++) {
GLuint shader = va_arg(shaders, GLuint);
if (shader == NO_SHADER) {
// assume we've set our error when the shader failed to compile...
glDeleteProgram(program);
program = NO_SHADER;
} else {
glAttachShader(program, shader);
};
};
va_end(shaders);
// and try and link our program
if (program != NO_SHADER) {
GLint linked = 0;
glLinkProgram(program);
// and check whether it all went OK..
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (!linked) {
GLint len = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH , &len);
if ((len > 1) && (shaderErrCallback != NULL)) {
GLchar* compiler_log;
// allocate enough space for our prefix and error
compiler_log = (GLchar*) malloc(len+50);
// write out our prefix first
strcpy(compiler_log, "Error linking shader program: ");
// append our error
glGetProgramInfoLog(program, len, 0, &compiler_log[strlen(compiler_log)]);
// and inform our calling logic
shaderErrCallback(SHADER_ERR_NOLINK, compiler_log);
free(compiler_log);
} else if (shaderErrCallback != NULL) {
char error[250];
strcpy(error,"Unknown error linking shader program");
shaderErrCallback(SHADER_ERR_UNKNOWN, error);
};
glDeleteProgram(program);
program = NO_SHADER;
};
};
return program;
};
#endif
#endif
當我編譯使用: cc pkg-config --cflags glfw3
-o rtt rtt.c pkg-config --static --libs glfw3 glew
我只是得到一個紅色的屏幕(我清楚的主要幀緩衝區),但我期望一個藍色的矩形出現在屏幕中間(之前我清除爲藍色的紋理)。即使我取消了片段着色器中的測試線的註釋,也沒有顯示藍色矩形!
有沒有人看到我在這裏失蹤?
在此先感謝!
Martijn
這是一段很長的代碼。 –
對不起,我想包括一個(最小的)工作示例,我將在包含整個文件之前首先突出顯示相關函數(load_objects&draw_objects)。 – Martijnh