TOTAL:2746, TODAY:512

GLSLのQualifier変数タイプ

GLSLは日本語の教科書がまだ少ないので、分かったことを書いておこうと思っていました。今回は、GLSLで初めてプログラムする場合、分かりにくい点の一つに変数のQuailifierプリフィックスがあるので、簡単に説明します。GLSLで使用される変数タイプにおいて、C言語等にはない種類としてQualifier(日本語でなんと訳せばよいのかよく分かりません)があります。C言語にないのは当たり前で、シェーダ間、及びシェーダ-OpenGL間で渡す変数のタイプ宣言だからです。GLSLの仕様書や分厚い英語のリファレンスを見ると、次に示す4種類のQualifier変数があります。

attribute OpenGLプログラムから渡す変数です。
頂点ごとに変化する値を渡すことができます。ビルトインのattribute変数としては、gl_Vertex, gl_Normalなどがあります。ユーザ独自の頂点ごとに変化するデータを用意し、シェーダに渡すことが可能です。
バーテックスシェーダでしか使用できません。
uniform OpenGLプログラムから渡す変数です。
描画プリミティブごとに渡すことができます。ビルトインのuniform変数としては、sampler2D, samplerCubeなどがあります。
バーテックスシェーダ、フラグメントシェーダの両方で使用できます。
varing バーテックスシェーダからフラグメントシェーダに渡す変数です。
バーテックスシェーダとフラグメントシェーダの両方で宣言します。
const コンパイル時に定数として処理されるコンスタント変数です。
シェーダの中で変数の値を変更することはできません。

使い方ですが、シェーダプログラムにおいて、Qualifier変数は関数の外で宣言するため、C言語で言うところのグローバル変数のような感じです。

// vertex shader

attribute vec3 tangent;
uniform float angle;
varying vec3 normal;
const int numLights = 3;

void main(void)
{
    position = vec3(gl_ModelViewMatrix * gl_Vertex);
    normal = gl_NormalMatrix * gl_Normal;
    :   : 途中略 :   :
}
// fragment shader

uniform sampler2D texture;
varying vec3 normal;

void main(void)
{
    vec4 color = texture2D(texture, gl_TexCoord[0].st);
    vec3 fnormal = normalize(normal);
    :   : 途中略 :   :
}

uniform変数のOpenGLからの渡し方は次のようになります。uniform変数の場合、glGetUniformLocationを使用して、シェーダプログラムから変数名によりその変数番号を取得し、glUniform関数で値をセットすることでシェーダに渡すことが可能です。変数の要素数や型に応じて、glUniform****の部分を変える必要があります。

/* シェーダプログラムの適用 */
glUseProgram(shdProg);

/* バーテックスシェーダのunform変数angleに値をセット */
angleIdx = glGetUniformLocation(shdProg, "angle");
glUniform1f(angleIdx, 20.0f);   <- float変数のため、glUniform1fを使用

/* フラグメントシェーダのunform変数textureに値をセット */
textureIdx = glGetUniformLocation(shdProg, "texture");
glUniform1i(textureIdx, 0);     <- テクスチャの場合、ユニット番号を指定

一方、attriubte変数の場合、次のようにglGetAttribLocationを使用します。uniform変数同様、シェーダプログラムから変数名によりその変数番号を取得します。その後、頂点配列や頂点バッファを使用してデータを渡す場合、glEnableVertexAttribArrayで有効にし、glVertexAttribPointerで要素数、型、ストライド、データへのポインタ等を指定します。

/* シェーダプログラムの適用 */
glUseProgram(shdProg);

/* バーテックスシェーダのattribute変数tangentに頂点データを渡す */
tangentLoc = glGetAttribLocation(shdProg, "tangent");
glEnableVertexAttribArray(tangentLoc);
glVertexAttribPointer(tangentLoc, 3, GL_FLOAT, GL_FALSE, 0, lpData);

glVertexAttribPointerは引数が多くややこしいですが、次のような関数プロトタイプです。

void glVertexAttribPointer(
    GLuint  index,          /* glGetAttributeLocationで得られる変数番号 */
    GLint   size,           /* 要素数 1,2,3,4のいずれか */
    GLenum  type,           /* データの型 */
    GLboolean  normalized,  /* 整数型データの場合、正規化するかどうか */
    GLsizei  stride,        /* 頂点データのストライド */
    const GLvoid *pointer   /* 頂点データへのポインタ(オフセット) */
); 

4番目の引数normalizedは、glVertexPointer等でも見慣れない引数ですが、頂点データが整数型の場合に、正規化([-1,1]や[0,1]への正規化)して渡すか、そのまま渡すかを指定するものです。例えば、データを節約するために、float型ではなく、short型のデータで[-1,1]の範囲の座標を渡したい場合に有効です。また、頂点配列や頂点バッファを使用せずに頂点データを渡す場合、glVertexAttribを使用します。詳しくはリファレンスを見てください。

最新の7件

OpenGL

電子工作

玄箱HG

ホームページ

日記

Copyright (C) 2007 Arakin , All rights reserved.