代码之家  ›  专栏  ›  技术社区  ›  Mason Wheeler

如何对纹理执行HSL变换?

  •  1
  • Mason Wheeler  · 技术社区  · 14 年前

    我想写一个函数,在这里我可以传递一个纹理和三个值,一个色相偏移度,饱和度和亮度乘数在0到2之间,然后让它调用一个着色器,在它渲染之前将这些变换应用到纹理。界面如下所示:

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

    不过,我不知道该怎么做。我理解HSL/RGB转换中涉及的基本数学,但我不知道如何编写着色器或如何应用它。有人能给我指出正确的方向吗?德尔福的例子首选,但我也可以阅读C如果我必须的。

    4 回复  |  直到 14 年前
        1
  •  4
  •   Community rohancragg    7 年前

    这是相当复杂的,如果你是新的着色器和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.0opengl之前的版本,您需要首先加载适当的扩展,然后添加一些 EXT s和/或 ARB

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

        2
  •  2
  •   dicroce    14 年前

    The CG Tutorial

    一旦编写了着色器,就可以用OpenGL扩展函数加载并绑定它。当您将几何体推入管道时,它将由光栅化器应用。下面是一个简单的教程,演示如何编写和使用非常基本的着色器:

    Tutorial - Cg Pixel Shaders in OpenGL

        3
  •  1
  •   Ville Krumlinde    14 年前

      //Get copy of pixels. P is a pointer to floats (^single)
      GetMem(P,TextureHeight * TextureWidth * 4 * SizeOf(single));
      glGetTexImage(GL_TEXTURE_2D,0,GL_RGBA,GL_FLOAT,P);
      ... loop and modify pixels here. 4 float values per pixels: Red, green, blue and alpha
      //Update texture with modified pixels
      glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureWidth, TextureHeight , 0, GL_RGBA, GL_FLOAT, P);
      FreeMem(P);
    

    如果要使用字节而不是浮点,可以使用GL\u UNSIGNED\u BYTE。

        4
  •  1
  •   Community rohancragg    7 年前

    使用“渲染到纹理”(render to texture):

    1. 使用源纹理texRgb的大小创建新的(目标)纹理texHSL
    2. 使用 orthogonal projection
    3. framebuffer 并使用纹理texHSL作为渲染目标
    4. 使用着色器渲染屏幕大小的四边形(可能更大)。对于着色器,使用统一的
    5. reads the texture value for the currently rendered value (参见此处的答案),计算RGB->HSL转换并将HSL值写入gl\u FragColor
    6. 瞧,你转换的图像是texHSL格式的