如果我有一个OpenGL纹理,我需要在渲染纹理之前对它进行HSL修改,从我听到的我需要一个着色器。问题是,我对着色器一无所知。有谁知道我需要看哪里?
我想编写一个函数,我可以在其中传递一个纹理和三个值,一个度数的色调偏移,以及0到2之间的饱和度和亮度乘数,然后让它调用一个着色器,将这些变换应用于纹理呈现之前。界面看起来像这样:
procedure HSLTransform(texture: GLuint; hShift: integer; sMult, lMult: GLfloat);
我不知道该怎么回事程。我理解HSL / RGB转换中涉及的基本数学,但我不知道如何编写着色器或如何应用它。有人能指出我正确的方向吗? Delphi示例首选,但如果必须,我也可以阅读C.
答案 0 :(得分:4)
这是非常复杂的,如果你是着色器和FBO的新手,它需要一些时间来理解它。所以这里是一些实现Danvil's answer的最小的,未经测试的OpenGL代码。错误检查已被遗漏;这很复杂。如果多次调用此函数,则应该保留在此代码中创建的任何或所有对象。
如果你不关心速度,那么在CPU上运行的VilleK's answer就容易多了......
// 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
上点击。
如果您愿意沿着这条路走下去并且没有成功,请不要犹豫发表评论,描述您遇到的问题。我很乐意帮忙!
答案 1 :(得分:2)
编写着色器并不像听起来那么难。你应该研究像Cg或HLSL这样的东西...基本上,你最终会编写一个带有像素并转换它的函数。
编写着色器后,您将加载并使用OpenGL扩展函数绑定它。当您将几何体推入管道时,它将由光栅化器应用。这是一个简单的教程,展示了如何编写和使用一个非常基本的着色器:
答案 2 :(得分:1)
如果您不想使用着色器(即不需要实时),您可以获取纹理的像素并使用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硬件上进行测试,以确保它们正常工作。
答案 3 :(得分:1)
使用渲染到纹理: