1

OpenGL テクスチャがあり、テクスチャをレンダリングする前に HSL 変更を実行する必要がある場合、聞いたところによると、シェーダーが必要です。問題は、シェーダーについて何も知らないことです。私がどこを見る必要があるか知っている人はいますか?

テクスチャと 3 つの値、色相シフト (度単位)、彩度と明度の乗数 (0 ~ 2) を渡すことができる関数を作成し、その前にこれらの変換をテクスチャに適用するシェーダーを呼び出します。レンダリングします。インターフェイスは次のようになります。

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

しかし、ルーチンの中に何が入っているのかわかりません。HSL/RGB 変換に関連する基本的な計算は理解していますが、シェーダーの書き方や適用方法がわかりません。誰かが私を正しい方向に向けることができますか? Delphi の例が望ましいですが、必要に応じて C を読むこともできます。

4

4 に答える 4

4

これは非常に複雑で、シェーダーや FBO を初めて使用する場合は、理解するのに時間がかかります。したがって、 Danvilの答えを実装する、テストされていない最小限のOpenGLコードを次に示します。エラーチェックは省略されています。それはそのままで十分に複雑です。この関数を何度も呼び出す場合は、このコードで作成されたオブジェクトの一部またはすべてを保持する必要があります。

速度を気にしない場合は、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あちこちで平手打ちする必要があります。

この道をたどってもうまくいかない場合は、遭遇した問題を説明するコメントをためらわずに投稿してください。喜んでお手伝いします!

于 2010-04-30T11:44:01.683 に答える
2

シェーダーを書くことは、思ったほど難しくありません。Cg や HLSL などを調べる必要があります。基本的には、ピクセルを取得して変換する単一の関数を作成することになります。

CG チュートリアル

シェーダーが作成されたら、それをロードして OpenGL 拡張関数にバインドします。ジオメトリをパイプラインにプッシュすると、ラスタライザーによって適用されます。以下は、非常に基本的なシェーダーを作成して使用する方法を示す簡単なチュートリアルです。

チュートリアル - OpenGL の Cg ピクセル シェーダー

于 2010-04-29T18:07:33.170 に答える
1

テクスチャにレンダリングを使用します。

  1. ソーステクスチャtexRgbのサイズで新しい(ターゲット)テクスチャtexHSLを作成します
  2. 正射影を使用してtexHSLのサイズのビューポートを設定します
  3. フレームバッファを作成してバインドし、テクスチャtexHSLをレンダリングターゲットとして使用します
  4. シェーダーを使用して、画面サイズのクワッド(大きい場合があります)をレンダリングします。シェーダーの場合、ユニフォームを使用してtexRgbをバインドします
  5. シェーダーは、現在レンダリングされている値のテクスチャ値を読み取り(回答を参照)、RGB-> HSL変換を計算し、HSL値をgl_FragColorに書き込みます。
  6. フレームバッファのバインドを解除して削除します
  7. 出来上がり、変換された画像はtexHSLにあります
于 2010-04-30T11:02:12.073 に答える
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);

float の代わりにバイトを操作したい場合は、GL_UNSIGNED_BYTE を使用できます。

シェーダーよりもパフォーマンスは遅くなりますが、特に以前にシェーダーを作成したことがない場合は、シェーダーを作成するのが難しいため、おそらく短時間で作業を完了することができます。また、正しく動作することを確認するために、NVIDIA と ATI の両方のハードウェアでテストする必要があります。

于 2010-04-29T20:24:13.757 に答える