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

Author Topic: Mixing shaders  (Read 3093 times)

0 Members and 1 Guest are viewing this topic.

ThaxSillion

  • Newbie
  • *
  • Posts: 5
    • View Profile
Mixing shaders
« on: January 05, 2011, 01:05:09 pm »
Hello,

I have come upon a problem with applying several shaders to an image.
What I'm currently doing is I'm drawing all the necessary stuff to a RenderImage, and then I keep copying it to image, and drawing again with a different shader.

The main loop code:
Code: [Select]

window.Clear();

rim.Clear();
rim.Draw(background);
rim.Display();

RenderToImage(rim);
sf::Sprite test(rim.GetImage());
window.Draw(test);


RenderToImage function:
Code: [Select]

void CEffectManager::RenderToImage(sf::RenderImage &_renderimage)
{
std::list<CBaseEffect*>::iterator it = m_Effects.begin();

for ( ; it != m_Effects.end(); it++)
{
m_CopyImage = _renderimage.GetImage();

_renderimage.Clear();
_renderimage.Draw(sf::Sprite(m_CopyImage), *(*it));

_renderimage.Display();
}
}


The problem is only one shader will apply. Each of the shaders work.
I tried searching the forums but couldn't find any solution (or maybe I searched too little?). What might be wrong?

Thanks in advance

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Mixing shaders
« Reply #1 on: January 05, 2011, 01:15:38 pm »
It looks good. Could make a complete and minimal code with this, so that I can test it?

By the way, there's no need to copy the image, the most efficient way to apply several shaders is to use a kind a double-buffering as shown here (french):
http://www.sfml-dev.org/forum-fr/viewtopic.php?p=31824#31824
Laurent Gomila - SFML developer

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Mixing shaders
« Reply #2 on: January 05, 2011, 03:15:46 pm »
In theory, if you draw the same image with different shaders, it will be drawing each time on top of the previous, so, only the last shader effect will be seen.

Isn't this right for this case?

As far as i know, when dealing with multiple shader effects for the same renderization, people composite the shader code, so all effects are programmed in the same shader. This is done programmaticly or mannualy,

Is this right? :)

ThaxSillion

  • Newbie
  • *
  • Posts: 5
    • View Profile
Mixing shaders
« Reply #3 on: January 05, 2011, 03:57:30 pm »
If nothing can be done, I can actually put all the effects in one shader file, but I guess it should be possible to re-draw objects to RenderImages several times but with different shaders.

Here is the minimal code (I hope):
Code: [Select]

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

std::string pixelate = "uniform sampler2D texture;\
uniform vec2 mouse;\
\
void main()\
{\
float factor = 5 + 100 * length(mouse);\
vec2 pos = floor(gl_TexCoord[0].xy * factor + 0.5) / factor;\
\
gl_FragColor = texture2D(texture, pos) * gl_Color; \
}\
";

std::string colorize = "\
uniform sampler2D texture;\
uniform vec3 color;\
\
void main()\
{\
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * gl_Color;\
float gray = pixel.r * 0.39 + pixel.g * 0.50 + pixel.b * 0.11;\
\
gl_FragColor = vec4(gray * color, 1.0) * 0.6 + pixel * 0.4;\
gl_FragColor.a = pixel.a;\
}\
";

int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Shader");

// Load a background image to display
    sf::Shape Circle = sf::Shape::Circle(400, 300, 100, sf::Color::White);

    sf::Shader shaders[2];
    shaders[0].LoadFromMemory(pixelate.c_str());
    shaders[1].LoadFromMemory(colorize.c_str());

    shaders[0].SetTexture("texture", sf::Shader::CurrentTexture);
    shaders[1].SetTexture("texture", sf::Shader::CurrentTexture);
    shaders[1].SetParameter("color", 1.f, 1.f, 1.f);

    sf::RenderImage rim, buffer;
    rim.Create(800, 600);
    buffer.Create(800, 600);

    sf::RenderImage *front = &rim;
    sf::RenderImage *back = &buffer;

    // Start the game loop
    while (window.IsOpened())
    {
        // Process events
        sf::Event event;
        while (window.GetEvent(event))
        {
            // Close window : exit
            if (event.Type == sf::Event::Closed)
                window.Close();
        }

        shaders[1].SetParameter("color", (1.0f / window.GetInput().GetMouseX()) * 800.0f, 1.0f, 1.0f);
shaders[0].SetParameter("mouse", (float)window.GetInput().GetMouseX() / static_cast<float>(window.GetWidth()), (float)window.GetInput().GetMouseY() / static_cast<float>(window.GetHeight()));

        window.Clear();

back->Clear();
        back->Draw(Circle);
        back->Display();

for ( int i = 0; i < 2; i++)
{
front->Clear();
front->Draw(sf::Sprite(back->GetImage()), shaders[i]);
front->Display();

std::swap(front, back);
}

sf::Sprite test(back->GetImage());

        window.Draw(test);

        // Finally, display the rendered frame on screen
        window.Display();
    }
}



The last shader's parameter is not updated (?) Actually this looks like a different problem.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Mixing shaders
« Reply #4 on: January 05, 2011, 06:11:18 pm »
Quote
The last shader's parameter is not updated (?) Actually this looks like a different problem.

So what's the problem actually? ;)

Does it work if you use very simple shaders (like outputing a single color), with no parameter?
Laurent Gomila - SFML developer