Shaders issue

Hello,

I’m trying to make a light system for my game engine but I’ve come across a problem which I can’t get through.

I have a firecamp and when its dark the light looks cool, when its day it looks normal since there is no light…, but when it starts the transition it reaches a point where the fading gets inverted and it looks so wierd…

I can’t find the error on my shader file… please help…

MBTmyEvSH6E

Code:

#version 330 compatibility

uniform sampler2D texture;
in vec2 texCoords;

uniform float dayLight;

uniform vec2 lightPosition[50];
uniform vec3 lightColor[50];
uniform float lightIntensity[50];
uniform float lightInUse[50];
uniform float lightType[50];
uniform float lightSize[50];
uniform float lightFacing[50];

void main() {		
	float day = dayLight * 2;
	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 ocolor = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 tex = texture2D(texture, gl_TexCoord[0].st);
	color = tex;
		
	float alpha = 1.0;
	if (tex.x == 1.0 && tex.y == 0.0 && tex.z == 1.0) {
		alpha = 0.0;
	}
	
	vec4 result = vec4(color.xyz, alpha);
	color = result;
	ocolor = result;
	 
	int num = 0;
	int changed = 0;			
	
	for (int i = 0; i < 50; i++) {
		if (lightInUse[i] == 1) {	
			vec2 pos = lightPosition[i];
			float distance = length(pos - gl_FragCoord.xy);
			if (pos.x == 0 && pos.y == 0) continue;
			vec3 col = lightColor[i];
			float ints = lightIntensity[i];
			
			float attenuation = 1.0 / distance;
			
			float falloff = 80;
			falloff -= distance / 25.0f / ints;			
				  
			if (attenuation >= 0.010) {
				color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;				
				color /= (distance / (ints * falloff));					
				changed = 1;
				num++;
			}
				
		}
	}
	if (changed == 1) color *= 30.0 * pow(166.0, float(num - 1)) + 1;
	else color = vec4(color * vec4(day, day, day, day));
	
	vec4 dcolor = vec4(ocolor * vec4(day, day, day, day));	
	
	if (min(dcolor, color) == color) color = dcolor;
	
	if (min(result, color) == color) gl_FragColor = color;
	else gl_FragColor = result; 
}

Thank you,
João Lourenco.

PS: If there is a better way of doing this, please tell me, I’m trying to learn more about this.

I would assume your issue lies with those if statements with ‘min’ function calls at the end of the code snippet.

Tips:

  • Insert in line 8 [icode]#define LIGHTS_COUNT 50[/icode] and replace all those 50’s with LIGHT_COUNT.
  • That if statement on line 39 should come before the length function call on line 38 as that call is pretty expensive (it uses as sqrt).
  • Lines 58 and 60, that outer vec4(…) is not necessary, the multiplication will create a new one already.
  • What is the point of ‘ocolor’? The whole behavior and assignments of tex/color/dcolor/ocolor are very strange… take a closer look at those and simplify that mess.

Ok so first of all thank you for the awnser and I’ve changed a few things, I hope its better now…

  • Now using the LIGHTS_COUNT.
  • If statement on line 39 has been moved.
  • The ocolor was the “Original Color” but I’ve removed it since I can use the result which is also the original color.
  • Now on the operations instead of using new vectors I only use the dcolor vector created at the beginning…
#version 330 compatibility
#define LIGHTS_COUNT 50

uniform sampler2D texture;
in vec2 texCoords;

uniform float dayLight;

uniform vec2 lightPosition[LIGHTS_COUNT];
uniform vec3 lightColor[LIGHTS_COUNT];
uniform float lightIntensity[LIGHTS_COUNT];
uniform float lightInUse[LIGHTS_COUNT];
uniform float lightType[LIGHTS_COUNT];
uniform float lightSize[LIGHTS_COUNT];
uniform float lightFacing[LIGHTS_COUNT];

