トゥーン風味

ousttrue2008-02-17

PhongとかBlinnをとばしてトゥーンをやってみた。
意外と簡単。
トゥーン用テクスチャを動的に生成したり
陰の合成をグレイスケールの乗算じゃなくて
PhotoShopの焼き込みみたいな合成ができるとよろしいかもしれない。
さらにはシャドウが欲しいところであります。

Vertex Shader
void main(){
  gl_Position = ftransform();
  gl_FrontColor=gl_Color;

  // トゥーン用に法線からテクスチャ座標を計算する
  // 法線
  vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
  // 頂点から光源への方向ベクトル
  vec3 light = normalize(gl_LightSource[0].position.xyz);
  // 視線(0, 0, 0)から頂点への方向ベクトル
  vec3 eye = normalize(vec3(gl_ModelViewMatrix * gl_Vertex));
  // 内積
  float lgtdot = dot(light, normal);
  float eyedot = dot(eye, normal);
  // テクスチャ座標に割り当てる
  gl_TexCoord[0].s = lgtdot*0.5+0.5; // スクリーン座標(-1〜+1)からテクスチャ座標(0〜1)に変換
  gl_TexCoord[0].t = eyedot*0.5+0.5; // スクリーン座標(-1〜+1)からテクスチャ座標(0〜1)に変換
}
Fragment Shader
uniform sampler2D toontex;

void main(){
  vec4 color = texture2D(toontex, gl_TexCoord[0].st);
  gl_FragColor = color * gl_Color;
}

toontexにテクスチャユニット0を結び付けている。
順番的にテクスチャ生成、シェーダプログラム生成、Uniform変数設定の順番でやらないとうまくいかなかった。

Shaderの外でシェーダと関連するところ

テクスチャ読み込み
  improt Image # PIL

  glPixelStorei(GL_UNPACK_ALIGNMENT,1)
  texture=glGenTextures(1)
  # 0
  glBindTexture(GL_TEXTURE_2D, texture)
  # settings
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
  # 画像読み込み
  image=Image.open(file)
  if len(image.getbands())!=4: image=image.convert("RGBA")
  size=image.size
  # テクスチャ生成
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, image.tostring())

テクスチャユニット0(デフォルト)にテクスチャオブジェクトを作成

Uniform変数の定義
  # シェーダ変数
  texLoc = glGetUniformLocation(program, "toontex")
  if texLoc==-1:
    print "no active uniform variable"
  glUniform1i(texLoc, 0); # シェーダ変数にテクスチャユニット0を結びつける

テクスチャユニットとuniform変数"toontex"を結びつける