godot-proposals
godot-proposals copied to clipboard
RandomTexture2D and RandomTexture3D
Describe the project you are working on
I am trying to write a voxel game with procedural generation However I wanted to support block texture variants in my game.
Describe the problem or limitation you are having in your project
There is no way to randomize a texture in 2d and 3d
Describe the feature / enhancement and how it helps to overcome the problem or limitation
Implement RandomTexture2D and RandomTexture3D
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
I tried to build it in C# but ran into issues when trying to compile the resource.
Here is an example of how I tried to implement it.
[Tool]
[GlobalClass]
public partial class RandomTexture : Texture2D
{
[Export] public Array<Texture2D> Textures
{
get => _textures;
set
{
if (_textures == value) return;
var randomize = _textures != null;
_textures = value;
if (randomize) Randomize();
EmitChanged();
}
}
public RandomTexture()
{
if (_empty == null)
{
var image = Image.CreateEmpty(1, 1, false, Image.Format.Rgb8);
_empty = ImageTexture.CreateFromImage(image);
}
Randomize();
}
private static ImageTexture _empty;
private Texture2D _texture = null;
private Array<Texture2D> _textures = new();
private void Randomize()
{
if (_textures == null || _textures.Count == 0) return;
_texture = Textures[GD.RandRange(0, Textures.Count)];
}
public override int _GetWidth()
{
if (_texture == null) return _empty._GetWidth();
return _texture._GetWidth();
}
public override int _GetHeight()
{
if (_texture == null) return _empty._GetHeight();
return _texture._GetHeight();
}
public override bool _HasAlpha()
{
if (_texture == null) return _empty._HasAlpha();
return _texture._HasAlpha();
}
public override bool _IsPixelOpaque(int x, int y)
{
if (_texture == null) return _empty._IsPixelOpaque(x, y);
return _texture._IsPixelOpaque(x, y);
}
public override void _Draw(Rid toCanvasItem, Vector2 pos, Color modulate, bool transpose)
{
if (_texture == null)
{
_empty.Draw(toCanvasItem, pos, modulate, transpose);
return;
};
_texture._Draw(toCanvasItem, pos, modulate, transpose);
}
public override void _DrawRect(Rid toCanvasItem, Rect2 rect, bool tile, Color modulate, bool transpose)
{
if (_texture == null)
{
_empty._DrawRect(toCanvasItem, rect, tile, modulate, transpose);
return;
}
_texture._DrawRect(toCanvasItem, rect, tile, modulate, transpose);
}
public override void _DrawRectRegion(Rid toCanvasItem, Rect2 rect, Rect2 srcRect, Color modulate, bool transpose, bool clipUv)
{
if (_texture == null)
{
_empty._DrawRectRegion(toCanvasItem, rect, srcRect, modulate, transpose, clipUv);
return;
}
_texture._DrawRectRegion(toCanvasItem, rect, srcRect, modulate, transpose, clipUv);
}
}
If this enhancement will not be used often, can it be worked around with a few lines of script?
This may not be possible in a way that encapsulates the random chosen texture If Texture2D can't be extended then it forces script end users to use something like ImageTexture which ultimately exposes a way to mutate the random chosen image.
Also users might want to ensure textures are the same size, which I have no idea on how to enforce.
Is there a reason why this should be core and not an add-on in the asset library?
Its useful for texture variants
I don't think this makes much sense as a texture resource, since resources are made to be shared and cached, so your random choice would be global by default.
This is usually done by having a texture atlas (see AtlasTexture), or randomly offsetting the UV coordinates.
Regardless of the above reasoning, I don't see a reason to have this in core, given the specific niche it fulfills. Sounds like a cool addon, though.