void main() {		
	float day = dayLight * 2;
	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 tex = texture2D(texture, gl_TexCoord[0].st);
	color = tex;
		
	float alpha = 1.0;
	if (tex.x == 1.0 && tex.y == 0.0 && tex.z == 1.0) {
		alpha = 0.0;
	}
	
	vec4 result = vec4(color.xyz, alpha);
	color = result;
	
	vec4 dcolor = vec4(result * vec4(day, day, day, day));	
	 
	int num = 0;
	int changed = 0;			
	
	for (int i = 0; i < LIGHTS_COUNT; i++) {
		if (lightInUse[i] == 1) {	
			vec2 pos = lightPosition[i];
			if (pos.x == 0 && pos.y == 0) continue;
			float distance = length(pos - gl_FragCoord.xy);
			vec3 col = lightColor[i];
			float ints = lightIntensity[i];
			
			float attenuation = 1.0 / distance;
			
			float falloff = 80;
			falloff -= distance / 25.0f / ints;			
				  
			if (attenuation >= 0.010) {
				color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
				
				color /= (distance / (ints * falloff));
					
				changed = 1;
				num++;
			}
				
		}
	}
	if (changed == 1) color *= 30.0 * pow(166.0, float(num - 1)) + 1;
	else color = dcolor;
		
	if (min(dcolor, color) == color) color = dcolor;
	
	if (min(result, color) == color) gl_FragColor = color;
	else gl_FragColor = result; 
}

