Skip to content

Implement Drawable Textures #7379

@reduz

Description

@reduz

Describe the project you are working on

Godot

Describe the problem or limitation you are having in your project

One feature that is widely requested in Godot is the ability to easily have a texture and just draw to it (or even run a custom shader).
Examples of things you want to do:

  • Animated textures
  • Smoke and fire using ping-pong transfers
  • Water plane effects
  • Effects such as painting
  • etc.

Traditionally this has be done with Viewports, but the whole thing is still relatively limited, as you can only write to a single image, writing to alpha is more complex, and you can't run multiple writing iterations per frame (ping-pong).

While in Godot 4.0+ users can access compute and RenderingDevice, this is still hard and beyond the level of experience of what most users can do, plus it won't work on GLES3 (compatibility) renderer.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Ideally, it should be possible to expose a very simple API to do this via RenderingServer, and an higher level DrawableTexture2D exposed for regular usage.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

At low level, the following API should be exposed for RenderingServer:

enum TextureDrawableFormat {
   TEXTURE_DRAWABLE_FORMAT_RGBA8,
   TEXTURE_DRAWABLE_FORMAT_RGBA8_SRGB, // Use this if you want to read the result from both 2D (non-hdr) and 3D.
   TEXTURE_DRAWABLE_FORMAT_RGBAH,
   TEXTURE_DRAWABLE_FORMAT_RGBAF,
};

// Create
RID texture_drawable_create(const Size2i& p_size, TextureDrawableFormat p_format,bool p_with_mipmaps = false);

// Draw

// Blit a rect
void texture_drawable_blit_rect(const Vector<RID> &p_textures, const Rect2i& p_rect, RID p_material,const Color& p_modulate,const Vector<RID>& p_source_textures,int p_to_mipmap=0); 
// Blit a polygon, 1 = point, 2 = line, 3 = polygon (will be tesselated). If UV provided, use these, otherwise UV is from dest texture.
void texture_drawable_blit_polygon(const Vector<RID> &p_textures, const PackedVector2Array& p_points, const PackedVector2Array& p_uvs,const PackedVector2Array& p_modulate_colors, RID p_material,const Vector<RID>& p_source_textures,int p_to_mipmap=0); 

// Utility functions
void texture_drawable_generate_mipmaps(RID p_texture); // Update mipmaps if modified
RID texture_drawable_get_default_material(); // To use with simplified functions in DrawableTexture2D

And that's it! We also need to add a new type of shader in Godot: SHADER_TYPE_TEXTURE_BLIT

Example of how to use:

shader_type texture_blit
// Optional render modes:
render_mode blend_mix /* default , also available: blend_add, blend_sub, blend_mul */;

uniform texture2D source_texture : hint_blit_source;
uniform texture2D source_texture2 : hint_blit_source2;
// up to 4 sources

void blit() {
     // Read sources and blit
     COLOR = texture(source_texture,UV) * MODULATE;
     COLOR2 = texture(source_texture2,UV);
     // up to COLOR4
}

Then put in a material and use.

Higher Level Abstraction

A resource can be provided:

class DrawableTexture2D : public Texture2D {
//...//
   enum DrawableFormat {
       DRAWABLE_FORMAT_RGBA8,
       DRAWABLE_FORMAT_RGBA8_SRGB,
       DRAWABLE_FORMAT_RGBAH,
       DRAWABLE_FORMAT_RGBAF,
   };
    void setup(Size2i p_size, DrawableFormat p_format,bool p_use_mipmaps=false);
    // Simple version without needing to use materials (uses a built-in material). Single source texture.
    void blit_rect(const Rect2i p_rect, const Ref<Texture2D>& p_source, const Color& p_modulate,int p_mipmap=0);
    void blit_polygon(const Rect2i p_rect, const Ref<Texture2D>& p_source, const PackedVector2Array& p_points const PackedVector2Array& p_uvs, const PackedColorArray& p_modulate,int p_mipmap=0);

    void blit_rect_multi(const Rect2i p_rect, const TypedArray<Ref<Texture2D>>& p_sources, const TypedArray<Ref<DrawableTexture2D>>& p_extra_targets, const Color& p_modulate,int p_mipmap=0);
    void blit_polygon_multi(const Rect2i p_rect,  const TypedArray<Ref<Texture2D>>& p_sources, const TypedArray<Ref<DrawableTexture2D>>& p_extra_targets,, const PackedVector2Array& p_points const PackedVector2Array& p_uvs, const PackedColorArray& p_modulate,int p_mipmap=0);

   void generate_mipmaps();
};

If this enhancement will not be used often, can it be worked around with a few lines of script?

N/A

Is there a reason why this should be core and not an add-on in the asset library?

N/A

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions