Best way to add post-effects

I’m thinking of adding some post-effects into the game with the possibility to dynamically turn them on/off. What might be the best (easiest/tidiest) way to do that?
Right now i can only think of the solutionn using the 1x1 quads for each post-effect, i.e. in render script:
0. Add multiple quads to the scene, each with unique rendering tag. Create one render texture, that will be used in each post-effect shader

  1. With no post-effects enabled render camera straight to the screen
  2. Otherwise, render it to the texture. After that render enabled post-effects one-by-one into the same texture, and the last one onto the screen.

So, the questions are:

  1. Can i use the same render texture as input of the shader and as current render target? If not, i’ll ahve to create unique texture for every shader (and render every effect into the texture used in the next effect).
  2. Are there any limitations to max amount of render predicates or something like that?
  3. Could there be any better ways to do that?

I think that there are no other ways to do it. I used a few render target for 2d light.
I use one quad model for all render target. I think you can have 2 render target.And draw post-effect first at texture one, second in texture two, then again one, etc.
1)I do not think that your can use same render texture as input of the shader and as current render target.It sound’s like bad idea to change texture, and use this texture in shader in same time.
Please write something about your solution, because i later will need some post-effects for my game.:slight_smile:

I’ll have to use multiple quads, as each effect requires its own shader (and material) to be drawn.

Please write something about your solution

Will do, hope i’ll get something running soon, but might focus on other things first.

You can change material by render.enable_material(“material_id”)


To enable material, first add it to render, then you can change it,in render script

Nice, didn’t see this function, thx!

Managed to run two post-effects simultaneously. Right now i’m reading and writing from the same texture and it works for me, at least in editor. If this wouldn’t work in the future, it can easily be fixed by something like this (pseudocode):

enable_render_target(texture_1)
enable_texture(0, texture_2)
-- Draw effect #1
disable_texture(0, texture_2)
disable_render_target(texture_1)

enable_render_target(texture_2)
enable_texture(0, texture_1)
-- Draw effect #2
disable_texture(0, texture_1)
disable_render_target(texture_2)

...

enable_texture(0, texture_1)
-- Draw last effect onto the screen, choose the needed texture from the previous pass
disable_texture(0, texture_1)

-- Of course, doing all this in cycle, not with copy-pasting like here

Right now my code looks like this:

  -- TODO Check if we have any effect to render, otherwise it will break rn
  render.enable_render_target(self.target_effect)
  -- draw everything as usual here, render target texture has screen's width and height
  ...
  render.disable_render_target(self.target_effect)

  -- Prepare render parameters, ignore depth, cull and everything, 
  -- as we are drawing from quad to quad now and shouldn't care about any of this 
  -- (i don't have this as i have everything disabled before in main render)
  render.set_depth_mask(false)
  render.disable_state(render.STATE_DEPTH_TEST)
  render.disable_state(render.STATE_CULL_FACE)

  -- Set up projections to render quad
  render.set_view(vmath.matrix4())
  render.set_projection(vmath.matrix4())

  -- Render every effect
  local effects = { 'effect_grain', 'effect_night' } -- Currently enabled effects, materials added in the *.render file
  local effects_count = #effects
  for i, effect_name in ipairs(effects) do
    local drawing_to_texture = i < effects_count
    if drawing_to_texture then
      -- Draw every effect except the last one into the texture
      -- Should probably call this only once
      render.enable_render_target(self.target_effect)
    end

    -- Enable texture for shader to read
    render.enable_texture(0, self.target_effect, render.BUFFER_COLOR_BIT)

    -- Create constants buffer with time for post-effects
    local constants_buffer = render.constant_buffer()
    constants_buffer.time = vmath.vector4(RenderHelper.time)

    -- Clear previous data (not needed if everything is filled and depth buffer is ignored etc)
    --render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1 })

    -- Swap material for the effect and draw our quad
    render.enable_material(effect_name)
    render.draw(self.quad_effect_pred, constants_buffer)
    render.disable_material(effect_name)

    -- Disable texture for reading, could probably call that on the last effect (only once)
    render.disable_texture(0, self.target_effect)

    if drawing_to_texture then
      render.disable_render_target(self.target_effect)
    end
  end

  -- Render gui as usual (render it in the beginning if needed)
  ...

3 Likes

I have another question now. Lets say, i want to pass 2 additional textures to the shader. This is “constant” textures - sprites in project. How can add them to the shader. Right now i suppose i only have DIFFUSE_TEXTURE, which is “Texture” field in the model object, so i can add one texture (though it will be the same for every effect shader, because i use one quad for each of them), how can i add another one?
I don’t quite understand how does “samplers” array in materials settings work and if i can use it somehow.