if (lightInUse[i] == 1) {  
         if (pos.x == 0 && pos.y == 0) continue;

What are these test? Why both?

I would just send uniform light counter and avoid those branches per light.

So instead of sending the info if the light is on or off only send the lights that are on right? that makes sence…

I’m trying to learn how to make shaders and only now I’m starting to realize that every operation done on the shader is very heavy… and when I did that if, for example, it was like … heee there is no problem to check if its on or off on the shader… but there is… and for that I must thank you all… ur helping a lot with small things…

so new version of the code:

#version 330 compatibility
#define LIGHTS_COUNT 50

uniform sampler2D texture;
in vec2 texCoords;

uniform float dayLight;

uniform vec2 lightPosition[LIGHTS_COUNT];
uniform vec3 lightColor[LIGHTS_COUNT];
uniform float lightIntensity[LIGHTS_COUNT];
uniform float lightType[LIGHTS_COUNT];
uniform float lightSize[LIGHTS_COUNT];
uniform float lightFacing[LIGHTS_COUNT];

void main() {		
	float day = dayLight * 2;
	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 tex = texture2D(texture, gl_TexCoord[0].st);
	color = tex;
		
	float alpha = 1.0;
	if (tex.x == 1.0 && tex.y == 0.0 && tex.z == 1.0) {
		alpha = 0.0;
	}
	
	vec4 result = vec4(color.xyz, alpha);
	color = result;
	
	vec4 dcolor = vec4(result * vec4(day, day, day, day));	
	 
	int num = 0;
	int changed = 0;			
	
	for (int i = 0; i < LIGHTS_COUNT; i++) {
		vec2 pos = lightPosition[i];
		if (pos.x == 0 && pos.y == 0) continue;
		float distance = length(pos - gl_FragCoord.xy);
		vec3 col = lightColor[i];
		float ints = lightIntensity[i];
		
		float attenuation = 1.0 / distance;
		
		float falloff = 80;
		falloff -= distance / 25.0f / ints;			
			  
		if (attenuation >= 0.010) {
			color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
			
			color /= (distance / (ints * falloff));
				
			changed = 1;
			num++;			
		}
	}
	if (changed == 1) color *= 30.0 * pow(166.0, float(num - 1)) + 1;
	else color = dcolor;
		
	if (min(dcolor, color) == color) color = dcolor;
	
	if (min(result, color) == color) gl_FragColor = color;
	else gl_FragColor = result; 
}

Thank you,
João Lourenço.

I’ve Changed a couple more things…

  • Added a new light type which I’m not happy with yet… the effect looks different don’t know why yet…
  • Removed day variable, the dayLight * 2 is now performed on the java side.

ZuOhlqAsa6M

#version 330 compatibility
#define LIGHTS_COUNT 50

uniform sampler2D texture;
in vec2 texCoords;

uniform float dayLight;

uniform vec2 lightPosition[LIGHTS_COUNT];
uniform vec3 lightColor[LIGHTS_COUNT];
uniform float lightIntensity[LIGHTS_COUNT];
uniform float lightType[LIGHTS_COUNT];
uniform float lightSize[LIGHTS_COUNT];
uniform float lightFacing[LIGHTS_COUNT];

void main() {		
	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 tex = texture2D(texture, gl_TexCoord[0].st);
	color = tex;
		
	float alpha = 1.0;
	if (tex.x == 1.0 && tex.y == 0.0 && tex.z == 1.0) {
		alpha = 0.0;
	}
	
	vec4 result = vec4(color.xyz, alpha);
	color = result;
	
	vec4 dcolor = vec4(result * vec4(dayLight, dayLight, dayLight, dayLight));	
	 
	int num = 0;
	int changed = 0;			
	
	for (int i = 0; i < LIGHTS_COUNT; i++) {
		vec2 pos = lightPosition[i];
		if (pos.x == 0 && pos.y == 0) continue;
		float distance = length(pos - gl_FragCoord.xy);
		vec3 col = lightColor[i];
		float ints = lightIntensity[i];
		
		float attenuation = 1.0 / distance;
		
		float falloff = 80;
		falloff -= distance / 25.0f / ints;			
			  
		if (attenuation >= 0.010) {
			if (lightType[i] == 1) {
				color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
			
				color /= (distance / (ints * falloff));
				
				changed = 1;
				num++;
			} else if (lightType[i] == 2) {
				float angle = degrees(acos((pos.x - gl_FragCoord.x) / distance));		
				if (pos.y < gl_FragCoord.y) angle = 360 - angle;
				
				float max = (lightFacing[i] + (lightSize[i] / 2));
				float min = (lightFacing[i] - (lightSize[i] / 2));	
				bool spec = false;
				
				if (max > 360) {
					max = max - 360;
					spec = true;
				}
				if ((lightFacing[i] - (lightSize[i] / 2)) < 0) {
					min = 360 - abs(lightFacing[i] - (lightSize[i] / 2));
					spec = true;
				}
		
				if ((angle >= min && angle <= max && !spec) || ((angle >= min || angle <= max) && spec)) {
					color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
				
					color /= (distance / (ints * falloff));
					changed = 1;
					num++;
				}
			}
		}
	}
	if (changed == 1) color *= 30.0 * pow(166.0, float(num - 1)) + 1;
	else color = dcolor;
		
	if (min(dcolor, color) == color) color = dcolor;
	
	if (min(result, color) == color) gl_FragColor = color;
	else gl_FragColor = result; 
}

And after this changes, I’m officially out of ideas to performance upgrades…
Tomorrow I’m going to try to make the lights look better… don’t know how…
If you have any ideas please tell me… this is my first attempt at making light stuff…

Thanks,
João Lourenço.

Just a little change:

Avoid branching in shaders as much as possible, they can kill performance.
Use this:


gl_FragColor = min(result, max(dcolor, color));

Thank you Kefwar, I’ve no idea why but that solved my darker shadow when it was day…

#version 330 compatibility
#define LIGHTS_COUNT 50

uniform sampler2D texture;
in vec2 texCoords;

uniform float dayLight;

uniform vec2 lightPosition[LIGHTS_COUNT];
uniform vec3 lightColor[LIGHTS_COUNT];
uniform float lightIntensity[LIGHTS_COUNT];
uniform float lightType[LIGHTS_COUNT];
uniform float lightSize[LIGHTS_COUNT];
uniform float lightFacing[LIGHTS_COUNT];

void main() {		
	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 tex = texture2D(texture, gl_TexCoord[0].st);
	color = tex;
		
	float alpha = 1.0;
	if (tex.x == 1.0 && tex.y == 0.0 && tex.z == 1.0) {
		alpha = 0.0;
	}
	
	vec4 result = vec4(color.xyz, alpha);
	color = result;
	
	vec4 dcolor = vec4(result * vec4(dayLight, dayLight, dayLight, dayLight));	
	 
	int num = 0;
	int changed = 0;			
	
	for (int i = 0; i < LIGHTS_COUNT; i++) {
		vec2 pos = lightPosition[i];
		if (pos.x == 0 && pos.y == 0) continue;
		float distance = length(pos - gl_FragCoord.xy);
		vec3 col = lightColor[i];
		float ints = lightIntensity[i];
		
		float attenuation = 1.0 / distance;
		
		float falloff = 80;
		falloff -= distance / 25.0f / ints;			
			  
		if (attenuation >= 0.010) {
			if (lightType[i] == 1) {
				color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
			
				color /= (distance / (ints * falloff));
				
				changed = 1;
				num++;
			} else if (lightType[i] == 2) {
				float angle = degrees(acos((pos.x - gl_FragCoord.x) / distance));		
				if (pos.y < gl_FragCoord.y) angle = 360 - angle;
				
				float max = (lightFacing[i] + (lightSize[i] / 2));
				float min = (lightFacing[i] - (lightSize[i] / 2));	
				bool spec = false;
				
				if (max > 360) {
					max = max - 360;
					spec = true;
				}
				if ((lightFacing[i] - (lightSize[i] / 2)) < 0) {
					min = 360 - abs(lightFacing[i] - (lightSize[i] / 2));
					spec = true;
				}
		
				if ((angle >= min && angle <= max && !spec) || ((angle >= min || angle <= max) && spec)) {
					color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
				
					color /= (distance / (ints * falloff));
					changed = 1;
					num++;
				}
			}
		}
	}
	if (changed == 1) color *= 30.0 * pow(166.0, float(num - 1)) + 1;
	else color = dcolor;
		
	gl_FragColor = min(result, max(dcolor, color));
}

Thank you,
João Lourenço.

A couple of changes I made once more…

  • Removed the attenuation if.
  • I now pass in a variable with the lights amount to avoid the for loop trying to work unexistent lights.

VLiyF5iZj5U

#version 330 compatibility
#define LIGHTS_COUNT 50

uniform sampler2D texture;
in vec2 texCoords;

uniform float dayLight;

uniform int lightAmount;

uniform vec2 lightPosition[LIGHTS_COUNT];
uniform vec3 lightColor[LIGHTS_COUNT];
uniform float lightIntensity[LIGHTS_COUNT];
uniform float lightType[LIGHTS_COUNT];
uniform float lightSize[LIGHTS_COUNT];
uniform float lightFacing[LIGHTS_COUNT];

void main() {		
	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 tex = texture2D(texture, gl_TexCoord[0].st);
	color = tex;
		
	float alpha = 1.0;
	if (tex.x == 1.0 && tex.y == 0.0 && tex.z == 1.0) {
		alpha = 0.0;
	}
	
	vec4 result = vec4(color.xyz, alpha);
	color = result;	
	vec4 dcolor = vec4(result * vec4(dayLight, dayLight, dayLight, dayLight));	
	 
	int num = 0;
	int changed = 0;			
	
	for (int i = 0; i < lightAmount; i++) {
		vec2 pos = lightPosition[i];
		if (pos.x == 0 && pos.y == 0) continue;
		vec3 col = lightColor[i];
		float ints = lightIntensity[i];
		
		float distance = length(pos - gl_FragCoord.xy);
		float attenuation = 1.0 / distance;
		
		float falloff = 50 - distance / 5.0f / ints;			
			  
		if (lightType[i] == 1) {
			color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
		
			color /= (distance / (ints * falloff));
			
			changed = 1;
			num++;
		} else if (lightType[i] == 2) {
			float angle = degrees(acos((pos.x - gl_FragCoord.x) / distance));		
			if (pos.y < gl_FragCoord.y) angle = 360 - angle;
			
			float max = (lightFacing[i] + (lightSize[i] / 2));
			float min = (lightFacing[i] - (lightSize[i] / 2));	
			bool spec = false;
			
			if (max > 360) {
				max = max - 360;
				spec = true;
			}
			if ((lightFacing[i] - (lightSize[i] / 2)) < 0) {
				min = 360 - abs(lightFacing[i] - (lightSize[i] / 2));
				spec = true;
			}
	
			if ((angle >= min && angle <= max && !spec) || ((angle >= min || angle <= max) && spec)) {
				color *= vec4(attenuation, attenuation, attenuation, pow(attenuation, 3)) * vec4((col / distance * 15) * ints, 1.0) + 0.01;
			
				color /= (distance / (ints * falloff));
				changed = 1;
				num++;
			}
		}
	}
	
	if (changed == 1) color *= 30.0 * pow(166.0, float(num - 1)) + 1;
	else color = dcolor;
		
	gl_FragColor = min(result, max(dcolor, color));
}

I don’t think I can make the Point light any better now… At least I don’t have any Ideas for now…
The SpotLight in the other hand, has still a few adjustments to be done… For some reason the shader only works for the first light that is passed in… I’ve confirmed in the java side that I’m passing in both lights.

If anyone knows why the shader is only processing one light please tell me…

Thank you,
João Lourenço.

 if (pos.x == 0 && pos.y == 0) continue;

What is this?

In other matter. Always sort by type instead of doing redudant tests per pixel in inner loop.(1920 * 1080 * 50lights * 60fps = 6220800000 dynamic branches per second for no reason)

So instead of doing light type test there you create two loops. One for point lights and one for that special lights. Both have their counter and their own uniforms.