-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chapter2/6-MultipleLights sample is broken #48
Comments
Hi, thanks for the report. Could you please provide more information on what the error you get is? |
Surely:
Got this log with next code: diff --git a/Common/Shader.cs b/Common/Shader.cs
index 1ff74d2..8ec8596 100644
--- a/Common/Shader.cs
+++ b/Common/Shader.cs
@@ -68,6 +68,7 @@ namespace LearnOpenTK.Common
// First, we have to get the number of active uniforms in the shader.
GL.GetProgram(Handle, GetProgramParameterName.ActiveUniforms, out var numberOfUniforms);
+ Console.WriteLine("Shader: {0}+{1} Handle: {2}", vertPath, fragPath, Handle);
// Next, allocate the dictionary to hold the locations.
_uniformLocations = new Dictionary<string, int>();
@@ -83,6 +84,8 @@ namespace LearnOpenTK.Common
// and then add it to the dictionary.
_uniformLocations.Add(key, location);
+
+ Console.WriteLine("Adding location: {0} => {1}", key, location);
}
}
@@ -155,8 +158,15 @@ namespace LearnOpenTK.Common
/// <param name="data">The data to set</param>
public void SetFloat(string name, float data)
{
+ if (!_uniformLocations.TryGetValue(name, out var location))
+ {
+ location = GL.GetUniformLocation(Handle, name);
+ Console.WriteLine("Unknown location: {0} => {1}", name, location);
+ _uniformLocations.Add(name, location);
+ }
+
GL.UseProgram(Handle);
- GL.Uniform1(_uniformLocations[name], data);
+ GL.Uniform1(location, data);
}
/// <summary>
@@ -182,8 +192,15 @@ namespace LearnOpenTK.Common
/// <param name="data">The data to set</param>
public void SetVector3(string name, Vector3 data)
{
+ if (!_uniformLocations.TryGetValue(name, out var location))
+ {
+ location = GL.GetUniformLocation(Handle, name);
+ Console.WriteLine("Unknown location: {0} => {1}", name, location);
+ _uniformLocations.Add(name, location);
+ }
+
GL.UseProgram(Handle);
- GL.Uniform3(_uniformLocations[name], data);
+ GL.Uniform3(location, data);
}
}
} PS: Sorry, i'm did not wrote initially, issue was in that |
Can you give me the exception message you get on |
System.Collections.Generic.KeyNotFoundException: 'The given key 'dirLight.direction' was not present in the dictionary.' |
Are you sure you are compiling the correct shaders? |
Shader files are unmodified, as they come from this repository. |
I'm did not have luck to find any reasonable answer why only seven or so entries returned as active uniforms... (for me). Generally by this issue i'm point what LearnOpenGL did not use program introspection (is it exists some reason for this?). And set values by something like: void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
} This way work, and as i'm already wrote, if Shader.cs turn to act in similar way - then sample start to work, and everything looks fine. There is probably driver-specific behavior, however, glGetActiveUniform explicitly state how it deal with arrays: |
The code runs on my GPU (nvidia gtx 1070). |
Ah it seems there is also a typo. if (!_uniformLocations.TryGetValue(name, out var location))
{
location = GL.GetUniformLocation(Handle, name); You invert the That is the problem ;) code should look like this instead public void SetVector3(string name, Vector3 data)
{
if (_uniformLocations.TryGetValue(name, out var location))
{
GL.UseProgram(Handle); // this should be moved out actually, there is no need to call this for every parameter setting
GL.Uniform3(location, data);
return;
}
location = GL.GetUniformLocation(Handle, name);
if (location == -1)
{
Console.WriteLine($"Uniform {name} cannot be found.");
return;
}
_uniformLocations.Add(name, location);
} But also you should move the location lookup to after linking the program, then you dont have to repeat this code over and over and only lookup, when found use, when not found throw error |
@deccer is not a typo. If TryGetValue get value from dictionary - then code block skipped, nothing logged and go as it was designed. If not pulled, then location value obtained and logged to screen and added to dictionary (mainly to log location value once). If you read log you should notice what all calls succeed. [And more over - renderered as it should] However, thanks for your good intent. PS:
So, definitely you reverse branches of my code effectively doubling number of lines without changing logic itself, except what forward/bottom branch no more call GL.Uniform3, which effectively bug (additionally, which will be masked by next render call). So, your version nor add readability or maintability, may be some kind of yours taste, but, nothing more. Using
Again, thanks. It is clear for me from start. I guess samples don't do this just for simplicity. In my taste - if Shader.cs turn to it's C++ counterpart way - nothing will be lost (no need dictionary at all, performance is a question surely, but dictionary lookup is also bit naive in this sense), there is learning sample in first place. |
Your "log" output clearly shows valid uniform locations, which it should not print at all, if the .TryGet was correct - which in your case was not. the We have a discord server if you want to hop on... https://discord.gg/6HqD48s |
@deccer my log clearly shows, what introspection don't return all uniforms in first place, so _uniformLocations never was filled completely as initial code expect. Everything rest really no matter, and code was born to answer question as comment above (which uniform locations was not returned by get active uniforms call?). Even dictionary manipulation was added here with intent to report uniform name only once, and not to trying memoizing GetUniformLocation result. If you be more careful, you may find what this code is equivalent to your code, except, what this code set uniform value immediately, while your miss this step on second branch (I believe just as typo). public void SetFloat(string name, float data)
{
if (!_uniformLocations.TryGetValue(name, out var location))
{
// No variable in dictionary
// Get variable location
location = GL.GetUniformLocation(Handle, name);
// Report
Console.WriteLine("Unknown location: {0} => {1}", name, location);
// Add this to dictionary, so in next time TryGetValue will succeed.
_uniformLocations.Add(name, location);
}
// Here we always have correct location
GL.UseProgram(Handle);
GL.Uniform1(location, data);
} Anyway:
So, my contribution ends here, and there is no need more discussion about this topic. |
No no, I think I am stupid. The console output irritated me for some reason. You are right. :S I apologise. I wonder what GPU you use and if the drivers are up to date. |
@deccer all is fine. :) i'm wrote at initial message, it is Intel HD 4600 (i7-4770). I'm run Windows 10 stable with latest updates (windows care about intel drivers updates too in this case also automatically). I'm know what it is not very ideal GPU / software, but still it can complete many things easily (including this samples, even some good past games like DAO). It is just mine bad luck what when i'm pick samples - almost any work, but hit in this issue. (BTW, samples did not show exceptions, just silently close window on exception, so it can be discovered only with running by debugger.) |
Chapter2/6-MultipleLights sample are crash for me (I'm run it on Intel HD 4600 video, if it matters at all, doesn't sure, i'm completely newbie in OpenGL).
The issue is what Shader.cs fills _uniformLocations by using call
GL.GetProgram(Handle, GetProgramParameterName.ActiveUniforms, out var numberOfUniforms);
. However this call doesn't report all locations.I'm checked LearnOpenGL example, and it uses bit different way, so i'm put few changes:
And that's makes example to run. Surely, this requires more accurate fix.
The text was updated successfully, but these errors were encountered: