2010-04-29 4 views
1

OpenGL 텍스처가 있고 텍스처를 렌더링하기 전에 HSL 수정을 수행해야한다고 들었을 때 쉐이더가 필요합니다. 문제는 쉐이더에 대해 아무것도 모른다는 것입니다. 누구든지 내가 볼 필요가있는 곳을 알고 있습니까?텍스처에서 HSL 변환을 수행하려면 어떻게해야합니까?

텍스쳐와 3 가지 값, 도의 색조 변화, 0과 2 사이의 채도 및 명도 승수를 전달할 수있는 함수를 작성한 다음이 변환을 적용 할 셰이더를 호출하게합니다. 텍스처가 렌더링되기 전에 인터페이스는 다음과 같이 보일 것입니다 :

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

그래도 난, 루틴 내부에 가기로되어 있는지 모른다. HSL/RGB 변환과 관련된 기본 수학은 이해하지만 셰이더 작성법이나 적용 방법을 알지 못합니다. 누군가 올바른 방향으로 나를 가리킬 수 있습니까? 델파이 예제 선호하지만, C 언어도 읽을 수 있습니다.

답변

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을 여기 저기에 두 드리십시오.

이 도로를 내려 가려고해도 문제가 해결되지 않으면 주저하지 말고 문제를 설명하는 설명을 게시하십시오. 기꺼이 도와 드리겠습니다.

+0

와우! 거기서 멋진 일을 했어. 나는 그것을 쓰기에는 너무 게을 렀다;) – Danvil

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

불행히도 실시간으로 처리해야합니다. 그것을 prerender 수있는 ​​것이 좋겠지 만, 그것은 작동하지 않습니다. –

1

:

  • orthogonal projection
  • 만들기 사용 texHSL의 크기의 뷰포트를 설정 소스 텍스처 texRgb의 크기의 새 (대상) 텍스처 texHSL 만들기

    1. framebuffer을 바인딩하고 렌더링 대상으로 텍스처 texHSL을 사용하십시오.
    2. 쉐이더를 사용하여 화면 크기를 4 배 (더 클 수 있음) 렌더링하십시오. 쉐이더 바인드를 들어 texRgb는 RGB-> HSL 변환을 계산하고
    3. 바인딩 해제 gl_FragColor에 HSL 값을 기록하고 프레임 버퍼
    4. 짜잔을 삭제, 균일 한
    5. reads the texture value for the currently rendered value가 (이 대답에 의해 참조) 쉐이더를 사용하여 변환 이미지가 texHSL에 있습니다
  • +0

    3, 6 단계에서 "렌더 버퍼"는 "프레임 버퍼 객체"를 의미합니까? – Thomas

    +0

    감사합니다. 업데이트했습니다. – Danvil