2017-08-09 3 views
0

最後の数日間、私はJava(Libgdx)で稲妻で遊んでいました。私はOpenGLやShadersを初めて使っています。普通のマッピング(https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson6)でライティングを実装する方法については、チュートリアルを見つけました。今まで私は1つのライトでこれをやっていましたが、今は複数のライトで同じ効果を出そうとしています。私は、追加のブレンドを使用して各ライトに対して1回の描画呼び出しを実行しようとしました。影は正しく描画されていますが、ライトを追加するたびに周囲の色が明るくなります。私はいくつかのことを試みたが、何も働かず、私は立ち往生している。ライトが追加されると周囲光が明るくなります(OpenGL、ノーマルマッピング)

レンダリングマイ方法:ここ

@Override 
public void render() { 
    renderToFbo(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY()); 
    renderToScreen(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY()); 

    renderToFbo(200, 200); 
    batch.setBlendFunction(GL_ONE,GL_ONE_MINUS_SRC_COLOR); 
    renderToScreen(200,200); 

    renderToFbo(500, 500); 
    batch.setBlendFunction(GL_ONE, GL_ONE_MINUS_SRC_COLOR); 
    renderToScreen(500,500); 
} 


private void renderToFbo(float posX, float posY){ 
    fbo.begin(); 
    batch.setBlendFunction(GL_ONE, GL_ZERO); 
    batch.setShader(defaultShader); 
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 
    batch.begin(); 
    batch.draw(lightMap, posX - lightSize/2, posY - lightSize/2, lightSize,lightSize); 
    batch.end(); 
    fbo.end(); 
} 

private void renderToScreen(float posX, float posY){ 
    batch.setShader(lightningShader); 
    batch.begin(); 

    float x = posX/(float) Gdx.graphics.getWidth(); 
    float y = posY/(float) Gdx.graphics.getHeight(); 
    LIGHT_POS.x = x; 
    LIGHT_POS.y = y; 

    lightningShader.setUniformf("lightPos", LIGHT_POS.x, LIGHT_POS.y, LIGHT_POS.z); 

    fbo.getColorBufferTexture().bind(2); 
    normalMap.bind(1); 
    texture.bind(0); 

    batch.draw(texture, 0,0); 
    batch.end(); 
} 

そして、私のフラグメントシェーダ:

varying vec4 vColor; 
varying vec2 vTexCoord; 
uniform sampler2D u_texture; //diffuse map 
uniform sampler2D u_normals; //normal map 
uniform sampler2D u_light;  //light map 

uniform vec2 resolution;  //resolution of screen 
uniform vec3 lightPos;  //light position, normalized 
uniform vec4 lightColor;  //light RGBA -- alpha is intensity 
uniform vec4 ambientColor; //ambient RGBA -- alpha is intensity 


void main() { 
//RGBA of our diffuse color 
vec4 diffuseColor = texture2D(u_texture, vTexCoord); 

//RGB of our normal map 
vec3 normalMap = texture2D(u_normals, vTexCoord).rgb; 
//NormalMap.g = 1.0 - NormalMap.g; 

//The delta position of light 
vec3 lightDir = vec3(lightPos.xy - (gl_FragCoord.xy/resolution.xy), lightPos.z); 

lightDir.x *= resolution.x/resolution.y; 


//normalize our vectors 
vec3 N = normalize(normalMap * 2.0 - 1.0); 
vec3 L = normalize(lightDir); 

//Pre-multiply light color with intensity 
//Then perform "N dot L" to determine our diffuse term 
vec3 diffuse = (lightColor.rgb * lightColor.a) * max(dot(N, L), 0.0); 

//pre-multiply ambient color with intensity 
vec3 ambient = ambientColor.rgb * ambientColor.a; 

//calculate attenuation from lightmap 
vec2 lighCoord = (gl_FragCoord.xy/resolution.xy); 
vec3 attenuation = texture2D(u_light, lighCoord).rgb; 

//the calculation which brings it all together 
vec3 intensity = ambient + diffuse * attenuation; 
vec3 finalColor = diffuseColor.rgb * intensity; 
gl_FragColor = vColor * vec4(finalColor, diffuseColor.a); 
} 
+0

