Shader array limit?

Started by
2 comments, last by Tonyx97 7 years, 8 months ago

//Main Fragment shader (the one that manages all fragment shaders):

#version 430

smooth in vec2 texCoord;
smooth in vec3 NormalVec;
smooth in vec3 CamPosition;

uniform sampler2D gSampler;
uniform vec4 vColor;
uniform bool bUseOnlyColor = false;
uniform vec4 vAmbientColor = vec4(1.0);

#include "Directional_light.frag" //all this includes are properly done cause all them works.
#include "Spot_light.frag"
#include "Point_light.frag"
#include "Fog.frag"
#include "Plasma.frag"
#include "Text_1.frag"
#include "Water.frag"

void main()
{
	vec4 vTexColor = texture2D(gSampler, texCoord);
	vec3 vNormalized = normalize(NormalVec);
	if (!bUseOnlyColor)
		gl_FragColor = vTexColor * vColor * vAmbientColor;				
	else
		gl_FragColor = vColor * vAmbientColor;							 

	PlasmaShader(texCoord);                    //Plasma.frag
	Text_1Shader(texCoord);                    //Text_1.frag
	Water_Shader(texCoord, vColor.w);          //Water.frag


	//LIGHTING
	if (iDirectionalLights > 0)
	{
		vec4 DirectionalLightsFinalColor = vec4(1.0);
		for (int i = 0; i < iDirectionalLights; i++)
		{
			if (DirectionalLight[i].bEnabled)
			{
				DirectionalLightsFinalColor += getDirectionalLightColor(DirectionalLight[i], NormalVec);
			}
		}
		gl_FragColor *= DirectionalLightsFinalColor;
	}
	if (iPointLights > 0)
	{
		vec4 PointLightsFinalColor = vec4(1.0);
		for (int i = 0; i < iPointLights; i++)
		{
			if (PointLights[i].bEnabled)
			{
				PointLightsFinalColor += getPointLightColor(PointLights[i], CamPosition, vNormalized);
			}
		}
		gl_FragColor *= PointLightsFinalColor;
	}
	if (iSpotLights > 0)
	{
		vec4 SpotLightsFinalColor = vec4(1.0);
		for (int i = 0; i < iSpotLights; i++)
		{
			if (SpotLights[i].Enabled) //IF I COMMENT THIS LINE THE SHADER STOP WORKING
			{
				SpotLightsFinalColor += GetSpotLightColor(SpotLights[i], CamPosition);
			}
		}
		gl_FragColor *= SpotLightsFinalColor;
	}
}
 

#version 430  //SPOT LIGHT SHADER

#include_part 

uniform struct CSpotLight 
{ 
  vec3 vColor;
  vec3 vPosition;
  vec3 vDirection;
  float fConeAngle;
  float fConeCosine;
  float fLinearAtt;
  bool Enabled;
} SpotLights[90]; //putting here more than 90 will destroy all the shaders

uniform int iSpotLights = 0;
vec4 GetSpotLightColor(const CSpotLight spotLight, vec3 vWorldPos); 

#definition_part 

vec4 GetSpotLightColor(const CSpotLight spotLight, vec3 vWorldPos) 
{ 
	float fDistance = distance(vWorldPos, spotLight.vPosition); 

	vec3 vDir = vWorldPos-spotLight.vPosition; 
	vDir = normalize(vDir); 
	   
	float fCosine = dot(spotLight.vDirection, vDir); 
	float fDif = 1.0-spotLight.fConeCosine; 
	float fFactor = clamp((fCosine-spotLight.fConeCosine)/fDif, 0.0, 1.0); 

	if(fCosine > spotLight.fConeCosine) 
		return vec4(spotLight.vColor, 1.0)*fFactor/(fDistance*spotLight.fLinearAtt);
}

