Ren'Py How do you return all displayable's, on layer master, as a composite texture or similar, to be passed to a shader?

hakarlman

Engaged Member
Jul 30, 2017
2,130
3,346
How do you return all displayable's, on layer master, as a composite texture or similar, to be passed to a shader? There's got to be a quick and easy way to do this, without having to manually build a composite image of the entire scene; background & characters, etc.

I'm looking for a function like this or similar:
Code:
# returns all displayables, minus the UI, as a composite texture which can be passed to shader
Image dynamic_image_for_screen_shader = renpy.layer["master"].returnCompositeTextureImage()
The above functionality may look like something else.

The goal is to pass the current scene to a shader like this, but without having to manually build the scene via composite image:
Code:
# i shouldn't have to do this, isn't there a renpy way to get current scene as texture?
image dynamic_current_scene_image = Composite(
    (1920, 1080),
    (dynamicImg01_x, dynamicImg01_y), dynamicImg01,
    (dynamicImg02_x, dynamicImg02_y), dynamicImg02)

label test():
    show screen_shader_combined_image_of_scene:
        shader("photoshop.special_effect_05")
        Model().child("dynamic_current_scene_image ").child("images/soft_light_overlay_effect05.png")
 
    "Screen Shader Applied"
    hide screen_shader_combined_image_of_scene
    "Black Screen"
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,964
16,210
How do you return all displayable's, on layer master, as a composite texture or similar, to be passed to a shader?
Hmm...

The first point, is to get the displayable on a given layer. This can be done with ; the function return a set, therefore the list will not be ordered.
But this will only give you the name (string) of the images/displayable. Once there, you'll have to use in order to get the displayable itself, and not just its name. Since renpy.get_showing_tags()'s set can contain both displayable and image, you'll have to take care of the value returned by [URL='https://renpy.org/doc/html/displaying_images.html#renpy.get_registered_image'][icode]renpy.get_registered_image()[/URL][/icode] in order to discriminate between the two.
In the end, it's something that would looks more or less like this:
/!\ WARNING /!\ Code wrote on the fly
Python:
init python:
    def allDisplayables( layer ):
        retVal = []
        for i in renpy.get_showing_tags( layer ):
            tmp = renpy.get_registered_image( i )
            if tmp is None:
                retVal.append( i )
            else:
                retVal.append( tmp )

        return retVal
The second point is to create an image with them... This is way more tricky because Ren'Py assume way too much.
There's the function, but it works only with displayable, not with direct images. And like the doc say, the value are trustworthy only when they are trustworthy, while you can't never be sure that they will be trustworthy at the moment you'll look at them.

And here lie the problem, you can't replicate the screen as displayed by Ren'Py. You aren't sure about the position of the displayable, and you have no way to get the position if you use direct images.
In the same time, there isn't a way to get the full screen as built by Ren'Py. And even if there were, at this time the data format isn't anymore something you can tweak.

There's perhaps a way to apply a shader to a whole layer, but my knowledge regarding the model based rendering is far to be good ; it's a fucking mess inside this and I don't really had the time to dive deep.
 
  • Like
Reactions: hakarlman

hakarlman

Engaged Member
Jul 30, 2017
2,130
3,346
There's perhaps a way to apply a shader to a whole layer, but my knowledge regarding the model based rendering is far to be good ; it's a fucking mess inside this and I don't really had the time to dive deep.
I'm currently diving in deep. There has to be a way to just apply a simple screen shader to the layer master, or to renpys render tree or something. It's the equivalent of using screen shaders in a 3d game. I wish Renpy made this simpler to add.
 

shark_inna_hat

Active Member
Game Developer
Dec 25, 2018
705
2,765
What you want to do is render to a offscreen texture buffer (FBO) apply it to a fullscreen quad (or a very large triangle, for extra street cred) and render that into the main frame buffer.

The other way to do it is by coping the content of the framebuffer to a texture (glBlitFramebuffer) and doing the whole fullscreen quad thing again, but this is slow. Not like Python slow, but hardware level slow.

How to do that in renpy? Heh, if I'd knew I'd probably wouldn't be writing my own engine :(
 
  • Like
Reactions: hakarlman