c - 如何对纹理执行 HSL 变换?

标签 c delphi opengl shader glsl

如果我有一个 OpenGL 纹理,并且我需要在渲染纹理之前对其执行 HSL 修改,据我所知,我需要一个着色器。问题是,我对着色器一无所知。有谁知道我需要看哪里?

我想编写一个函数,我可以在其中传递一个纹理和三个值、以度数表示的色调偏移以及介于 0 和 2 之间的饱和度和亮度乘数,然后让它调用一个着色器,将这些转换应用到渲染前的纹理。界面看起来像这样:

procedure HSLTransform(texture: GLuint; hShift: integer; sMult, lMult: GLfloat);

不过,我不知道例程中应该包含什么。我了解 HSL/RGB 转换中涉及的基本数学,但我不知道如何编写着色器或如何应用它。有人能指出我正确的方向吗?首选 Delphi 示例,但如果需要,我也可以阅读 C。

最佳答案

这是相当复杂的,如果您是着色器和 FBO 的新手,则需要一些时间来理解它。所以这里有一些最小的、未经测试的 OpenGL 代码,它实现了 Danvil's answer。 .错误检查已被忽略;它已经够复杂了。如果多次调用此函数,则应保留在此代码中创建的任何或所有对象。

如果你不关心速度,VilleK's answer在 CPU 上运行要容易得多...

// Create the target texture object.
GLuint target;
glGenTextures(1, &target);

// Bind the target texture.
glBindTexture(GL_TEXTURE_2D, target);

// Allocate texture memory. width and height must be the size of the original texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

// Create a framebuffer object.
GLuint fbo;
glGenFramebuffers(1, &fbo);

// Bind the framebuffer object.
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

// Attach the target texture as the render target.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target, 0);

// Check framebuffer status.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    throw "Framebuffer incomplete.";

// Create fragment shader to do the transformation.
GLuint frag = glCreateShader(GL_FRAGMENT_SHADER);

// Set the shader's source code.
char const *source =
    "uniform sampler2D input;\n"
    "uniform float hShift, sMult, lMult;\n"
    "void main() {\n"
    "    vec4 color = texture2D(input, gl_FragCoord.xy);\n"
    "    /* Do your HSL transformations here... */\n"
    "    gl_FragColor = color;\n"
    "}\n";
glShaderSource(frag, 1, &source, 0);

// Compile the shader.
glCompileShader(frag);

// Check compilation result. Here, you probably want to use glGetShaderInfoLog() to get any compilation errors.
GLint status;
glGetShader(frag, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
    throw "Shader compilation failed";

// Create the program.
GLuint program = glCreateProgram();

// Attach the shader to the program.
glAttachShader(program, frag);

// Link the program.
glLinkProgram(program);

// Check link result. Here, you probably want to use glGetProgramInfoLog() to get any link errors.
glGetProgram(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
    throw "Program linking failed"

// Use the program for subsequent rendering.
glUseProgram(program);

// Set the values of the uniform parameters.
glUniform1i(glUniformLocation(program, "input"), 0);
glUniform1f(glUniformLocation(program, "hShift"), hShift);
glUniform1f(glUniformLocation(program, "sMult"), sMult);
glUniform1f(glUniformLocation(program, "lMult"), lMult);

// Bind the source texture to read from.
glBindTexture(GL_TEXTURE_2D, texture);

// Set up the viewport and matrices.
glPushAttrib(GL_VIEWPORT_BIT | GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, 1, 0, 1, 0, 1);
glViewport(0, 0, width, height);

// Render a quad.
glBegin(GL_QUADS);
glVertex2i(0, 0);
glVertex2i(1, 0);
glVertex2i(1, 1);
glVertex2i(0, 1);
glEnd();

// Restore the matrices and viewport.
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();

// Stop using the program.
glUseProgram(0);

// Stop using the framebuffer object.
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// Delete created objects.
glDeleteProgram(program);
glDeleteShader(frag);
glDeleteFramebuffers(1, &fbo);

// Optionally, delete the old, untransformed texture.
glDeleteTextures(1, &texture);

// Return the new texture.
return target;

希望对您有所帮助。对于 2.0 之前的 OpenGL,您需要先加载适当的扩展,然后在各处添加一些 EXT 和/或 ARB

如果您愿意走这条路,但没有成功,请不要犹豫,发表评论描述您遇到的问题。我很乐意提供帮助!

关于c - 如何对纹理执行 HSL 变换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2739406/

相关文章:

opengl - VBO状态调用的结构

c - 为什么这两个应该相同的指针指向不同的数据?

delphi - 如何将相对 PIDL 转换为绝对 PIDL?

c++ - 在具有多重采样的 QGLFramebufferObject 中使用 sRGB 颜色

delphi - 如何调试Delphi IDE?

delphi - 基于TInterfacedClass的Delphi插件框架的内存管理

OpenGL 早期深度测试不起作用

c - 对数组使用动态内存分配

c - 将 char 数组从 c 中的 scanf 传递给函数

通过套接字的 C 服务器-客户端通信 - 如何从服务器向客户端打印消息