Hello everyone, since yesterday I've been trying to figure out what was the problem with my shaders. Basically I realized something was wrong when I started to implement the spot light shader in my project. I have a loop to render each different light (directional, point and spot) and I have 3 arrays that contains the data of each type of light. Directional light array has 75 lights, Point light 75 and then when I put the spot light I couldn't put more than 30 because the whole shader program stopped working. I firstly thought it was an array limit but that's weird... 3 arrays, in total 165 lights more or less... Then I started to figure out where was the problem. I realized something, if I don't read any member of the spot light (for example) in the shader it works. Also I want to say that I'm storing all shaders in 1 program because I've heard that it's better to use 1 shader for all entities than putting each shader to each entity. The Shaders code are upper. I've been researching in internet for solutions but I didn't find anything that can answer me question/issue. If this problem is because I reached the max shader size or something like that I don't know how to do this with the best performance because I don't want to have 2 same vertex shaders sending data to their fragments shaders because I need to set the data to all vertex shaders and I only want to do it 1 time for all entities etc..

36eee0136662e885c4861dcbebbb80c6.png

In this screenshot I add all shaders to my main program, there are 10 shaders in total.

Does anyone know what could be the problem or how I should manage this?

Thanks in advance.

Advertisement
Could be hitting the implementation defined maximums for uniforms, maybe check GL_MAX_FRAGMENT_UNIFORM_COMPONENTS.

If that is the problem, the modern solution to it would be SSBOs. Alternatively, texture buffers...

Using SSBO is overkill. The problem is you're requesting 90 UBOs instead of an UBO with 90 elements in it.

Change your code to:


struct CSpotLight
{
vec3 vColor;
vec3 vPosition;
vec3 vDirection;
float fConeAngle;
float fConeCosine;
float fLinearAtt;
bool Enabled;
};

uniform SpotLightBuffer
{
CSpotLight SpotLights[90];
} spotLightBuffer;

//Then access it via:
spotLightBuffer.SpotLights[i];

Using SSBO is overkill. The problem is you're requesting 90 UBOs instead of an UBO with 90 elements in it.

Change your code to:


struct CSpotLight
{
vec3 vColor;
vec3 vPosition;
vec3 vDirection;
float fConeAngle;
float fConeCosine;
float fLinearAtt;
bool Enabled;
};

uniform SpotLightBuffer
{
CSpotLight SpotLights[90];
} spotLightBuffer;

//Then access it via:
spotLightBuffer.SpotLights[i];

Thanks for your answer! I'm using what you said, the shader is still working but I think my GL program can't write the uniforms because the program never pass the condition if any light is enabled or disabled so it's not drawing the light source. I'm also doing the same method to access the data as the shader. It should work with all information you provided but I don't know why I can't write the data of each light... Should I use glUniformBlockIndex etc? Without that method the lights render.


	for (uint i = 0; i < iPointLights; i++)
	{
		CPointLight* _light = PointLights[i];
		if (!IsBadReadPtr(_light, 4) && _light->ID != INT_MAX)
		{
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].bEnabled", true);
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].vPosition", glm::vec3(_light->Position.x, _light->Position.y, _light->Position.z));
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].vLightColor", glm::vec3(_light->LightColor.x, _light->LightColor.y, _light->LightColor.z));
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].fIntensity", _light->Intensity);
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].fConstantAtt", _light->ConstantAtt);
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].fLinearAtt", _light->LinearAtt);
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].fExpAtt", _light->ExpAtt);
			_shader.setUniform("iPointLights", (int)iPointLights);
		}
		else
			_shader.setUniform("PointLightBuffer.PointLights[" + std::to_string(i) + "].bEnabled", false);
	}


struct CPointLight
{
	vec3 vLightColor;
	vec3 vPosition;
	float fIntensity;
	float fConstantAtt;
	float fLinearAtt;
	float fExpAtt;
	bool bEnabled;
};

uniform CPointLightBuffer
{
	CPointLight PointLights[200];
} PointLightBuffer;

This topic is closed to new replies.

Advertisement