繁体   English   中英

如何对纹理执行HSL转换?

[英]How do I perform an HSL transform on a texture?

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

我想编写一个函数,在其中可以传递纹理和三个值,色相度变化以及0和2之间的饱和度和明度乘数,然后让它调用着色器,在此之前将这些转换应用于纹理渲染。 该界面如下所示:

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

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

这是相当复杂的,如果您不熟悉着色器和FBO,将需要一些时间来理解它。 因此,这里有一些最小的,未经测试的OpenGL代码,用于实现Danvil的答案 错误检查已被省略; 它是如此复杂。 如果多次调用此函数,则应保留此代码中创建的任何或所有对象。

如果您不在乎速度, 那么在CPU上运行的VilleK答案会容易得多 ...

// 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上打耳光。

如果您愿意走这条路,而且行不通,请毫不犹豫地发表评论,以描述您遇到的问题。 我很乐意为您服务!

编写着色器并不像听起来那样难。 您应该研究Cg或HLSL之类的东西...基本上,您将最终编写一个需要像素并对其进行转换的函数。

CG教程

编写完着色器后,将使用OpenGL扩展功能将其加载并绑定。 然后,当您将几何体推入管线时,它将由栅格化器应用。 这是一个简单的教程,显示了如何编写和使用非常基本的着色器:

教程-OpenGL中的Cg像素着色器

如果您不想使用着色器(即不需要实时),则可以获取纹理的像素并使用Delphi代码对其进行修改。 像这样:

  //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_UNSIGNED_BYTE。

它的性能将比着色器慢,但是您可能会在更少的时间内完成工作,因为着色器编写起来很棘手,尤其是如果您以前从未编写过着色器。 它们还需要在NVIDIA和ATI硬件上进行测试,以确保它们可以正常工作。

使用渲染进行纹理处理:

  1. 使用源纹理texRgb的大小创建一个新的(目标)纹理texHSL
  2. 使用正交投影设置texHSL大小的视口
  3. 创建并绑定帧缓冲区,并将纹理texHSL用作渲染目标
  4. 使用着色器渲染四边形(可能更大)的屏幕大小。 对于着色器,使用统一绑定texRgb
  5. 着色器读取当前渲染值的纹理值 (请参见答案),计算RGB-> HSL转换并将HSL值写入gl_FragColor
  6. 解除绑定并删除帧缓冲区
  7. 瞧,您转换后的图像在texHSL中

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM