標準のOpenGLライティングの品質は非常に低いため、ピクセルベースのライティングは多くのOpenGLアプリケーションで共通の問題です。
GLSLプログラムを使用して、OpenGLプログラムで頂点単位ではなくピクセル単位のライティングを使用したいと考えています。拡散照明のみですが、少なくともフォグ、テクスチャ、テクスチャアルファを使用します。
私は このシェーダー から始めました:
texture.vert:
varying vec3 position;
varying vec3 normal;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
normal = normalize(gl_NormalMatrix * gl_Normal);
position = vec3(gl_ModelViewMatrix * gl_Vertex);
}
texture.frag:
uniform sampler2D Texture0;
uniform int ActiveLights;
varying vec3 position;
varying vec3 normal;
void main(void)
{
vec3 lightDir;
float attenFactor;
vec3 eyeDir = normalize(-position); // camera is at (0,0,0) in ModelView space
vec4 lightAmbientDiffuse = vec4(0.0,0.0,0.0,0.0);
vec4 lightSpecular = vec4(0.0,0.0,0.0,0.0);
// iterate all lights
for (int i=0; i<ActiveLights; ++i)
{
// attenuation and light direction
if (gl_LightSource[i].position.w != 0.0)
{
// positional light source
float dist = distance(gl_LightSource[i].position.xyz, position);
attenFactor = 1.0/( gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist );
lightDir = normalize(gl_LightSource[i].position.xyz - position);
}
else
{
// directional light source
attenFactor = 1.0;
lightDir = gl_LightSource[i].position.xyz;
}
// ambient + diffuse
lightAmbientDiffuse += gl_FrontLightProduct[i].ambient*attenFactor;
lightAmbientDiffuse += gl_FrontLightProduct[i].diffuse * max(dot(normal, lightDir), 0.0) * attenFactor;
// specular
vec3 r = normalize(reflect(-lightDir, normal));
lightSpecular += gl_FrontLightProduct[i].specular *
pow(max(dot(r, eyeDir), 0.0), gl_FrontMaterial.shininess) *
attenFactor;
}
// compute final color
vec4 texColor = gl_Color * texture2D(Texture0, gl_TexCoord[0].xy);
gl_FragColor = texColor * (gl_FrontLightModelProduct.sceneColor + lightAmbientDiffuse) + lightSpecular;
float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale; // Intensität berechnen
fog = clamp(fog, 0.0, 1.0); // Beschneiden
gl_FragColor = mix(gl_Fog.color, gl_FragColor, fog); // Nebelfarbe einmischen
}
このコードが投稿されたドイツのサイトなので、コメントはドイツ語です。申し訳ありません。
しかし、このシェーダーが行うことは、すべてを非常に暗くすることです。照明効果はまったくありません-シェーダーコードはコンパイルされます。フラグメントシェーダーでGL_LIGHT0のみを使用する場合、それは機能するように見えますが、カメラに面するポリゴンにのみ妥当であり、床のポリゴンは非常に暗いです。また、RGBAテクスチャを持つ四角形は、透明の兆候を示しません。 Modelviewマトリックスには標準のglRotate/Translateを使用し、ポリゴンにはglVertex/Normalを使用します。 OpenGLライティングは、非常に大きな表面で見栄えが悪いという事実は別として、うまく機能します。私は自分の法線をトリプルチェックしました、彼らは大丈夫です。
上記のコードに何か問題がありますか? ORこの実際のタスクに一般的なライティングシェーダーがない理由を教えてください(距離減衰を伴うポイントベースのライト:できればろうそく)-これを行う正しい方法は1つだけではありませんバンプ/通常/視差/トゥーン/ぼかし/どのようなエフェクトもしたくないのですが、大きなポリゴンでライティングのパフォーマンスを向上させたいだけです。
私が見つけたすべてのチュートリアルは、カメラがオブジェクトに直交して0,0,0を向いているときに1つのオブジェクトを照明する場合にのみ役立ちます。上記は、少なくとも私がやりたいことのように見える唯一のものです。
この記事 を読んで、GLSL内で標準のADSライトニングがどのように行われるかを確認することを強くお勧めします。つまり、GL 4.0ですが、バージョンに合わせて問題はありません:
また、ビュー(カメラ)空間で操作するため、DON "Tは目のベクトルを無効にします。
vec3 eyeDir = normalize(-position);
アイベクトルもビュースペースに変換されることを忘れて無視したので、私はあなたの問題とかなり似ていました。現在のシナリオでは、拡散と鏡面反射の計算も間違っているようです。あなたの場所では、固定パイプライン、それ以外の場合、シェーダーでそれを行うポイントは何ですか?これは、フラグメントごとのADSポイントライトニングで拡散と鏡面反射を計算する方法です。
void ads( int lightIndex,out vec3 ambAndDiff, out vec3 spec )
{
vec3 s = vec3(lights[lightIndex].Position - posOut) ;
vec3 v = normalize( posOut.xyz );
vec3 n = normalize(normOut);
vec3 h = normalize(v+s) ;// half vector (read in the web on what it is )
vec3 diffuse = ((Ka+ lights[lightIndex].Ld) * Kd * max( 0.0,dot(n, v) )) ;
spec = Ks * pow( max(0.0, dot(n,h) ), Shininess ) ;
ambAndDiff = diffuse ;
/// Ka-material ambient factor
/// Kd-material diffuse factor
/// Ks-material specular factor.
/// lights[lightIndex].Ld-lights diffuse factor;you may also add La and Ls if you want to have even more control of the light shading.
}
また、ここにある減衰式を使用することはお勧めしません。制御が困難です。光半径ベースの減衰を追加する場合 この素敵なブログ投稿があります: