2010-04-29 37 views
1

如果我有OpenGL紋理,並且我需要在渲染紋理之前對其執行HSL修改,從我聽說我需要着色器開始。問題是,我對着色器一無所知。有誰知道我需要看什麼?如何在紋理上執行HSL轉換?

我想寫一個函數,我可以傳遞紋理和三個值,度數的色調偏移以及0和2之間的飽和度和亮度倍數,然後讓它調用着色器,將這些變換應用於它呈現之前的紋理。該界面將是這個樣子:

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

我不知道什麼是應該去的例程中,雖然。我理解HSL/RGB轉換中涉及的基本數學知識,但我不知道如何編寫着色器或如何應用它。有人能指引我朝着正確的方向嗎? Delphi的例子是首選,但如果必須的話,我也可以讀C語言。

回答

4

這是相當複雜的,如果你是着色器和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 s和/或ARB s處打耳光。

如果你願意順着這條道路走下去,不要猶豫,隨時發表評論來描述你遇到的問題。我很樂意提供幫助!

+0

哇!你在那裏做了一些不錯的工作:)我懶得寫出來;) – Danvil 2010-04-30 15:24:31

2

寫一個着色器並不像聽起來那麼難。你應該看看像Cg或HLSL ......基本上,你最終會寫一個函數來獲取一個像素並進行轉換。

The CG Tutorial

一旦你着色器寫,你會加載與OpenGL擴展功能綁定。當您將幾何體推入管道時,它將由光柵器應用。下面是一個簡單的教程,展示瞭如何編寫和使用一個非常基本的着色器:

Tutorial - Cg Pixel Shaders in OpenGL

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硬件上進行測試,以確保它們正常工作。

+0

不幸的是,這確實需要實時完成。能夠預渲染它會很好,但那不行。 – 2010-04-29 20:31:02

1

使用紋理渲染:

  1. 與源紋理texRgb的大小
  2. 設置使用orthogonal projection
  3. 創建texHSL的大小視口創建一個新的(目標)質地texHSL和綁定framebuffer並使用紋理texHSL作爲渲染目標
  4. 使用着色器渲染屏幕尺寸四邊形(可能較大)。爲着色器綁定texRgb使用均勻
  5. 着色器reads the texture value for the currently rendered value(由回答有看到),計算RGB-> HSL轉化率和HSL值寫入gl_FragColor
  6. 拆散和刪除幀緩衝
  7. 瞧,轉換後圖像是在texHSL
+0

在步驟3和6中,「渲染緩衝區」是指「幀緩衝區對象」? – Thomas 2010-04-30 11:06:04

+0

謝謝,更新它。 – Danvil 2010-04-30 11:58:44