я бы хотел получить цвет текущего текселя в моем фрагментном шейдере так что я могу адаптировать выходной цвет в зависимости от него.
Например: если цвет текущего текселя красный затем установите цвет на зеленый.
Вы можете увидеть, что есть два треугольники. Один треугольник частично нарисован на другой. Вы можете видеть, что наложенная часть имеет зеленый цвет, так как, как я уже сказал, мой фрагментный шейдер обнаружил цвет «красный», поэтому он установил выходной цвет на «зеленый».
Как видите, моя программа работает хорошо. Тем не менее, я очень новичок в OpenGL, поэтому я не совсем понимаю все, что я написал, и я уверен, что сделал несколько ошибок. Я хотел бы получить ваши отзывы.
Что я сделал, чтобы добиться этого:
Сначала я пытался нарисовать два треугольника прямо на экране без FBO, но тогда я не мог получить цвет текселя с texture2D()
в моем фрагменте шейдера.
Вот мой код (я использую OpenGL 3.3, GLFW 3 а также GLEW):
#include <iostream>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const std::string WINDOW_TITLE = "Drawing color depending on current background pixel color";
const GLuint WIDTH = 800, HEIGHT = 600;
const std::string vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0f);
}
)";
const std::string fragmentShaderSource = R"(
#version 330 core
layout(location = 0) out vec4 color;
uniform sampler2D renderedTexture;
void main()
{
vec2 size = textureSize(renderedTexture, 0);
vec2 position = gl_FragCoord.xy / size.xy;
vec4 inputColor = texture2D(renderedTexture, position);
if (inputColor[0] == 0.0f)
{
color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
else if (inputColor[0] == 1.0f)
{
color = vec4(0.1f, 1.0f, 0.0f, 1.0f);
}
else
{
color = vec4(0.8f, 0.0f, 1.0f, 1.0f);
}
}
)";GLFWwindow *setupWindow()
{
GLFWwindow *window = nullptr;
int width = 0, height = 0;
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, WINDOW_TITLE.c_str(), nullptr, nullptr);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glewInit();
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
return window;
}
GLuint compileShader(GLenum type, const std::string &source, std::string &errorLog)
{
GLuint shader = 0;
GLint compileSuccess = 0;
const GLchar *sourceC = source.c_str();
const std::size_t ERROR_LOG_BUFFER_SIZE = 512;
GLchar errorLogBuffer[ERROR_LOG_BUFFER_SIZE]{};
errorLog = "";
shader = glCreateShader(type);
glShaderSource(shader, 1, &sourceC, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);
if (!compileSuccess)
{
glGetShaderInfoLog(shader, ERROR_LOG_BUFFER_SIZE, nullptr, errorLogBuffer);
glDeleteShader(shader);
errorLog = errorLogBuffer;
return 0;
}
return shader;
}
GLuint compileShaderProgram(const std::string &vertexShaderSource, const std::string &fragmentShaderSource, std::string &errorLog)
{
GLuint vertexShader{};
GLuint fragmentShader{};
GLuint shaderProgram{};
GLint linkSuccess{};
const std::size_t ERROR_LOG_BUFFER_SIZE = 512;
GLchar errorLogBuffer[ERROR_LOG_BUFFER_SIZE]{};
errorLog = "";
vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource, errorLog);
if (vertexShader == 0)
return 0;
fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource, errorLog);
if (fragmentShader == 0)
return 0;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &linkSuccess);
if (!linkSuccess)
{
glGetProgramInfoLog(shaderProgram, ERROR_LOG_BUFFER_SIZE, nullptr, errorLogBuffer);
glDeleteProgram(shaderProgram);
errorLog = errorLogBuffer;
return 0;
}
return shaderProgram;
}
int main(int argc, char *argv[])
{
GLFWwindow *window = setupWindow();
std::string errorLog = "";
GLuint shaderProgram = compileShaderProgram(vertexShaderSource, fragmentShaderSource, errorLog);
GLuint fbo = 0;
GLuint fboTexture = 0;
GLuint vao = 0;
GLuint vbo = 0;
GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
GLuint indicesBuffer = 0;
GLushort indices[] = { 0,1,2, 3,4,5 };
GLfloat vertices[] = {
// Bottom triangle (first triangle drawn)
-0.5f, +0.0f,
+0.5f, +0.0f,
+0.0f, +0.5f,
// Top triangle (second triangle drawn, partially ON the first one, and slighly above it)
-0.5f, +0.2f,
+0.5f, +0.2f,
+0.0f, +0.8f,
};/*
** Setup FBO
*/
glEnable(GL_TEXTURE_2D);
glGenFramebuffers(1, &fbo);
glGenTextures(1, &fboTexture);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindTexture(GL_TEXTURE_2D, fboTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 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);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTexture, 0);
glDrawBuffers(sizeof(drawBuffers) / sizeof(GLenum), drawBuffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return EXIT_FAILURE;/*
** Setup VAO and VBO
*/
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &indicesBuffer);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);/*
** Main loop
*/
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
/*
** Draw first triangle in FBO (not on screen)
*/
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
glUseProgram(0);/*
** Copy the read framebuffer to the draw framebuffer (= on screen)
*/
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, WIDTH, HEIGHT);
glBlitFramebuffer(0, 0, WIDTH, HEIGHT, 0, 0, WIDTH, HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);/*
** Draw the second triangle directly on screen
*/
glUseProgram(shaderProgram);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<const void*>(3 * sizeof(GLushort)));
glUseProgram(0);/*
** Swap buffers
*/
glfwSwapBuffers(window);
}/**
** Free resources
*/
glDeleteBuffers(1, &indicesBuffer);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(shaderProgram);
glfwTerminate();return 0;
}
glTexImage2DMultisample()
сделать мультисэмплинг. Но даже если я использую FBO, я использую glTexImage2D()
вместо glTexImage2DMultisample()
, Так?Кроме того, я не совсем понимаю как uniform sampler2D renderedTexture;
в моем фрагменте шейдер работает. Я думал, что мне нужно сделать что-то вроде:
GLuint texID = glGetUniformLocation(shaderProgram, "renderedTexture");
glUniform1i(texID, 0);
установить единую переменную, но я не сделать это, и это работает. Зачем?
Наконец, вы можете спросить, почему я хочу сделать все это. Ну, так как я только начал изучать OpenGL, я делаю это как «упражнение» для решения моей настоящей проблемы: написать текст на изображении в цвете с достаточным контрастом, чтобы его можно было прочитать (например: если вы хотите написать какой-нибудь текст на белой стене, напишите его черным, а не белым, или вы его не увидите).
Задача ещё не решена.
Других решений пока нет …