SFML community forums
General => General discussions => Topic started by: Laurent on November 03, 2009, 10:17:56 am
-
Hi
I've rewrote the sf::PostFx class, which is now sf::Shader. It's a more general purpose pixel shader (or fragment shader) class. I've not updated the API documentation yet, so here is a short description of the new features, and of what to change for people using shaders.
Its interface is basically the same as PostFx (Load, SetParameter, SetTexture), but it no longer inherits from sf::Drawable. Here is the new usage:
target.Draw(object, shader);
Shaders can be used on any type of drawable, but for sf::String and sf::Shape it is more limited than for sf::Sprite because:
- the texture used by a sf::String is not what you see on screen
- sf::Shape doesn't use a texture
You have to take this in account in your shaders.
Post-effects are now achieved using a combination of RenderImage and Shader:
sf::Shader postEffect;
...
sf::RenderImage renderImage;
renderImage.Create(window.GetWidth(), window.GetHeight());
...
renderImage.Clear();
renderImage.Draw(everything);
renderImage.Display();
sf::Sprite screen(renderImage.GetImage());
window.Draw(screen, postEffect);
window.Display();
Images are no longer passed by pointer to Shader::SetTexture, and the texture of the object being drawn is referred as Shader::CurrentTexture:
sf::Image image;
...
shader.SetTexture("image", image);
shader.SetTexture("texture", sf::Shader::CurrentTexture);
The special preprocessing step has been removed, shaders are now pure GLSL programs. So what was previously this:
texture tex
effect
{
_out = tex(_in);
}
is now this:
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, gl_TexCoord[0].xy);
}
Shaders can also be used directly, with custom OpenGL rendering. However it is not possible to have a vertex shader if you use sf::Shader.
window.SetActive();
shader.Bind();
... render OpenGL stuff ...
shader.Unbind();
If I have forgotten anything, or if something is not clear enough, ask your question here :)
-
If you are using OpenGL3, which SFML2 will do automatically if it is available AFAIK, the predefined varyings like gl_TexCoord etc no longer exist, which might turn out to be a problem (depending on how your predefined vertex shader is set)
-
If you are using OpenGL3, which SFML2 will do automatically if it is available AFAIK
It will probably be explicitely specified with an additional parameter in sf::ContextSettings in the future.
the predefined varyings like gl_TexCoord etc no longer exist, which might turn out to be a problem (depending on how your predefined vertex shader is set)
I hadn't thought about this potential issue. I don't know much about the new predefined variables, I'll have to take a look into this.
To avoid problems I think I'll first implement the explicit selection of the OpenGL version :)
-
By the way, it is still possible to do post-effects the old way:
sf::Shader postEffect;
sf::Image screen;
...
window.Clear();
window.Draw(everything);
screen.CopyScreen(window);
window.Draw(sf::Sprite(screen), postEffect);
window.Display();
This one has the benefit of not impacting the main rendering process, and can be added/removed easily.
-
It will probably be explicitely specified with an additional parameter in sf::ContextSettings in the future.
Good idea. Will window creation fail if a specific version is requested and isn't available, or will it work, but report it in some way? (I would prefer the first variant)
I hadn't thought about this potential issue. I don't know much about the new predefined variables, I'll have to take a look into this.
Which is why I brought it up. BTW, there are no "new predefined" variables, as OpenGL3 simply removes all of the predefined ones (even position iirc)
-
Good idea
Implemented and commited ;)
Will window creation fail if a specific version is requested and isn't available, or will it work, but report it in some way? (I would prefer the first variant)
My rule is that context settings are only a hint, and if any of them is not supported then SFML will try to find the closest valid match. So no, no failure will happen. And you can request the actual settings that were used with Window::GetSettings().
BTW, there are no "new predefined" variables, as OpenGL3 simply removes all of the predefined ones (even position iirc)
Oh, I see. That will not be a big issue then :)
-
So we can draw the shader to specific sprites on the screen with Bind and Unbind? Exciting, now I can make my 2D Water distort everything inside of it. Before, it would've taken drawing the sprites, then after the water is drawn, copy that region covered by water to a sprite, render the shader to it, then copy that BACK to the screen.
-
So we can draw the shader to specific sprites on the screen with Bind and Unbind?
Bind and Unbind is for using the shader with OpenGL. To use it with sprites, you just have to pass the shader to the Draw function.
Exciting, now I can make my 2D Water distort everything inside of it. Before, it would've taken drawing the sprites, then after the water is drawn, copy that region covered by water to a sprite, render the shader to it, then copy that BACK to the screen.
You could already do it with a render image ;)
-
So I'm trying this out, right? I updated to build 1262, cded to the sfml2 directory, did a make sfml, then a sudo make install, changed my game to use the new shader class, compiled, and get this:
/usr/local/lib/libsfml-graphics.so undefined reference to `sf::EnsureGlewInit()'
-
I think you have to "make clean" before :)
If you were previously using a very old revision, be careful because the default install path has changed, so you probably have to remove what's left in /usr/include and /usr/lib.
-
Already made up your mind about giving us the ability to apply textures to sf::Shape's ?
-
Almost.
I won't think about it until the next major version (maybe SFML 3, maybe not), and here is why: a sf::Shape with texture would make sf::Sprite almost useless, I think I'd have to merge them into a more general purpose "2D entity with texture" class that would be as easy as sf::Sprite to use, and as powerful as sf::Shape. You see, it's not a trivial modification and it will make me rewrite some core parts of the graphics module.
Another problem is that a lot of people will want to be able to use texture-repeat with shapes, and I can't provide it.
-
Ignore this post, it was an error on my end.
-
Alright, so I got everything working with sf::Shader, and went to test the differences. Here's what I've found:
-Native Linux sf::Shader is very laggy
-Emulated Windows game with sf::PostFX runs perfectly at full speed
Why is it that an Emulated Game can run more efficiently than a Native Test? Here's another problem. When I used sf::PostFX, I used this shader:
texture screen
float time
effect
{
vec2 offset = vec2(cos(time/500+_in.x*10)/50, sin(time/500+_in.y*10)/50);
_out = vec4(screen(_in+offset));
}
This was meant to make a watery effect by stretching and shrinking the screen. It worked perfectly, every part of the screen was stretched and shrunk, and there were no blank spaces in the screen. I used this code:
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow Window(sf::VideoMode(512, 512, 32), "Test");
sf::Image imgBackground;
imgBackground.LoadFromFile("Random512x512image.png");
sf::Sprite sprBackground;
sprBackground.SetImage(imgBackground);
sf::PostFX WaterShader;
WaterShader.LoadFromFile("WaterShader.sfx");
while (Window.IsOpened()){
// Process Events here, close on sf::Event::Close
Window.Clear();
Water.SetTexture("screen", NULL);
Water.SetParameter("time", (double)clock());
Screen.Draw(sprBackground);
Screen.Draw(Water);
Screen.Display();
}
}
It works like a charm. However, with sf::Shader, I translated the Shader file to this:
uniform sampler2D screen;
uniform float time;
void main(){
vec2 offset = vec2(cos(time/500+gl_TexCoord[0].x*10)/50, sin(time/500+gl_TexCoord[0].y*10)/50);
gl_FragColor = vec4(texture2D(screen, gl_TexCoord[0].xy+offset));
}
And the test's code to this:
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow Window(sf::VideoMode(512, 512, 32), "Test");
sf::Image imgBackground;
imgBackground.LoadFromFile("Random512x512image.png");
sf::Sprite sprBackground;
sprBackground.SetImage(imgBackground);
sf::Shader WaterShader;
WaterShader.LoadFromFile("WaterShader.sfx");
while (Window.IsOpened()){
// Process Events here, close on sf::Event::Close
Window.Clear();
Water.SetTexture("screen", sf::Shader::CurrentTexture);
Water.SetParameter("time", (double)clock());
Screen.Draw(sprBackground, Water);
Screen.Display();
}
}
And it works, but I get blank spots on the sides of the screen, and there is much lag. What could be causing this change?
-
And it works, but I get blank spots on the sides of the screen
Can you show a screenshot? Have you tried to disable smoothing on your image?
and there is much lag
You didn't have it before?
-
And it works, but I get blank spots on the sides of the screen
Can you show a screenshot? Have you tried to disable smoothing on your image?
and there is much lag
You didn't have it before?
Can you show a screenshot? Have you tried to disable smoothing on your image?
I just disabled smoothing, and the glitch changed slightly to this:
(http://i35.tinypic.com/2uo467t.png)
It also does get blackness on the top and bottom of the screen once every second, and when that happens, the darker area is on the sides.
You didn't have it before?
No, I did not. I emulated a Windows program using build 1245 or so with sf::PostFX, and it ran lag-free.
I ran a native Linux program using build 1262 with sf::Shader, and I'm getting piles of lag.
-
No, I did not. I emulated a Windows program using build 1245 or so with sf::PostFX, and it ran lag-free.
I ran a native Linux program using build 1262 with sf::Shader, and I'm getting piles of lag.
But what about native Linux program using revision 1245?
Can you upload your project so that I can test it?
I'm surprised because the internal OpenGL code related to shaders hasn't changed at all, my modifications were almost all to the public API.
-
I updated to SFML 1268, and the glitch with the tearing and blackness is gone, but I still have the lag.
Here's the demo with SFML 1268.
http://willhostforfood.com/access.php?fileid=93440
Use run.sh to use the local .so files.
-
My laptop with ATI Radeon Mobility HD3465, Catalist 9.4 (AFAIK the last version with HD3465 support) refused to compile wave.sfx. Other shaders are Ok. Investigations showed that it had stuck at the line:
vec2 texoffset = texture2D(wave, (gl_TexCoord[0].xy * offset).xy);
If I use vec2 explicit construction, everything is Ok.
vec2 texoffset = vec2(texture2D(wave, (gl_TexCoord[0].xy * offset).xy));
I'm far far away from being a glsl guru. May this behavior be caused by the sfml current shader's version incompatibility with my hardware?
-
Ah, true. I'll fix it as soon as possible :)
-
I updated to SFML 1268, and the glitch with the tearing and blackness is gone, but I still have the lag.
Here's the demo with SFML 1268.
http://willhostforfood.com/access.php?fileid=93440
Use run.sh to use the local .so files.
I couldn't use the local .so files (my system has a problem and needs a modified version of SFML), but I tried shaders with the latest revision:
- the Shader sample runs perfectly
- I can see the lag in your application
Can you show your source code? Did you try the Shader sample?
-
Hello!
float edge = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb);
That's some good coding right there.
-
float edge = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb);
That's some good coding right there.
?
-
float edge = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb);
That's some good coding right there.
?
The sqrt returns a vec3, since the value sent to it is a vec3. vec3s cannot be assigned to floats.
-
I updated to SFML 1268, and the glitch with the tearing and blackness is gone, but I still have the lag.
Here's the demo with SFML 1268.
http://willhostforfood.com/access.php?fileid=93440
Use run.sh to use the local .so files.
I couldn't use the local .so files (my system has a problem and needs a modified version of SFML), but I tried shaders with the latest revision:
- the Shader sample runs perfectly
- I can see the lag in your application
Can you show your source code? Did you try the Shader sample?
Here's our repository: http://mke.svn.sourceforge.net/viewvc/mke/
I tried to Shader sample, and it works fine, so I dunno what's going on.
-
The sqrt returns a vec3, since the value sent to it is a vec3. vec3s cannot be assigned to floats.
Ah, true (my driver accepts so many errors...).
I fixed the code, thanks.
-
Here's our repository: http://mke.svn.sourceforge.net/viewvc/mke/
I tried to Shader sample, and it works fine, so I dunno what's going on.
It seems like clock() has a very low resolution on Linux. Using a sf::Clock solves the problem.
-
Here's our repository: http://mke.svn.sourceforge.net/viewvc/mke/
I tried to Shader sample, and it works fine, so I dunno what's going on.
It seems like clock() has a very low resolution on Linux. Using a sf::Clock solves the problem.
Alright then. Thanks for the help! I switched to sf::Clock and it works perfect!
On the shader sample, global fisheye Y coordinates are flipped for me. It doesn't do this with background, and I can't tell on flower.
-
So I am trying to make the screen draw two shaders, right? Here's the shader code in the Title Screen in Main.cpp of my repository(not committed yet):
if (sf::Shader::IsAvailable()){
Water.SetTexture("screen", sf::Shader::CurrentTexture);
Water.SetParameter("time", Clock.GetElapsedTime()*1000.f);
Blend.SetTexture("screen", sf::Shader::CurrentTexture);
Blend.SetParameter("color", 0.5, 0.0, 0.5);
Blend.SetParameter("alpha", 1.0);
sf::RenderImage Screen;
Screen.Draw(BG);
Screen.Display();
Window.Draw(sf::Sprite(Screen.GetImage()));
}
Guess what? I just get a white screen. Why is this? When I replace the Window.Draw line with Window.Draw(BG); it works fine. When I use this code, it absolutely fails. What am I doing wrong? I'm drawing the BG to the RenderImage, Displaying the RenderImage, then drawing the RenderImage to the Screen, and I get White. :S
-
On the shader sample, global fisheye Y coordinates are flipped for me. It doesn't do this with background, and I can't tell on flower.
I know, this is a bug in the code of the shader.
Guess what? I just get a white screen. Why is this? When I replace the Window.Draw line with Window.Draw(BG); it works fine. When I use this code, it absolutely fails. What am I doing wrong? I'm drawing the BG to the RenderImage, Displaying the RenderImage, then drawing the RenderImage to the Screen, and I get White. :S
Your RenderImage instance gets destroyed after the call to Draw; but SFML delays the actual drawing until you call Window.Display(), and at this time the source image doesn't exist anymore.
-
Guess what? I just get a white screen. Why is this? When I replace the Window.Draw line with Window.Draw(BG); it works fine. When I use this code, it absolutely fails. What am I doing wrong? I'm drawing the BG to the RenderImage, Displaying the RenderImage, then drawing the RenderImage to the Screen, and I get White. :S
Your RenderImage instance gets destroyed after the call to Draw; but SFML delays the actual drawing until you call Window.Display(), and at this time the source image doesn't exist anymore.
Moved the sf::RenderImage's Declaration to outside the if statement, in the context of the Window.Display() code. Black screen. Moved it back inside and added a Window.Flush() to the end of the if statement. Black Screen.
-
Can you show a simple code sample that reproduces this problem?
-
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow Window;
Window.Create(sf::VideoMode(512, 512, 32), "Test");
sf::Image Background;
Background.LoadFromFile("Any512x512Image.png");
sf::Sprite BG(Background);
//sf::RenderImage Screen; // Uncomment this line and comment the definition ahead and Flush if you want to test both
if (sf::Shader::IsAvailable()){
sf::RenderImage Screen;
Screen.Draw(BG);
Screen.Display();
Window.Draw(sf::Sprite(Screen.GetImage()));
Window.Flush();
}
else
Window.Draw(BG);
Window.Display();
sf::Event Event;
while (Window.IsOpened()){
while (Window.GetEvent(Event)){
if (Event.Type == sf::Event::Closed)
Window.Close();
if (Event.Type == sf::Event::KeyPressed && Event.Key.Code == sf::Key::Escape)
Window.Close();
}
}
return EXIT_SUCCESS;
}
There's the code that does not work for me. It draws nothing.
-
You do know that you are only drawing once?
-
You do know that you are only drawing once?
Yes. I don't change what the screen shows after I draw.
-
Got it to work by changing the RenderImage to an Image and CopyScreen() instead of the RenderImage functions.
-
What does RenderImage::IsAvailable() return?
-
What does RenderImage::IsAvailable() return?
True.
-
Weird. Do you run in debug mode? Is there any message in the standard error output?
-
Weird. Do you run in debug mode? Is there any message in the standard error output?
Nothing in stderr, I use Release.
-
Can you try debug?
-
Has the DEBUGBUILD=yes/no changed since SFML1.x? I can't seem to get it to compile debug.
-
No, it's the same. What's wrong?
-
No, it's the same. What's wrong?
I run make sfml DEBUGBUILD=yes, and even try setting DEBUGBUILD=yes in the makefile manually, but only the release binaries are built.
-
Are you sure? The debug binaries have the same name as the release ones (yes I know, this is bad, I'm currently working to make it cleaner).
-
My rule is that context settings are only a hint, and if any of them is not supported then SFML will try to find the closest valid match. So no, no failure will happen. And you can request the actual settings that were used with Window::GetSettings().
About this:
When I request GL 3.0, I get a 3.0 context. Requesting a 3.1 context fails, but falls back to 2.0 instead of 3.0. I think the minor version should be lowered first.
Also, if I use an invalid MSAA level, the fallback fails (even though antialiasing usually works)
-
When I request GL 3.0, I get a 3.0 context. Requesting a 3.1 context fails, but falls back to 2.0 instead of 3.0. I think the minor version should be lowered first
Yeah, maybe.
Also, if I use an invalid MSAA level, the fallback fails (even though antialiasing usually works)
Really? When AA fails I just lower the value and call the same function again and again, until it works. When 0 is reached, the execution is exactly the same as if you passed 0 directly.
Maybe you can run your program step-by-step in debug mode to see what happens in SFML?
-
Looks like the error is in line 184 of ContextWGL.cpp:
mySettings.AntialiasingLevel = intAttributes[1] = 2;
this should actually be
mySettings.AntialiasingLevel = intAttributes[11] = 2;
-
That's so stupid :shock:
Thank you very much, it's now fixed :)
-
I got the debug binaries working. Blackness when I use RenderImage. Nothing in stderr, either.
-
I got the debug binaries working. Blackness when I use RenderImage. Nothing in stderr, either.
What about the Shader sample? Does it work?
-
I got the debug binaries working. Blackness when I use RenderImage. Nothing in stderr, either.
What about the Shader sample? Does it work?
Yes. It's probably a problem with sf::RenderImage, as that is where my problem is at.
-
Yes. It's probably a problem with sf::RenderImage, as that is where my problem is at.
But the shader sample uses a RenderImage as well, so the problem might be from your code.
-
When I request GL 3.0, I get a 3.0 context. Requesting a 3.1 context fails, but falls back to 2.0 instead of 3.0. I think the minor version should be lowered first.
Done in latest sfml2 revision.
-
After updating to the latest version, my game now freezes completely at
Screen.Create(mode, "oglgame", sf::Style::Resize | sf::Style::Close, settings);
If I set the opengl version to 2.x instead of 3.x, it works fine. I last updated less than 24h ago and it worked fine. Maybe this thread isn't the right place to post this in, I guess it could be an unrelated problem.
-
You're right, this was a stupid error related to this modification today. Now it should work.
Thanks for your quick feedback :)
-
Haha, thanks for the quick fix. It does indeed work fine again. :)
-
The shader example has one error: the global shader mousey parameters seems to be working like 1-mouseY.
If you replace the update code like this, it works.
// Update the shaders
backgroundShader.Update(mouseX, mouseY);
entityShader.Update(mouseX, mouseY);
globalShader.Update(mouseX, 1-mouseY);
-
It fixes only the "fisheye" effect, all other effects get broken.
This is not really an error, actually the fisheye effect should be more complex in order to handle properly the texture coordinates.
-
I thought the problem wasn't fisheye, but globalShader :D
Is it because you are using a RenderImage?
-
I thought the problem wasn't fisheye, but globalShader
It is fisheye with globalShader ;)
Is it because you are using a RenderImage?
Yes, the internal texture of a render-image is flipped compared to a regular image. And the effect doesn't take that in account.
-
I thought the problem wasn't fisheye, but globalShader
It is fisheye with globalShader ;)
Is it because you are using a RenderImage?
Yes, the internal texture of a render-image is flipped compared to a regular image. And the effect doesn't take that in account.
May I ask why? Some sort of optimization?
-
No, it's just the way OpenGL draws to a render-texture. Actually, it forces me to add some ugly hacks to handle it.
-
Whenever I try to use sf::Shader::CurrentTexture it does not link telling me "unresolved external symbol "public: static class sf::Image const sf::Shader::CurrentTexture"". This also happens in the Shader example. I have linked sfml-graphics.lib and other graphics do work fine. I am using SFML2 revision 1399.
Thanks.
-
You forgot to define SFML_DYNAMIC.
-
why did you remove the preprocessing step? seem very odd. what you had in there was a very clean, very easy to use version of the GLSL shader language.
-
Basically, people had to learn GLSL and then unlearn a few things and replace them with SFML specific stuff. I find it more natural to use plain GLSL.
-
Basically, people had to learn GLSL and then unlearn a few things and replace them with SFML specific stuff. I find it more natural to use plain GLSL.
Mhm, yeah that is true I guess. I remember getting confused with the GLSL syntax a few times when I started using it together with the "sfmlglsl".
But without all the gl_Whatever stuff in the shader files it just seemed way more streamlined with the rest of SFML to me.
Maybe a solution would be to write a more detailed tutorial about pixel shaders in general?
I know it would cost you time, but you wouldn't have to go into syntax specific things like "put a ; after every statement". You'd just have to tell people: This is how you address pixels of a texture, this is how you manipulate it's color, and this is how you put it out to the screen. And maybe something like: "A pixel shader does that, and it works like this" etc.
Or you could somehow provide us with the preprocessing code so we can include it in our code ourselves?
But whatever, it isn't too big of a deal I guess. It's one of the few (if not only) 2D libraries where we even get to use pixel shaders so I'm happy :)
-
I know it would cost you time, but you wouldn't have to go into syntax specific things like "put a ; after every statement". You'd just have to tell people: This is how you address pixels of a texture, this is how you manipulate it's color, and this is how you put it out to the screen. And maybe something like: "A pixel shader does that, and it works like this" etc.
It's even simpler with the current design: "read any GLSL tutorial and you're ready to use sf::Shader".
Or you could somehow provide us with the preprocessing code so we can include it in our code ourselves?
You're free to implement a different shader syntax and the proprocessor that goes with it. You can pick the code in sf::PostFx and base your implementation on that.