What is the error you receive, and what are you passing to the shader?
Related: Performing so many conditionals on the GPU is very expensive and may not be supported on all cards. You might want to process some of this information on the CPU and pass it into the shader.
I think you mixed your coordiates up … looks like lightCenter is in WorldSpace but your “screenPosition” is in Screenspace. Those do not match.
also you really shouldn’t use hardcoded dimensions - if you need the worldposition in the PixelShader, you can just pass that over in a param like TEXCOORD1 - which is a common way.
anyway - you didn’t tell what error you receive - i would just guess it’sa type mismatch (we can only guess at this point)
The error is always the same error, for everything:
Error 2 The command ““C:\Program Files (x86)\MSBuild\MonoGame\v3.0\Tools\MGCB.exe” /@:“C:\Users\Administrador\Desktop\Inventario Adrian NO BORRAR AUNNNN\Inventario\Content\Content.mgcb” /platform:Windows /quiet /outputDir:“bin\Windows\Content” /intermediateDir:“obj\Windows\Content”” exited with code 1. CraftTale
The coordinates are fine, work perfect for one light , when I use arrays to try extend the number of lights is when everything go crazy.
My game is a 2D game, the player have plenty of freedom, for example, he can colocate unlimited numbers of bonfire in the ground, every bonfire add a new light fount. First I implemented the lights using masks and work fine, but the fps go down a lot.
That’s not an HLSL error message, it just tells you that MGCB.exe exited with an error. Are you maybe not getting HLSL errors because of the /quiet option?
You might be running into pixel shader limitations. ps_4_0_level_9_1 is basically pixel shader 2, which is old and limited. Your loop count is very high. With pixel shader 2 the loop may need to be unrolled, making your shader program too long. Does lowering the loop count help?
If that’s the case, your options are
increase the pixel shader version (if your target platform allows it)
use less lights. Maybe use the 10 most influential lights for every object, instead of all the lights.
somehow divide the shader up into multiple smaller steps
use a different lighting model. If you have many small lights you could render them all into a lighting texture first (one quad per light), and then blend the whole scene using this texture.
Exist a way to control to what Draw apply the effect?
I read thath a way is do many Begin/End, but I have only one Begin/End for the entire World, I use Sprite SortMode.FrontToBack and calculate dynamically the Depth for every actor. If I use many of them (Begin/End) I can not handle the order of drawing.
I would say, you need to reorganize it in your code then - as you didn’t tell what you want to achieve, it’s hard to give any recommendation.
you cannot switch the effect used between begin/end (at least not on spritebatch, you could make your own spritebatch which does this I guess, but if it’s worth that work?)
I do this in a simple way. I draw in a 1920*1080 (virtual resolution) RenderTarget2D, masks of white to black for every light affecting de scene. I pass the final RenderTarget2D of the entire scene and multiply the pixel color in the scene for the color in the big mask of ligths.
Not sure, if the shader code in your first post is still what you are using. The way I would do it is as follows (maybe it’s already like you do it)
Render the light-falloff to a texture (this don’t need to be full res, you can do 1/4 because you don’t need the detail anyway) - you could basically just render a texture with a white dot per lightsource on a black-cleared target. Do NOT use any loops in the shader, just pass in as geometry (or with spritebatch as 1 draw per light). This can also be as fast as passing a single Postion + falloff and do all the other calculations in vertexshader (not using spritebatch then, it’s more like a particlesystem in that case)
you then pass that texture to the batch where you draw everything else and in the shader use the position (screenspace: 0-1) as TextureCoordinate on that “lightmap” and multiply with color to get the result - should not have any problems with thousands of lights
There also should be no reason for multiple spritebatches or different effects per sprite <- that’s what you should aim for
But your pixel shader at no point actually uses this value that is passed in from the vertex shader.
This could cause a error depending on what the rest of the shader looks like.
Which is why its helpful to post the full shader ?
Also the way you are doing it you should have a lightIntensity or lightStrength array that ranges from 0 to 1.
You should for loop each light.
Based on the distance calculate the strength of the light.
Multiply that intensity amount (0 to 1 / distance.) to the rgb color.
Sum that rgb color on each iteration to a final color.
After the loop is completed you should call saturate on the color to ensure it is within a normal color range.
Then pass that value out.
…
No if else statements are required.
Basically though this is just pseudo code.
// add this
float lightStrength[75]; // intensity 0 to 1;
.
.
float4 PixelShaderFunction(float4 pos : SV_POSITION, float2 coords : TEXCOORD0) : COLOR0
{
float4 uv_texel_color = tex2D(s0, coords);
// im not to confident of this line but im going to assume that you are already made sure this works and tested it.
float2 screenPosition = float2(coords.x * 1920, coords.y * 1080) + cameraPosition;
for (int i = 0; i < 75; i++)
{
dist = distance(screenPosition, lightCenter[i]);
// light falloff curve formula is entirely up to you depending on how you want it to feel.
// I forget how distance works in a shader so you will probably need to experiment with this.
// The intensity should i think fall off with the square of the distance.
float intensity = lightStrength[i] * ( lightRadius[i] / ( lightRadius[i] * (dist + 1.0f) ) );
// make sure the value isn't below zero saturate can be used here as well i think alternately.
intensity = max(0, intensity);
// sum each light that illuminates this pixel.
end_color += uv_texel_color * float4(intensity, intensity, intensity, 1.0f);
}
end_color = saturate(end_color);
return end_color;
}
Get rid of the color1 input value if you are not using it.
Almost 400 lights in the scene and the fps is stable. The low resolution of the render was a big improve to the speed. Thanks for the patience and the help.