シェーダで普通のシェーディングをする

本物のページはこちら→shading

Included page "glsl:shading" does not exist (create it now)

shading.png

概要

シェーディングするには、基本的に

の色をそれぞれ求めて、最後足し算diffuse+ambient+specularするのが常套手段だ。
光の成分に関して、すっごく雑に説明してしまったけど、

それぞれの反射強度の計算のしかたまとめ

それぞれの求め方を表にまとめると

diffuse max(dot(光のベクトル,法線),0)
ambient 物質の色そのままのことが多い
specular pow(max(dot(反射ベクトル,視線ベクトル),shiniess)

ambientに関しては、そんなに特殊な計算は要らない。そのままでいい。
なぜか?
色は光がないと黒にしか見えない。
そもそも色っていうのは、物体に光があたって、光の中の特定の成分だけ反射した結果色に見えるのだ。
たとえば、ある物体が赤に見えるなら、
その物体は赤い波長だけを反射して
あとの残りの青だの緑だのという波長はすべて吸収してしまう物体だってことだ。

ソースコード

フルソースコードはgitで!

頂点シェーダ

varying vec3 v_lightvec;
varying vec3 v_cam;
varying vec3 v_normal;
void main(){
 
    vec4 pos = gl_ModelViewMatrix * gl_Vertex;  // 頂点位置
    gl_Position =gl_ProjectionMatrix *pos;
    v_cam =normalize(pos.xyz);          // 視線ベクトル
    v_normal=normalize(gl_NormalMatrix *gl_Normal);//gl_NormalMatrixをかけ算しないと、光の位置がオブジェクトについてくるように見える
    v_lightvec=normalize(gl_LightSource[0].position.xyz - pos);z;
}

フラグメントシェーダ

vec3 shading(vec3 _normal,vec3 _viewvec,vec3 _lightpos){
 
    vec3 ambient=gl_LightSource[0].ambient*gl_FrontMaterial.ambient;
    float diffuse_intensity=max(dot(_lightpos,_normal),0);//光源の拡散反射強度
    vec3 diffuse=gl_LightSource[0].diffuse*gl_FrontMaterial.diffuse*diffuse_intensity;
 
    if(diffuse_intensity<=0){//もし光の方向ベクトル・法線の内積が0以下だったら鏡面反射は発生しない。
        return ambient+diffuse;
    }else{//光の方向ベクトル・法線の内積が0より大きい場合だけ鏡面反射が発生する
        vec3 reflection = normalize(_lightpos-_viewvec);
        float specular_intensity=pow(max(dot(reflection,_normal),0),gl_FrontMaterial.shininess);
        vec3 specular=gl_LightSource[0].specular*gl_FrontMaterial.specular*specular_intensity;
        return ambient+diffuse+specular;
    }
}
varying vec3 v_normal;
varying vec3 v_cam;
varying vec3 v_lightvec;//モデルビュー変換する必要があるのでvarying変数にする
    void main() {  
        //vec3 v_lightpos=vec3(0.5,0.5,2.4);
        gl_FragColor=vec4(shading(v_normal,v_cam,v_lightvec),1.0);
 
    }

普通にシェーダ無しでかくよりもかなり面倒くさく複雑になる。
なんでわざわざこんなことしなきゃいけないの?
と思うかもしれない。
しかし、のちのち、シェーダコードないで自分なりのシェーディングの実装をするための基礎にすぎないのだ!

使用するGLSLの組み込みユニフォーム変数

しばらく見ないうちに、使えるユニフォーム変数が増えてびっくり!
便利になったもんだ。
光のプロパティをまとめて管理してくれている構造体。

struct gl_LightSourceParameters {
 vec4 ambient; // Acli GL_AMBIENT
 vec4 diffuse; // Dcli GL_DIFFUSE 光源強度の拡散反射成分
 vec4 specular; // Scli GL_SPECULAR
 vec4 position; // Ppli GL_POSITION
 vec4 halfVector; // Derived: Hi
 vec3 spotDirection; // Sdli
 float spotExponent; // Srli
 float spotCutoff; // Crli
 // (range: [0.0,90.0], 180.0)
 float spotCosCutoff; // Derived: cos(Crli)
 // (range: [1.0,0.0],-1.0)
 float constantAttenuation; // K0
 float linearAttenuation; // K1
 float quadraticAttenuation;// K2
};
uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];

CPU側 シェーダ デフォルト値
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient); gl_LightSource[0].ambient (0.0,0.0,0.0,1.0)
glLightfv(GL_LIGHT0,GL_DIFFUSE,position); gl_LightSource[0].diffuse (1.0,1.0,1.0,1.0)
glLightfv(GL_LIGHT0,GL_SPECULAR,specular); gl_LightSource[0].specular (0.0,0.0,0.0,1.0)
glLightfv(GL_LIGHT0,GL_POSITION,position); gl_LightSource[0].position (0.0,0.0,1.0,0.0)

素材(マテリアル)の反射プロパティ

struct gl_MaterialParameters {
 vec4 emission; // Ecm
 vec4 ambient; // Acm
 vec4 diffuse; // Dcm 物体の拡散反射係数
 vec4 specular; // Scm
 float shininess; // Srm
};
uniform gl_MaterialParameters gl_FrontMaterial;
uniform gl_MaterialParameters gl_BackMaterial;

CPU側 シェーダ デフォルト値
glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission); gl_FrontMaterial.emission (0.0,0.0,0.0,1.0)
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); gl_FrontMaterial.ambient (0.2,0.2,0.2,1.0)
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); gl_FrontMaterial.diffuse (0.8,0.8,0.8,1.0)
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); gl_FrontMaterial.specular (0.0,0.0,0.0,1.0)
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shiness); gl_FrontMaterial.shininess 0.0

ちなみにすべてデフォルト値でやったらこんな具合になりました
default_lighting.png

gl_LightProducts

光源強度と反射係数の積

gl_LightSource[0]* gl_FrontMaterial

ということ。

struct gl_LightProducts {
 vec4 ambient; // Acm * Acli
 vec4 diffuse; // Dcm * Dcli
 vec4 specular; // Scm * Scli
};
uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];
uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];

CPU側 シェーダ デフォルト値
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
gl_FrontLightProduct[0].ambient (0.0,0.0,0.0,1.0)
glLightfv(GL_LIGHT0,GL_DIFFUSE,position);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
gl_FrontLightProduct[0].diffuse (1.0,1.0,1.0,1.0)
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
gl_FrontLightProduct[0].specular (0.0,0.0,0.0,1.0)

参考にした本

サポートサイト Wikidot.com shader