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

Author Topic: Sharing shaders!  (Read 2120 times)

0 Members and 1 Guest are viewing this topic.

jamesk

  • Guest
Sharing shaders!
« on: May 03, 2018, 06:37:02 am »
While refactoring my code I reuse the same shader multiple times through my game. I decided to do what I've done with audio and textures: make a resource manager for shaders. Then I realized something terrible.

shader->setUniform() affects everyone's shader state so the last entity to Update() and touch the shader before Render() is the one whos values are used.

How can I share a shader so I do not keep loading the same scripts over and over while keeping the uniforms seperate?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sharing shaders!
« Reply #1 on: May 03, 2018, 07:55:13 am »
What's the problem? You use the manager to load the shader only once and share it with all entities that need it, but then each entity sets its own uniforms when it is drawn.
Laurent Gomila - SFML developer

jamesk

  • Guest
Re: Sharing shaders!
« Reply #2 on: May 03, 2018, 01:55:44 pm »
No because the pipeline is not

# Entity 1
Update()
Draw()

# Entity 2
Update()
Draw()

...

The order is

# Entities 1 - N
Update()

# Entities 1 - N
Draw()

It is very specific at this time. Is there a way I can share the shader program without sharing uniforms?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sharing shaders!
« Reply #3 on: May 03, 2018, 02:13:12 pm »
No, uniforms are part of the shader program.

But I'd say your program flow is wrong. Setting shader uniforms should not be part of an update function. Since you're sending values that are used for drawing stuff, it should definitely be done in the draw function.
Laurent Gomila - SFML developer

jamesk

  • Guest
Re: Sharing shaders!
« Reply #4 on: May 03, 2018, 02:58:21 pm »
It's not wrong it's by design. We are using components and each system updates their respective components. Hence update() then in render component, draw().

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sharing shaders!
« Reply #5 on: May 03, 2018, 03:10:33 pm »
So it's your design that is wrong ;) It definitely makes no sense to have the update of a graphical state in a location which is totally unrelated to the location where you draw using that state.

What you could do is to compute the uniforms in update(), but then store them and send them to the shader in draw().
« Last Edit: May 03, 2018, 03:12:30 pm by Laurent »
Laurent Gomila - SFML developer

jamesk

  • Guest
Re: Sharing shaders!
« Reply #6 on: May 03, 2018, 03:11:26 pm »
No quit being an ass. It's clear there's no immediate way to do this.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sharing shaders!
« Reply #7 on: May 03, 2018, 03:13:42 pm »
Just to be sure: I edited my post when you were replying, so make sure that you didn't miss the update.
Laurent Gomila - SFML developer

jamesk

  • Guest
Re: Sharing shaders!
« Reply #8 on: May 03, 2018, 11:29:12 pm »
The graphical state has everything to do with the representation of the object. Position, health status, other modifications, etc. can be represented as visual effects.

What I'm looking at doing is writing a wrapper for sf::Shader that maps from entity to their intended value and then in the draw() method, pass the entity in, find the value, and set the shader uniform.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sharing shaders!
« Reply #9 on: May 04, 2018, 06:34:26 am »
Since you're using a component-entity system, I guess you have a dedicated component for drawing, that uses the shader. Then wouldn't it be simpler to store the uniforms inside that component?
Laurent Gomila - SFML developer

jamesk

  • Guest
Re: Sharing shaders!
« Reply #10 on: May 04, 2018, 07:00:15 am »
It could. I would need to change the way components behave by accessing other component's information.

I ended up writing a smart shader. It keeps a table of individual uniform values and a reference to the sf::Shader. It also overloads copy and assignment operators with sf::Shader so you can use it naturally: e.g.

sf::Shader* GetShader(ShaderType type) { ... }
SmartShader pixelate = GetShader(ShaderType::PIXEL_BLUR);
pixelate.SetUniform("factor", timer/maxTimer);

In order to share between other entities it has a function called
ApplyUniforms()
that steps through the table and setting uniform values before the engine calls
Draw()
on the entity.

After drawing for cleanliness sake there's another function
ResetUniforms()
that sets the uniforms to the type-equivalent of zero.

At any time SmartShaders can free the reference to an sf::Shader by using
Release()
.

I'm satisfied with the results.
« Last Edit: May 04, 2018, 07:01:51 am by jamesk »

 

anything