Skip to content

Add support for rasterizing mesh to texture with custom shader #12443

Open
godotengine/godot
#106331
@beicause

Description

@beicause

Describe the project you are working on

Godot

Describe the problem or limitation you are having in your project

Related:

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.

However, the drawable texture proposal doesn't address the support for mesh/vertex shader yet.

Current MeshTexture is just a wrapper for canvas_item_add_mesh() and doesn't store texture data itself, which means it can't be used in shader uniform or 3D scene. And it can't do regional drawing.

ViewportTexture is heavy and not convenient for just rendering a simple mesh. In addition, ViewportTexture can't render 3D mesh if compling engine with 3d disabled because Node3Ds is not available.

Moreover, this is also a way to perform GPGPU using the rasterization pipeline.

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

Implement mesh rasterizer api and RasterizedMeshTexture. This texture accepts a mesh and a ShaderMaterial to do custom drawing.

Main differences from DrawableTexture2D:

  • It supports vertex shader and vertex attributes (UV and vertex color)
  • It clears the texture before each drawing, instead of blit the texture mult-times
  • It only writes one color output to itself. DrawableTexture2D can write up to 4 color outputs simultaneously.

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

My proposal PR is here: godotengine/godot#106331

Current api desgin:

	enum RasterizedTextureFormat {
		RASTERIZED_TEXTURE_FORMAT_RGBA8,
		RASTERIZED_TEXTURE_FORMAT_RGBA8_SRGB,
		RASTERIZED_TEXTURE_FORMAT_RGBAH,
		RASTERIZED_TEXTURE_FORMAT_RGBAF
	};
	virtual RID mesh_rasterizer_create(int p_width, int p_height, RasterizedTextureFormat p_texture_format, bool p_generate_mipmaps = false) = 0;
	virtual void mesh_rasterizer_set_bg_color(RID p_mesh_rasterizer, const Color &p_bg_color) = 0;
	virtual void mesh_rasterizer_set_mesh(RID p_mesh_rasterizer, RID p_mesh, int p_surface_index) = 0;
	virtual void mesh_rasterizer_set_material(RID p_mesh_rasterizer, RID p_material) = 0;
	virtual void mesh_rasterizer_draw(RID p_mesh_rasterizer) = 0;
	virtual RID mesh_rasterizer_get_texture(RID p_mesh_rasterizer) = 0;
And the core shader:
#[vertex]
#version 450

#VERSION_DEFINES

layout(set = 0, binding = 0, std430) restrict readonly buffer GlobalShaderUniformData {
	vec4 data[];
}
global_shader_uniforms;

#include "samplers_inc.glsl"

layout(location = 0) in vec3 vertex_attrib;
layout(location = 1) in vec2 uv_attrib;
layout(location = 2) in vec4 color_attrib;

layout(location = 0) out vec2 uv_interp;
layout(location = 1) out vec4 color_interp;

#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(set = 1, binding = 0, std140) uniform MaterialUniforms {
#MATERIAL_UNIFORMS
}
material;
/* clang-format on */
#endif

#GLOBALS

void main() {
	// Flip y-axis and convert z-axis to [0,1].
	mat4 m = mat4(
			1.0, 0.0, 0.0, 0.0,
			0.0, -1.0, 0.0, 0.0,
			0.0, 0.0, 0.5, 0.0,
			0.0, 0.0, 0.5, 1.0);
	vec4 vertex = m * vec4(vertex_attrib, 1);
	vec2 uv = uv_attrib;
	vec4 color = color_attrib;

	{
#CODE : VERTEX
	}

	uv_interp = uv;
	color_interp = color;
	gl_Position = vertex;
}

#[fragment]
#version 450

#VERSION_DEFINES

layout(set = 0, binding = 0, std430) restrict readonly buffer GlobalShaderUniformData {
	vec4 data[];
}
global_shader_uniforms;

#include "samplers_inc.glsl"

layout(location = 0) in vec2 uv_interp;
layout(location = 1) in vec4 color_interp;

layout(location = 0) out vec4 frag_color;

#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(set = 1, binding = 0, std140) uniform MaterialUniforms {
#MATERIAL_UNIFORMS
}
material;
/* clang-format on */
#endif

#GLOBALS

void main() {
	vec2 uv = uv_interp;
	vec4 color = color_interp;

	{
#CODE : FRAGMENT
	}

	frag_color = color;
}

And a new resource RasterizedMeshTexture, which is a wrapper of RenderingServer api.

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

This can be worked around using RenderingDevice ( See also https://github.com/beicause/GodotMeshTextureRd ), but not convenient

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

It's core

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions