So i am working on my game project using SFML and I tried to implement a blur shader. I have no idea why , but this block of code makes the program show a white screen and then close.I didn't even use the shader to draw anything , just the fact that I am trying to load it gives the unexpected result :( .
void button::setText(std::string _text)
{
text.setString(_text);
text.setFont(font);
text.setCharacterSize(80);
text.move(0,-(text.getLocalBounds().top));
text.setColor(sf::Color(255,255,255,255));
width=text.getLocalBounds().width+text.getLocalBounds().left;
height=text.getLocalBounds().height+text.getLocalBounds().top;
rndtexture.create(width, height);
rndtexture.setSmooth(true);
rndtexture.clear(sf::Color::Transparent);
rndtexture.draw(text);
rndtexture.display();
rTexture=rndtexture.getTexture();
spriteR.setTexture(rTexture);
rndtexture.clear(sf::Color::Transparent);
text.setColor(sf::Color(0,0,0,100));
rndtexture.draw(text);
rndtexture.display();
pTexture=rndtexture.getTexture();
spriteP.setTexture(pTexture);
//commenting this out will make it work just fine
if (!shader.loadFromFile("shader.frag", sf::Shader::Type::Fragment))
{
std::cout<<"lol";
}
//
shader.setParameter("texture", sf::Shader::CurrentTexture);
shader.setParameter("blur_radius", 5.0);
}
This is my shader file:
uniform sampler2D texture;
uniform float blur_radius;
void main()
{
vec2 offx = vec2(blur_radius, 0.0);
vec2 offy = vec2(0.0, blur_radius);
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 4.0 +
texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
gl_FragColor = gl_Color * (pixel / 16.0);
}
What is wrong with this.. ?
What's the return value when you call:
sf::Shader::isAvailable()
Make sure you can use a shader program before you call it. Also, a shader can't crash a program, so it's definitely not your shader. If something was wrong with your shader, it wouldn't compile. If your shader didn't compile, then SFML automatically switches to a built-in shader.
Related
I am trying to make a fragment shader for a 2d art style im working on.
But to make that work i must make a texture able to overlap itself multiple times.
result i want and the 2 current results:
Edit1: in my art style i have 1 texture per plane. to make the illusion of each plane having thickness i need it to draw it self 2 times, with one pixel distance.
illustration:
if it was drawn a green plane then a blue plane, yes i would like to replace the green area with blue where it overlaps.
I have attempted to subtract the next texture location to nullify texture blending, but resulted in also adding negative values at empty area.
```
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform float shxx;
uniform float shyy;
void main()
{
vec2 Coord1 = v_vTexcoord + vec2(0,0);
vec2 Coord2 = v_vTexcoord + vec2(shxx,shyy);
vec2 Coord3 = v_vTexcoord + vec2(shxx+shxx,shyy+shyy);
vec2 Coord4 = v_vTexcoord + vec2(+shxx+shxx+shxx,+shyy+shyy+shyy);
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, Coord1)
- v_vColour * texture2D( gm_BaseTexture, Coord2)
+ v_vColour * texture2D( gm_BaseTexture, Coord2)
- v_vColour * texture2D( gm_BaseTexture, Coord3)
+ v_vColour * texture2D( gm_BaseTexture, Coord3)
- v_vColour * texture2D( gm_BaseTexture, Coord4)
+ v_vColour * texture2D( gm_BaseTexture, Coord4);
}
```
Found a solution. every time i subtract next textures position i set all fragments with alpha value less than 0,9 to default color black. this way the next texture gets drawn on top of no existing colors. thus avoiding the textures blending into white.
Final Result = https://i.imgur.com/aexqIts.png
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform float shxx;
uniform float shyy;
void main()
{
vec2 Coord1 = v_vTexcoord + vec2(0,0);
vec2 Coord2 = v_vTexcoord + vec2(shxx,shyy);
vec2 Coord3 = v_vTexcoord + vec2(shxx+shxx,shyy+shyy);
vec2 Coord4 = v_vTexcoord + vec2(+shxx+shxx+shxx,+shyy+shyy+shyy);
vec2 Coord5 = v_vTexcoord + vec2(+shxx+shxx+shxx+shxx,+shyy+shyy+shyy+shyy);
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, Coord1)
- texture2D( gm_BaseTexture, Coord2)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord2)
- texture2D( gm_BaseTexture, Coord3)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord3)
- texture2D( gm_BaseTexture, Coord4)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord4)
- texture2D( gm_BaseTexture, Coord5)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord5);
}
I'm trying to write a custom shader where I first blur the texture and then run sobel edge finding.
I've got sobel running ok via the following script
vec4 colorSobel = texture2D(texture, uv);
float bottomLeftIntensity = texture2D(texture, uv + vec2(-0.0015625, 0.0020833)).r;
float topRightIntensity = texture2D(texture, uv + vec2(0.0015625, -0.0020833)).r;
float topLeftIntensity = texture2D(texture, uv + vec2(-0.0015625, 0.0020833)).r;
float bottomRightIntensity = texture2D(texture, uv + vec2(0.0015625, 0.0020833)).r;
float leftIntensity = texture2D(texture, uv + vec2(-0.0015625, 0)).r;
float rightIntensity = texture2D(texture, uv + vec2(0.0015625, 0)).r;
float bottomIntensity = texture2D(texture, uv + vec2(0, 0.0020833)).r;
float topIntensity = texture2D(texture, uv + vec2(0, -0.0020833)).r;
float h = -secondary * topLeftIntensity - coef * topIntensity - secondary * topRightIntensity + secondary * bottomLeftIntensity + coef * bottomIntensity + secondary * bottomRightIntensity;
float v = -secondary * bottomLeftIntensity - coef * leftIntensity - secondary * topLeftIntensity + secondary * bottomRightIntensity + coef * rightIntensity + secondary * topRightIntensity;
float mag = length(vec2(h, v));
// alpha values removed atm
if (mag < 0.5) {
colorSobel.rgb *= (1.0 - 1.0);
colorSobel.r += 0.0 * 1.0;
colorSobel.g += 0.0 * 1.0;
colorSobel.b += 0.0 * 1.0;
colorSobel.rgb += 1.0 * mag;
} else {
colorSobel.rgb *= (1.0 - 1.0);
colorSobel.r += 0.0 * 1.0;
colorSobel.g += 0.0 * 1.0;
colorSobel.b += 0.0 * 1.0;
colorSobel.rgb += 1.0 * mag;
}
gl_FragColor = colorSobel;
However I know it works by sampling the texture via texture2D.
If I were to first manipulate the output via a simple script such as this which reduces the colours
vec4 bg = texture2D(texture,uv);
gl_FragColor = vec4(gb.rgb, 1.0);
gl_FragColor.r = float(floor(gl_FragColor.r * 0.5 ) / 0.5);
gl_FragColor.g = float(floor(gl_FragColor.g * 0.5 ) / 0.5);
gl_FragColor.b = float(floor(gl_FragColor.b * 0.5 ) / 0.5);
The output still samples from the texture and ignores the first paint.
Is there a way to sample from the color output rather than using texture2D?
The reason I'm asking is that i'm chaining my shaders at runtime depending on user interaction?
I'm trying to implement a SFML Shader following their example and it doesn't show up.
GameObject is a class that inherits and implements sf::Drawable. Inside GameObject I have a sf::Texture and a sf::Sprite objects, responsible for the image of the game object. I'm trying to apply a blur effect on it. Here's the .cpp where I load the image and shader:
x = new GameObject("Images/apple.png", 100, 100, 1, 1);
mshade.loadFromFile("Shaders/blur.frag", sf::Shader::Fragment);
mshade.setParameter("texture", *(x)->objectTexture);
mshade.setParameter("blur_radius", 200);
And this is how I draw it:
gameWindow->draw(*x, &mshade);
And this is the GLSL code to create the blur shader:
uniform sampler2D texture;
uniform float blur_radius;
void main()
{
vec2 offx = vec2(blur_radius, 0.0);
vec2 offy = vec2(0.0, blur_radius);
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 4.0 +
texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
gl_FragColor = gl_Color * (pixel / 16.0);
}
But for some reason the image is displayed just as normally, without any effect. I also don't get any error. Does anyone know why the blur effect doesn't show up?
I don't know anything about SFML, but i looks like your blur_radius is not well chosen.
Your image has the size 100x100 and you Blur-Shader samples the image with distance of 200px (blur_radius). So if your texture has gl_repeat enabled , you hit exactly the same pixel as the original one. -> no blur
Try using a lower blur_radius maybe something around 2-5
Well in my question at: SFML shader not working I got help on this issue aswell I recoomend you go check out tntxtnt's answer that will probably help you. but basicly it dosent blur the outline of the textures it only blurs the colors inside the sprite.
I am trying to implement the Ashikhmin-Shirley model using these formulas:
This is the GLSL 1.2 fragment shader code:
uniform vec4 materialAmbient, materialDiffuse, materialSpecular;
uniform float materialShininess;
uniform vec4 lightAmbient, lightDiffuse, lightSpecular, lightPosition;
varying vec3 P,N;
float pi= 3.1415926535;
vec4 Fd(float NdotV, float NdotL) {
vec4 fd= (28.0 * materialDiffuse * lightDiffuse) / (23.0 * pi) * (1.0 - materialSpecular * lightSpecular);
fd*= 1.0 - pow(1.0-NdotV/2.0,5.0);
fd*= 1.0 - pow(1.0-NdotL/2.0, 5.0);
return fd;
}
vec4 Fr(float u, vec4 specular) {
return specular + (1.0-specular) * pow(1.0 - u, 5.0);
}
// f= phi
vec4 Fs(float VdotH, float NdotH, float NdotL, float NdotV, float et, float eb, float f) {
vec4 fs= Fr(VdotH, materialSpecular * lightSpecular);
fs*= sqrt((et+1.0) * (eb+1.0)) / (8.0 * pi);
fs*= pow(NdotH, et*pow(cos(f),2.0) + eb*pow(sin(f),2.0)) / (VdotH * max(NdotL, NdotV));
return fs;
}
void main(void) {
vec3 L= normalize(vec3(lightPosition) - P);
vec3 V= cameraPosition;
vec3 H= normalize(L+V);
float NdotL= max(dot(N,L),0.0);
float NdotV= max(dot(N,V),0.0);
float NdotH= max(dot(N,H),0.0);
float VdotH= max(dot(V,H),0.0);
gl_FragColor= Fd(NdotV, NdotL) + Fs(VdotH, NdotH, NdotL, NdotV, 128.0,128.0,1.0);
}
I already checked and it seems like all the uniforms and varying are passed in the right way, I pass P and N from the vertex shader. The variables are:
Light direction: L;
Surface normal: N;
Camera direction: V;
Half vector: H;
Fragment position: P.
The uniforms I pass are:
light{Specular | Diffuse | Ambient} : 0xffffff (converted to a rgba vector of course);
materialAmbient: 0x543807 ;
materialDiffuse: 0xc6901d;
materialSpecular: 0xfdefce;
materialShininess: 27.8974.
This is the result I get:
Which seems very strange to me, I've seen other images of Ashkhmin-Shirley implementations on the web, and they aren't similar. This is an example:
I want one like this !! Maybe I am using wrong values of phi and other values? Or there's something wrong in the formula?
I think you might be missing braces here:
vec4 fd= (28.0 * materialDiffuse * lightDiffuse) / (23.0 * pi) * (1.0 - materialSpecular * lightSpecular);
try
vec4 fd= ((28.0 * materialDiffuse * lightDiffuse) / (23.0 * pi)) * (1.0 - materialSpecular * lightSpecular);
instead.
I have an object that is a 2d array of sf::RectangleShapes (for a tile-based game). It's supposed to look like a cloud, so I want to add some blur to it. Here is what it looks like now:
And I want it to look like this:
Instinctively, it seems to achieve this blur effect on the low level, I would have to draw the cloud object to a buffer, and then apply the blur object to the buffer. But I'm not sure if SFML is doing this already.
In my main loop, I have this:
for( CloudIterator it = clouds.begin(); it != clouds.end(); it++ ) {
window.draw(**it);
}
Which I hope to replace with:
for( CloudIterator it = clouds.begin(); it != clouds.end(); it++ ) {
window.draw(**it, &blurShader);
}
Where blurShader is loaded from the following GLSL file:
uniform sampler2D texture;
uniform float blur_radius;
void main()
{
vec2 offx = vec2(blur_radius, 0.0);
vec2 offy = vec2(0.0, blur_radius);
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 4.0 +
texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
gl_FragColor = gl_Color * (pixel / 16.0);
}
However, the result is clouds that are completely black. Is the texture referred to in the GLSL file something I have to load?
My draw code for these cloud objects looks like this, overloaded from sf::Drawable :
void Cloud::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
...loop to draw various sf::RectangleShape's in the Cloud...
}
So, I may be a little naive that window.draw(**it, &blurShader) would just work. Should I be fetching and applying the shader in the Cloud::draw function?
However, the result is clouds that are completely black. Is the texture referred to in the GLSL file something I have to load?
I'm pretty sure you'll have to set the texture yourself. If you look at the shader example, when each shader is loaded the author binds the current texture as the texture parameter. You'll probably have to do the same thing.
m_shader.setParameter("texture", sf::Shader::CurrentTexture);
If sf::Shader::CurrentTexture refers to a different texture, then you'll have to explicitly obtain the correct texture. If your sf::RectangleShapes don't have a texture, then of course you can't blur something that isn't there.
In the case where your shapes do not have a texture of their own, you may be able to achieve the desired effect by rendering the shapes to an sf::RenderTexture, and then rendering an sf::Sprite using the sf::RenderTexture and applying the shader to that draw call.