【发布时间】:2014-11-15 00:59:11
【问题描述】:
我正在编写一个代码,该代码要求我将 2+ 个纹理发送到片段着色器中,然后我需要从着色器中获取 2 个 COLOR_ATTACHMETn。一旦我从我的着色器中得到COLOR_ATTACHMENT0 和COLOR_ATTACHMENT1,是否可以将它们作为采样器发送到着色器中以在四边形屏幕上渲染?
我需要将 COLOR_ATTACHMENT 发送到第二个着色器的原因是我在不同的监视器上渲染 COLOR_ATTACHMENT0 和 COLOR_ATTACHMENT1。 COLOR_ATTACHMENT0 将出现在一个屏幕上,COLOR_ATTACHMENT1 将出现在另一个屏幕上...
我正在进行测试视力的心理实验。我的第一个着色器对我的原始纹理集进行处理,但由于两个输出纹理所需的大部分处理是相同的,我不想在不需要时运行着色器基本上两次。
我正在使用 GLFW、GLEW 和 GLM。所以任何使用这些库的解决方案都是理想的
用于传递纹理坐标和屏幕位置的基本顶点着色器
const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main() {"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
任意片段着色器,接收两个采样器并输出两个 vec4“纹理”
const GLchar* fragmentSource =
"#version 150 core\n"
"in vec2 Texcoord;"
"out vec4 outColor0;"
"out vec4 outColor1;"
"uniform sampler2D texLite;"
"uniform sampler2D texDark;"
"void main() {"
" outColor0 = texture(texLite, Texcoord);"
" outColor1 = texture(texDark, Texcoord);"
"}";
(和以前一样)基本的顶点着色器传递纹理坐标和屏幕位置
const GLchar* vertexSourceDisp =
"#version 150 core\n"
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main() {"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
简单的片段着色器用于采样器并在四边形上显示
const GLchar* fragmentSourceDisp =
"#version 150 core\n"
"in vec2 Texcoord;"
"out vec4 outColor;"
"uniform sampler2D tex;"
"void main() {"
" outColor = texture(tex, Texcoord);"
"}";
当我运行 glFramebufferTexture2D 时,它会将纹理图像附加到帧缓冲区,所以当着色器运行时,我的着色器输出的 vec4 是否会存储回纹理以及颜色附件中?
完整代码
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <stdio.h>
// Simple through-put vertex shader
const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main() {"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
// Basic fragment shader for the moment
const GLchar* fragmentSource =
"#version 150 core\n"
"in vec2 Texcoord;"
"out vec4 outColor0;"
"out vec4 outColor1;"
"uniform sampler2D texLite;"
"uniform sampler2D texDark;"
"void main() {"
" vec4 colLena = texture(texLite, Texcoord);"
" vec4 colTex7 = texture(texDark, Texcoord);"
" outColor0 = mix(colLena, colTex7, 0.0);"
" outColor1 = mix(colLena, colTex7, 1.0);"
"}";
const GLchar* vertexSourceDisp =
"#version 150 core\n"
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main() {"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
const GLchar* fragmentSourceDisp =
"#version 150 core\n"
"in vec2 Texcoord;"
"out vec4 outColor;"
"uniform sampler2D tex;"
"void main() {"
" outColor = texture(tex, Texcoord);"
"}";
void printShaderInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
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()
{
if (glfwInit() != GL_TRUE)
{
fprintf(stderr, "Failed to initialize GLFW\n");
return -1;
}
int count;
GLFWmonitor** monitors = glfwGetMonitors(&count);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window0;
GLFWwindow* window1;
window0 = glfwCreateWindow(1680, 1050, "OpenGL", monitors[2], window1); // Front Screen
window1 = glfwCreateWindow(1280, 800, "OpenGL", monitors[1], window0); // Back Screen
glfwMakeContextCurrent(window0);
glfwSetKeyCallback(window0, key_callback);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Vertex array object - Contains all vertex information
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Vertex buffer object
GLuint vbo;
glGenBuffers(1, &vbo);
// Vertices to use inside my shader
GLfloat vertices[] = {
-1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 1.0f
};
// Attached vertices to my GPU
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Element buffer object - allows me to reuse vertices
GLuint ebo;
glGenBuffers(1, &ebo);
// Index into the rows of vertices to use different vertices more than once
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
// Attach element array to use on GPU
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
// Set up shader
// Vertex Shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
printShaderInfoLog(vertexShader);
// Fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
printShaderInfoLog(fragmentShader);
// Shader program
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor0");
glBindFragDataLocation(shaderProgram, 1, "outColor1");
printProgramInfoLog(shaderProgram);
glLinkProgram(shaderProgram);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0);
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
4*sizeof(float), (void*)(2*sizeof(float)));
cv::VideoCapture cap("movie.mov");
cv::Mat image0;
cv::Mat image1;
int width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
// float ratio = width/(float)height;
//Set up samplers
GLuint ldrTextures[2];
glGenTextures(2, ldrTextures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ldrTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR, GL_UNSIGNED_BYTE, NULL);
glUniform1i(glGetUniformLocation(shaderProgram, "texLite"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, ldrTextures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR, GL_UNSIGNED_BYTE, NULL);
glUniform1i(glGetUniformLocation(shaderProgram, "texDark"), 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//Set up framebuffer
GLuint frameBuffer;
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
//Set up target textures
GLuint dispTextures[2];
glGenTextures(2, dispTextures);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, dispTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dispTextures[0], 0);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, dispTextures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, dispTextures[1], 0);
GLenum bufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, bufs);
bool success;
//Render loop
while(!glfwWindowShouldClose(window0) && !glfwWindowShouldClose(window1))
{
std::cout << "Loop" << std::endl;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Grab two frames from video
success = cap.read(image0);
if(!success)
{
std::cout << "Could not grab a frame" << std::endl;
exit(0);
}
success = cap.read(image1);
if(!success)
{
std::cout << "Could not grab a frame" << std::endl;
exit(0);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ldrTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR, GL_UNSIGNED_BYTE, image0.data);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, ldrTextures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR, GL_UNSIGNED_BYTE, image1.data);
glfwMakeContextCurrent(window0);
glfwSetKeyCallback(window0, key_callback);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
// glViewport(0,0,width,height);
// glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glActiveTexture(GL_TEXTURE2);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glActiveTexture(GL_TEXTURE3);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glfwMakeContextCurrent(window0);
glfwSetKeyCallback(window0, key_callback);
glViewport(0,0,width,height);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, dispTextures[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window0);
glfwPollEvents();
glfwMakeContextCurrent(window1);
glfwSetKeyCallback(window1, key_callback);
glViewport(0,0,width,height);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, dispTextures[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window1);
glfwPollEvents();
}
//Clean up memory, remember good coding practices
glDeleteTextures(1, ldrTextures);
glDeleteTextures(1, dispTextures);
glDeleteFramebuffers(1, &frameBuffer);
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();
}
【问题讨论】:
-
texLite和texDark是我原来的两张图片。我正在使用 OpenCv 读取它们并将它们转换为纹理,然后在着色器中将它们用作采样器。每次调用glUseProgram时,我都需要将outColor0和outColor1作为两个新纹理。有没有办法把我的颜色附件变成纹理? -
@Maggic:您可以渲染到纹理,因此您的颜色附件可以是纹理。但我真的不明白这一切的意义。你到底想在这里解决什么问题?
-
我有两个显示器(两个不同的显示器)我想运行一个处理一系列图像/纹理的着色器,然后我需要从该着色器返回两个图像/纹理/颜色附件。每个颜色附件都需要渲染到不同屏幕上的四边形上。由于某种原因,我无法在两个屏幕上渲染。但我试图看看是否可以将颜色附件重新转换为纹理并使用新的着色器在每个不同的监视器上显示每个纹理。如果有助于理解,我附上了完整的代码
-
老实说,这听起来更像是多个渲染上下文和资源共享的问题。您是否尝试使用单独的窗口来驱动这些显示器中的每一个?默认情况下,每个窗口的渲染上下文不会共享同一组资源名称,所以这可能是您的问题。
-
是的。但是我已经设置了两个窗口来共享资源。
GLFWwindow* window0;GLFWwindow* window1;window0 = glfwCreateWindow(1680, 1050, "OpenGL", monitors[2], window1); // Front Screenwindow1 = glfwCreateWindow(1280, 800, "OpenGL", monitors[1], window0); // Back Screen