在過去的幾天裏,我在Java(Libgdx)中玩閃電。我是新來的OpenGL或着色器,我偶然發現一個不錯的教程,如何使用法線貼圖(https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson6)實現照明。到目前爲止,我設法用一盞燈做到這一點,現在我試圖用多盞燈做同樣的效果。我試圖用添加劑混合對每個燈進行一次繪製調用。陰影繪製正確,但每次添加燈光時,環境顏色都變得更亮。我嘗試了一些東西,但沒有任何工作,我卡住了。添加燈光時,環境光線會變得更亮(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);
}
這取決於你的環境光的定義。如果每個光源「發出」環境光,那麼這種行爲就完全沒有問題。如果環境光是某種特殊的東西,只能添加一次,那麼它應該從光着色器中完全移除,並通過單獨的繪圖調用/着色器添加。就像一個評論一樣:每個光源渲染每個幾何圖形的方式效率非常低。考慮在一個着色器中使用統一數組。作爲奧地利人是沒有什麼不好的:) – BDL
感謝您的快速回復:)我剛剛從着色器中刪除了環境光線。我怎樣才能實現它,而不使用其他着色器? – Quentin
你不能;)。創建一個僅輸出環境光線並使用一次的第二個着色器。我應該在第一條評論中提到,如果屏幕空間中存在對象重疊,那麼您的算法可能會出現問題,因爲它們可能編寫不正確。 – BDL