Can't clear DynamicTexture to transparent in BabylonReactNative

Hi!

I’m working with text on a plane and am using DynamicTexture and drawText to do so. I can’t seem to clear the texture back to transparent when drawing a new Text. I put more explanation in this question here: How to clear a DynamicTexture
But the gist of it is that I can’t seem to set the canvas.fillStyle to anything with transparency in BabylonReactNative. It throws this error: Error: Exception in HostFunction: Unknown color name

These are the versions I’m on:
@babylonjs/core”: “5.0.0-alpha.65”,
@babylonjs/gui”: “5.0.0-alpha.65”,
@babylonjs/loaders”: “5.0.0-alpha.65”,
@babylonjs/react-native”: “0.4.0-alpha.47”,

Is there another way of clearing a DynamicTexture that I’m missing? Thanks!

cc @Cedric and @bghgary

I know what can cause this issue.
Can you please try with other color names like red or `#00000’ ?

Hi! I’ve tried with red, or #000 and that does give a solid color. But anything I try that has transparency in it gives this error.

It’s already on my radar. I opened an issue some time ago. I’ll try to fix it soon.

2 Likes

Great! Is there any way to circumvent this in the meantime? :smiley:

you can set the color to transparent which is equivalent to (0,0,0,0). An empty string should behave the same.

Oh, I’ve actually tried “transparent”. I just checked now and it doesn’t seem to clear when I do:
canvas.fillStyle = ""; texture.clear();
The old text will still be on the texture.

Might be another issue in addition to the color. I’m checking.

2 Likes

PR for improvement color parsing [Canvas] Color parsing improvements by CedricGuillemet · Pull Request #1051 · BabylonJS/BabylonNative · GitHub
In the mean time, I checked clearing the texture and this code works:

texture.getContext().fillStyle = '#000000';
texture.clear();

Hi!

I tried your code, but that clears it to black for me. Could it be that I need a newer version? I have this right now:

    "@babylonjs/core": "5.0.0-alpha.65",
    "@babylonjs/gui": "5.0.0-alpha.65",
    "@babylonjs/loaders": "5.0.0-alpha.65",
    "@babylonjs/react-native": "0.4.0-alpha.47",

Do you have a playground that does the clear the way you want and doesn’t work with native?

Sure! Here it is

This one displays the behaviour I would like to replicate in my app. Although trying #000000 there also gave me black instead of transparent.

Texture.clear renders a quad with the color of fillStyle.
A color value #000000 is equivalent of #000000FF
and clearing with that color will give a full opaque black
As alpha is used when rendering the clearing quad, it’s not possible to set it as the destination value.
To do so, it’s madatory to use a ‘copy’ compositing value

That’s currently not supported by BabylonNative

In your PG, the color for the texture, is transparent, clearing it with a transparent color and a ‘source-over’ compositing will leave it unchanged.

Check in this PG line 66:

But, by default, each texture pixel is set to (0,0,0,0), so it’s possible to create transparent texture with BabylonNative:

The code to get that is :

var ground = BABYLON.MeshBuilder.CreateGround("ground1", { width: 0.5, height: 0.5, subdivisions: 2 }, scene);
        ground.rotation.x = -Math.PI * 0.5;
        ground.rotation.y = Math.PI;
        ground.position.z = -0.25;
        ground.position.x = 0.25;
    
        //Create dynamic texture
        var textureResolution = 512;
        textureGround = new BABYLON.DynamicTexture("dynamic texture", textureResolution, scene);
    
        var materialGround = new BABYLON.StandardMaterial("Mat", scene);
        textureGround.hasAlpha = true;
        materialGround.diffuseTexture = textureGround;
        ground.material = materialGround;
        materialGround.backFaceCulling = false;

        textureGround.drawText("BabylonNative", 0, 246, font, "White", null, true, true);

So, until compositing modes are supported in BN, I suggest to dispose and create a new texture.

1 Like

I see, I guess I thought since I can make a transparent texture when I start I can have a transparent texture when I update.
So looking at the playground I guess that the fillStyle will overlay the cube to ‘clear’ it. So if I make this transparent nothing will actually happen.

I’ve tried disposing and recreating, but it gets a little flickery if I want fast updates. Maybe if I limit the updates, not make them every frame…
Another user here also suggested this as a possible solution: How to clear a DynamicTexture - #10 by mise

So I do have other options. Thanks again for taking the time to explain all this, I really appreciate it :smiley:

Hi!

Sorry to keep coming back to this, but I’ve tried disposing the texture and then remaking it. But it seems like there’s some resources that aren’t getting released when doing texture.dispose()

Here’s the android profiler

The way I’m creating and disposing these textures is as follows, in case I’m doing something wrong there. I have a useEffect that listens to my inputs and once one of those is changed I do this (this is all just for trying out how to tackle this):

const font = `bold ${Number(props.FontSize)}px monospace`;
var canvas = texture.getContext();
canvas.font = font;
var textWidth = canvas.measureText(props.InputText).width;
var textHeight: number = Number(props.FontSize);
const textureWidth = 1024 * mesh?.scaling.x;
const textureHeight = 1024 * mesh?.scaling.y;

texture.dispose();
texture.onDisposeObservable.add(() => {
    const localTexture = new DynamicTexture(
        "NewTexture",
        { width: textureWidth, height: textureHeight },
        scene
    );
    localTexture.hasAlpha = true;
    let textureX = textureWidth / 10;
    let textureY = textureHeight / 10;
    switch (props.TextAlign) {
        case "center":
            textureX = textureWidth / 2 - textWidth / 2;
            break;
        case "left":
            break;
        case "right":
            textureX = textureWidth - (textWidth + textureWidth / 10);
            break;
        default:
            break;
    }
    switch (props.TextAlignVertical) {
        case "center":
            textureY = textureHeight / 2 - textHeight / 2;
            break;
        case "top":
            textureY = textHeight + textureHeight / 10;
            break;
        case "bottom":
            textureY = textureHeight - (textHeight + textureHeight / 10);
            break;
        default:
            break;
    }
    localTexture.drawText(
        props.InputText ?? "",
        textureX,
        textureY,
        font,
        props.Color,
        null!,
        true,
        true
    );

    (mesh.material as StandardMaterial).diffuseTexture = localTexture;
    setTexture(localTexture);
    setCounter(0);
});

Let me check

1 Like

@Peter

How often is the texture disposed? Do you get the same behavior with a web browser with increasing memory footprint?

This is me stress testing this function. So a lot, I’ve tried throttling it, but that causes the same behaviour, it just takes longer to get there.
I can try that in the browser tomorrow and let you know the result :smiley:

2 Likes

I haven’t looked in detail, but you have to be really careful with event handlers (like onDispose)