それは、周囲光のあなたの定義に依存します。それぞれの光源が周囲光を「放射」する場合、この動作は完全に良好です。アンビエントライトが特殊なものであれば、一度しか追加しないと、ライトシェーダから完全に削除し、別の描画コール/シェーダで追加する必要があります。コメントと同じように、光源ごとに1回ずつすべてのジオメトリをレンダリングする方法は非常に非効率的です。 1つのシェーダで均一な配列を使用することを検討してください。そしてオーストリア人は何も悪いことはありません:) – BDL

+0

あなたの素早い返答をありがとう:)私はちょうどシェーダから環境光を削除しました。他のシェーダを使用せずに、今すぐ実装する方法はありますか? – Quentin

+0

できません。周囲の光を出力して一度しか使用しない第2のシェーダを作成します。最初のコメントでは、オブジェクトが正しく構成されていない可能性があるため、スクリーンスペースにオブジェクトが重なっていると、アルゴリズムに問題が発生する可能性があります。 – BDL

答えて

0

。これを行うには、単一の描画コールでは、あなたのフラグメントシェーダは、処理するために、光位置の配列を受け入れなければなりません。シェーダはコンパイル時に配列のサイズを知っていなければならないので、必要な数のライトに十分な大きさの配列を設定する必要があります(必要な数が少ない場合は残りのライトを黒に設定できます)。

あなたのコードで上で正しく動作していると仮定して、私はあなたのシェーダを以下のように改造しました。私はあなたがライトマップのもので何をしているのか分からないので、あなたの減衰計算をより伝統的なものに置き換えました。あなたのシェーダにあなたの光パラメータを渡すために

varying vec4 vColor; 
varying vec2 vTexCoord; 
uniform sampler2D u_texture; //diffuse map 
uniform sampler2D u_normals; //normal map 

const int LIGHT_COUNT = 4; 

uniform vec2 resolution;  //resolution of screen 
uniform vec3[LIGHT_COUNT] lightPos;  //light position, normalized 
uniform vec4[LIGHT_COUNT] lightColor;  //light RGBA -- alpha is intensity 
uniform vec4 ambientColor; //ambient RGBA -- alpha is intensity 

void main() { 

    vec4 diffuseColor = texture2D(u_texture, vTexCoord); 
    vec3 normalMap = texture2D(u_normals, vTexCoord).rgb; 
    vec3 N = normalize(normalMap * 2.0 - 1.0); 

    float resolutionFactor = resolution.x/resolution.y; 

    vec3 diffuse = new vec3(0.0); 
    for (int i=0; i<LIGHT_COUNT; i++){ 
     vec3 lightDir = vec3(lightPos[i].xy - (gl_FragCoord.xy/resolution.xy), lightPos[i].z); 
     lightDir.x *= resolutionFactor; 
     vec3 L = normalize(lightDir); 
     float distance = length(lightDir); 
     vec3 attenuation = 1.0/(0.4 + 3.0*distance + (20.0*distance*distance)); 
     diffuse += attenuation * (lightColor[i].rgb * lightColor[i].a) * max(dot(N, L), 0.0); 
    } 

    //pre-multiply ambient color with intensity 
    vec3 ambient = ambientColor.rgb * ambientColor.a; 


    //the calculation which brings it all together 
    vec3 intensity = min(vec3(1.0), ambient + diffuse); // don't remember if min is critical, but I think it might be to avoid shifting the hue when multiple lights add up to something very bright. 
    vec3 finalColor = diffuseColor.rgb * intensity; 
    gl_FragColor = vColor * vec4(finalColor, diffuseColor.a); 

} 

static final int LIGHT_COUNT = 4; 
final float[] tmpLightPositions = new float[3 * LIGHT_COUNT]; 
final float[] tmpLightColors = new float[4 * LIGHT_COUNT]; 

//... 

int i = 0; 
for (Vector3 pos : myLightPositions) {// should be LIGHT_COUNT of them 
    tmpLightPositions[i++] = pos.x; 
    tmpLightPositions[i++] = pos.y; 
    tmpLightPositions[i++] = pos.z; 
} 
i = 0; 
for (Color col : myLightColors) { 
    tmpLightColors[i++] = color.r; 
    tmpLightColors[i++] = color.g; 
    tmpLightColors[i++] = color.b; 
    tmpLightColors[i++] = color.a; 
} 
shader.setUniform3fv("lightPos", tmpLightPositions, 0, tmpLightPositions.length); 
shader.setUniform4fv("lightColor", tmpLightColors, 0, tmpLightColors.length); 
+0

ありがとうございました:)そのうまく動作します。 – Quentin

関連する問題