Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Drawing on transparrent renderTextures (using shaders)  (Read 2440 times)

0 Members and 2 Guests are viewing this topic.

adge

  • Newbie
  • *
  • Posts: 6
    • View Profile
Drawing on transparrent renderTextures (using shaders)
« on: October 18, 2017, 03:13:59 pm »
Please have a look at this code:

#include <iostream>
#include <conio.h>
#include <SFML/Graphics.hpp>

using namespace std;
using namespace sf;

float stepSizeMultiplier = 2.0f;
unsigned int additionalTextureSize = 200;

int main()
{
        // Create the window
        RenderWindow window(VideoMode(800, 600, 32), "SFML Shader Test", Style::Default);
        Event eve;

       
        // Create a Sprite with a texture
        Texture texture;
        texture.loadFromFile("Resources/Textures/stoneHouse.png");
        texture.setSmooth(true);
        Sprite sprite(texture);
        sprite.setPosition(400.0f, 100.0f);
        sprite.setScale(1.3f, 1.3f);
        sprite.setRotation(7);

        // Create the Render Textures
        RenderTexture outlineTexture;
        outlineTexture.create(sprite.getGlobalBounds().width + 2 * additionalTextureSize, sprite.getGlobalBounds().height + 2 * additionalTextureSize);
        outlineTexture.setSmooth(true);


        // Create the outline shader
        Shader outlineShader;
        outlineShader.loadFromFile("Resources/Shader/outlineShader.txt", Shader::Fragment);
        outlineShader.setUniform("texture", Shader::CurrentTexture);
        outlineShader.setUniform("edge_threshold", 10.0f / sprite.getGlobalBounds().width);

        // Create the blur shader
        Shader blurShader;
        blurShader.loadFromFile("Resources/Shader/blurShader.txt", Shader::Fragment);
        blurShader.setUniform("texture", Shader::CurrentTexture);
        blurShader.setUniform("blur_radius", 2.0f / (sprite.getGlobalBounds().width + additionalTextureSize * 2));

       

        // If ome of the shaders is not available
        if (!outlineShader.isAvailable() || !blurShader.isAvailable())
                cerr << endl << "Shaders are not available on this system!";

        while (window.isOpen())
        {
                while (window.pollEvent(eve))
                {
                        if (eve.type == Event::Closed)
                                window.close();
                        if (eve.type == Event::KeyReleased)
                                if (eve.key.code == Keyboard::Key::Escape)
                                        window.close();
                }

                window.clear();

                // Draw a rectangle to see where the renderTexture is
                RectangleShape rectagle(static_cast<Vector2f>(window.getSize()));
                rectagle.setFillColor(Color::Red);
                window.draw(rectagle);

                // Draw the outline renderTexture
                outlineTexture.clear();

                // Draw a transparent rectangle
                RectangleShape rect(static_cast<Vector2f>(outlineTexture.getSize()));
                rect.setFillColor(Color::Transparent);
                outlineTexture.draw(rect, BlendMultiply);

                Vector2f position = sprite.getPosition();
                sprite.setPosition(additionalTextureSize, additionalTextureSize);
                outlineTexture.draw(sprite, &outlineShader);
                sprite.setPosition(position);
                outlineTexture.display();

                // Create an outline Sprite
                Sprite outlineSprite;
                outlineSprite.setTexture(outlineTexture.getTexture());
                outlineSprite.setOrigin(additionalTextureSize, additionalTextureSize);
                outlineSprite.setPosition(sprite.getPosition());

                // draw the sprite without the shader
                window.draw(sprite);

                // draw the outline with the blur shader
                window.draw(outlineSprite, &blurShader);

                window.display();
        }

        cout << endl << endl << "Press any key to end the program...";
        _getch();
        return EXIT_SUCCESS;
}

Short explanation:
I am trying to draw a sprite with a blured edge filter/shader ontop of it.

The code kinda works like this. However, I am planning on implementing such an effect into my engine and I have the feeling that I am doing a lot of unnecessary work here.

Oh, and before I forget (for completeness sake), here are the two shaders:

Outline shader:
uniform sampler2D texture;
uniform float edge_threshold;


void main()
{
    const float offset = 1.0 / 128.0;
    vec2 offx = vec2(offset, 0.0);
    vec2 offy = vec2(0.0, offset);


    vec4 hEdge = 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;


    vec4 vEdge = texture2D(texture, gl_TexCoord[0].xy - offx)        *  2.0 +
                 texture2D(texture, gl_TexCoord[0].xy + offx)        * -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;



    vec3 result = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb);
    float edge = length(result);
    vec4 pixel = gl_Color * texture2D(texture, gl_TexCoord[0].xy);

    if (edge > (edge_threshold * 8.0))
        //pixel.rgb = vec3(0.0);
        pixel.rgb = vec3(0.0, 0.89, 0.19);
    else
        pixel = vec4(0.0);
    gl_FragColor = pixel;
}

Blur Shader:
#version 130

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);
}

Your help is very much appreciated,

Kind Regards,

Adrian
« Last Edit: October 18, 2017, 03:21:33 pm by Laurent »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Drawing on transparrent renderTextures (using shaders)
« Reply #1 on: October 19, 2017, 08:29:01 am »
So what's the question?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

adge

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Drawing on transparrent renderTextures (using shaders)
« Reply #2 on: October 19, 2017, 09:23:37 am »
Sorry if I didn't make the question clear,

Problem:
I am trying to use an ede/outline detection filter (Fragment shader). Its not the outline shader I have posted below since the one I was intending to use doesn't quite work yet. Anyway, I can't detect an edge when a non-transparrent pixel is directly next to the end of the texture. This is why I found the solution with drawing on a renderTexture bigger than the original sprite instead. However, there was the issue that after drawing on this renderTexture and the  drawing the render texture ontop of other stuff, a black reectangle was shown. I found blendModes in the forum but they don't just ignore the black bit, if u know what I mean.

Now the Question(s):

Firstly,
Is there any (official) way of creating a transparrent renderTexture? (appart from drawing a transparrent rectangle of the same size ontop of it)

Secondly,
Is there any way to directly apply another shader to the outcome of the previous shader without having to redraw the entire thing to a renderTarget. So e.g. first the outline fragment shader and then the blur fragment shader using the result of the previous one. (I am quite new to shader programing so forgive me if thats a stupid question)

I hope this was a bit clearer,

Oh yeah, and thanks for taking the time to help!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Drawing on transparrent renderTextures (using shaders)
« Reply #3 on: October 19, 2017, 09:30:33 am »
Is there any (official) way of creating a transparrent renderTexture? (appart from drawing a transparrent rectangle of the same size ontop of it)
You can clear the render texture with any transparent color you want. Just apply the correct alpha value.

Is there any way to directly apply another shader to the outcome of the previous shader without having to redraw the entire thing to a renderTarget. So e.g. first the outline fragment shader and then the blur fragment shader using the result of the previous one. (I am quite new to shader programing so forgive me if thats a stupid question)
I'm not that much familiar with usage of shaders, but I don't think you can apply multiple shaders of the same time at the same time.

Keep in mind that blend modes can also be quite customized. I recommend checking out the documentation.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

adge

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Drawing on transparrent renderTextures (using shaders)
« Reply #4 on: October 19, 2017, 11:08:43 am »
Quote
You can clear the render texture with any transparent color you want. Just apply the correct alpha value.

True, I didn't think of that. Thats what I was looking for :)

With regards to the shaders; Drawing to intermediate render textures should work fine since the application is likey to be CPU bound anyway.

Thanks!