[英]Why does this lighting code only work for single lights and break when I add multiple lights?
I'm trying to create a simple 2D game engine using lwjgl and java. 我正在尝试使用lwjgl和java创建一个简单的2D游戏引擎。 But I got stuck during the lighting programming, because the code I wrote only works when I have one light in the scene and not when I add multiple.
但是我在照明编程时陷入了困境,因为我编写的代码仅在场景中有一个光源时才起作用,而在添加多个光源时才起作用。 I just can't figure out why so i decided to ask here.
我只是不知道为什么,所以我决定在这里问。
This is the fragment shader with the lighting calculation: 这是带有光照计算的片段着色器:
#version 330 core
layout (location = 0) out vec4 color;
layout (origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;
in DATA {
vec2 tc;
} fs_in;
uniform sampler2D tex;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec3 lightColor = vec3(1, 1, 1);
float range = 700;
float x = 200;
float y = 200;
float ambient = 0.1;
float intensity = 0.8;
float alpha = 1.0;
vec3 totalDiffuse = vec3(0.0);
for(int i=0;i<1;i++){
alpha = 1-map(distance(gl_FragCoord.xy, vec2(x*i, y*i)), 0.0, range, 0.0, 1.0);
totalDiffuse += alpha*lightColor;
}
totalDiffuse = max(totalDiffuse, ambient);
color = vec4(totalDiffuse, 1.0) * texture(tex, fs_in.tc);
}
If I run this code with only one light in the scene, ie setting the times the for loop runs to 1, then it works just fine and creates something like this: 如果我仅在场景中使用一盏灯运行此代码,即将for循环的时间设置为1,则它工作正常,并创建如下内容:
But when I change it to loop for example 3 times, you would expect it to create 3 different lights, but actually it just increases the light intensity of the first light like this: 但是,当我将其更改为例如循环3次时,您会期望它会创建3个不同的灯光,但实际上,它只是增加了第一个灯光的光强度,如下所示:
Anybody know why? 有人知道为什么吗?
The result of the term 任期的结果
alpha = 1-map(distance(gl_FragCoord.xy, vec2(x*i, y*i)), 0.0, range, 0.0, 1.0);
can be negative. 可以为负。
This will cause that the totalDiffuse
is decreased. 这将导致
totalDiffuse
减少。
Clamp alpha
to a minimum of 0: 将
alpha
为最小0:
//totalDiffuse += alpha*lightColor;
totalDiffuse += max(0.0, alpha) * lightColor;
Note, the distance between the light sources is length(vec2(200, 200))
, but the illumination range (radius) of each light source is 700. So anyway the light sources are overlapping. 请注意,光源之间的距离为
length(vec2(200, 200))
,但是每个光源的照明范围(半径)为700。因此无论如何光源都是重叠的。
I recommend to use the glsl function smoothstep
, which performs a Hermite interpolation between two values. 我建议使用glsl函数
smoothstep
,该函数在两个值之间执行Hermite插值 。
Try the following: 请尝试以下操作:
for(int i=0; i<3; i++ )
{
vec2 pos = vec2(x, y) * float(i);
float dist = distance(gl_FragCoord.xy, pos);
alpha = smoothstep(50.0, 100.0, dist);
totalDiffuse += clamp(1.0-alpha, 0.0, 1.0) * lightColor;
}
in this case the 2nd parameter (100.0) to smoothstep
is the maximum radius of the light source and the 1st parameter (50.0) is the radius which is full lit. 在这种情况下,要
smoothstep
的第二个参数(100.0)是smoothstep
的最大半径,而第一个参数(50.0)是全光照的半径。
See the WebGL example, where I used smoothstep
: 请参阅WebGL示例,其中使用了
smoothstep
:
(function loadscene() { var canvas, gl, vp_size, prog, bufObj = {}; function initScene() { canvas = document.getElementById( "ogl-canvas"); gl = canvas.getContext( "experimental-webgl" ); if ( !gl ) return; progDraw = gl.createProgram(); for (let i = 0; i < 2; ++i) { let source = document.getElementById(i==0 ? "draw-shader-vs" : "draw-shader-fs").text; let shaderObj = gl.createShader(i==0 ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER); gl.shaderSource(shaderObj, source); gl.compileShader(shaderObj); let status = gl.getShaderParameter(shaderObj, gl.COMPILE_STATUS); if (!status) alert(gl.getShaderInfoLog(shaderObj)); gl.attachShader(progDraw, shaderObj); gl.linkProgram(progDraw); } status = gl.getProgramParameter(progDraw, gl.LINK_STATUS); if ( !status ) alert(gl.getProgramInfoLog(progDraw)); progDraw.inPos = gl.getAttribLocation(progDraw, "inPos"); progDraw.u_time = gl.getUniformLocation(progDraw, "u_time"); progDraw.u_resolution = gl.getUniformLocation(progDraw, "u_resolution"); gl.useProgram(progDraw); var pos = [ -1, -1, 1, -1, 1, 1, -1, 1 ]; var inx = [ 0, 1, 2, 0, 2, 3 ]; bufObj.pos = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos ); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( pos ), gl.STATIC_DRAW ); bufObj.inx = gl.createBuffer(); bufObj.inx.len = inx.length; gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx ); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( inx ), gl.STATIC_DRAW ); gl.enableVertexAttribArray( progDraw.inPos ); gl.vertexAttribPointer( progDraw.inPos, 2, gl.FLOAT, false, 0, 0 ); gl.enable( gl.DEPTH_TEST ); gl.clearColor( 0.0, 0.0, 0.0, 1.0 ); window.onresize = resize; resize(); requestAnimationFrame(render); } function resize() { //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight]; vp_size = [window.innerWidth, window.innerHeight]; //vp_size = [256, 256] canvas.width = vp_size[0]; canvas.height = vp_size[1]; } function render(deltaMS) { gl.viewport( 0, 0, canvas.width, canvas.height ); gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); gl.uniform1f(progDraw.u_time, deltaMS/2000.0); gl.uniform2f(progDraw.u_resolution, canvas.width, canvas.height); gl.drawElements( gl.TRIANGLES, bufObj.inx.len, gl.UNSIGNED_SHORT, 0 ); requestAnimationFrame(render); } initScene(); })();
<script id="draw-shader-vs" type="x-shader/x-vertex"> precision mediump float; attribute vec2 inPos; void main() { gl_Position = vec4( inPos.xy, 0.0, 1.0 ); } </script> <script id="draw-shader-fs" type="x-shader/x-fragment"> precision mediump float; uniform float u_time; uniform vec2 u_resolution; vec3 HUEtoRGB(in float H) { float R = abs(H * 6.0 - 3.0) - 1.0; float G = 2.0 - abs(H * 6.0 - 2.0); float B = 2.0 - abs(H * 6.0 - 4.0); return clamp( vec3(R,G,B), 0.0, 1.0 ); } void main() { vec2 uv = gl_FragCoord.xy / u_resolution; vec3 lightColor = vec3(1, 1, 1); float range = length(u_resolution) / 4.0; float x = u_resolution.x / 4.0; float y = u_resolution.y / 4.0; float ambient = 0.1; float intensity = 0.8; float alpha = 1.0; vec3 totalDiffuse = vec3(0.0); for(int i=0;i<3;i++) { vec2 pos = vec2(x, y) * float(i+1); float dist = distance(gl_FragCoord.xy, pos); alpha = smoothstep(range/4.0, range/2.0, dist); totalDiffuse += clamp(1.0-alpha, 0.0, 1.0) * lightColor; } totalDiffuse = max(totalDiffuse, ambient); vec4 texcol = vec4( 1.0-uv.x, 1.0-uv.y, uv.x*uv.y, 1.0 ); gl_FragColor = vec4(totalDiffuse, 1.0) * texcol; } </script> <canvas id="ogl-canvas" style="border: none"></canvas>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.