[SOLVED] Dynamic Text Render... how to?

Hi there, again!

I’ve been trying to implement something simmilar to this proyect: PlayCanvas 3D HTML5 Game Engine

The idea is to show, sequentially, different phrases in a plane. We’ve been using that project to create the texture and then apply it to the material, but we’re a bit lost: first, with the opacity channel (only red coloured text would appear), then we guessed we had to use two different texture: an opacity map with text in black and white and the text istelf, with the real color we wanted to use, and apply both in the material.

But… We are lost in the “canvas” :frowning:, any thoughts? any help?


EDIT:

This is the link to our project PlayCanvas | HTML5 Game Engine , the text would appear after some seconds.

Ok, I think I need to be more accurate…

I forked that project and tried some stuff, for example, changing font color… finally, I achieved it:

Dynamic text Render:

So I tried to “put some colors in our lifes” :smile: joy: changed font color and the opacity channel in the material where we draw our texture. Et voilà!

Some nice blue letters in the text render… so, everything seems to be Ok, I copy&paste this script to our project and then, enjoy the magic, but… after doing the same stufff I’ve done:

Color changes and text updates but… text quality is very low. I have changed resolution, yes sir, but if I keep the original values, same thing happens. (I think it’s not very visible in the gif. Check the project instead, I’ll leave it like this.
I that last GIF I show both projects with the text render, with same values. I’ve also checked cameras and both are simmilar. (No FXAA). Any thoughts?

Thank you so much for your patience :smile:

Interesting. I have just been taking a look at the original canvas text tutorial and I noticed it didn’t allow you to subsequently update the text if only one canvas is used. I have fixed that. I’m not sure what’s going on with your app though. It almost looks like the mipmap setting on the texture is being ignored but I checked in WebGL Inspector and the texture looks correct. I’ll have to investigate further.

1 Like

OK, I’ve rewritten your script:

pc.script.attribute('anchoTexto', 'number', 0.0, {
    displayName: "Ancho"
});
pc.script.attribute('altoTexto','number', 0.0, {
    displayName: "Alto"
});
pc.script.attribute('reglones','number', 0.0, {
    displayName: "Reglones"
});
pc.script.attribute('separador','number', 0.0, {
    displayName: "Separación entre reglones",
    min: 0,
    max:2
});
pc.script.attribute('colorTexto','string', 'no funciona todavía', {
    displayName: "Color"
});
pc.script.attribute('tamanoTexto','string', '70px', {
    displayName: "tamaño"
});
pc.script.attribute('fuente','enumeration', 'Verdana', {
    displayName: "Fuente",
    enumerations: [{
        name: "Verdana",
        value: 'Verdana'
    },
    {
        name: "Arial",
        value: 'Arial'
    },
    {
        name: "Times New Roman",
        value: 'Times New Roman'
    },
    {
        name: "Courier New",
        value: 'Courier New'
    },
    {
        name: "Serif",
        value: 'serif'
    },
    {
        name: "sans-serif",
        value: 'sans-serif'
    }]
});
pc.script.attribute('variante','enumeration', 'normal', {
    displayName: "Variante",
    enumerations: [{
        name: "Normal",
        value: 'normal'
    },
    {
        name: "Small-caps",
        value: 'small-caps'
    }]
});
pc.script.attribute('estilo','enumeration', 'normal', {
    displayName: "Estilo",
    enumerations: [{
        name: "Normal",
        value: 'normal'
    },
    {
        name: "Italic",
        value: 'italic'
    },
    {
        name: "Oblicua",
        value: 'oblique'
    }]
});
pc.script.attribute('peso','enumeration', 'normal', {
    displayName: "Peso",
    enumerations: [{
        name: "Normal",
        value: 'normal'
    },
    {
        name: "Bold",
        value: 'bold'
    },
    {
        name: "Bolder",
        value: 'bolder'
    },
    {
        name: "Lighter",
        value: 'lighter'
    },
    {
        name: "100",
        value: '100'
    },
    {
        name: "200",
        value: '200'
    },
    {
        name: "300",
        value: '300'
    },
    {
        name: "400",
        value: '400'
    },
    {
        name: "500",
        value: '500'
    },
    {
        name: "600",
        value: '600'
    },
    {
        name: "700",
        value: '700'
    },
    {
        name: "800",
        value: '800'
    },
    {
        name: "900",
        value: '900'
    }]
});


pc.script.create('texto_bocadillo', function (app) {
    // Creates a new Text instance
    var texto_bocadillo = function (entity) {
        this.entity = entity;
    };

    texto_bocadillo.prototype = {
        // Called once after all resources are loaded and before the first update
        initialize: function () {
            this.tiempo=0;
            
            this.canvas = document.createElement('canvas');
            this.canvas.height = this.altoTexto;
            this.canvas.width = this.anchoTexto;
            this.context = this.canvas.getContext("2d");
            
            this.texture = new pc.Texture(app.graphicsDevice, {
                format: pc.PIXELFORMAT_R8_G8_B8,
                autoMipmap: true
            });
            
            this.texture.setSource(this.canvas);
            this.texture.minFilter = pc.FILTER_LINEAR;
            this.texture.magFilter = pc.FILTER_LINEAR;
            this.texture.addressU = pc.ADDRESS_REPEAT;
            this.texture.addressV = pc.ADDRESS_REPEAT;
            
            this.updateText();

            var material = this.entity.model.material;
            material.emissive.set(0, 0, 1);
            material.emissiveMap = this.texture;
            material.emissiveMapTint = true;
            material.opacityMap = this.texture;
            material.blendType = pc.BLEND_NORMAL;
            material.opacity = 1;
            material.alphaTest = 0;
            material.noFog = true;
            material.update();
        },

        updateText: function () {
            var ctx = this.context;
            var w = ctx.canvas.width;
            var h = ctx.canvas.height;
            
            // Clear the context to transparent
            ctx.fillStyle = 'black';
            ctx.fillRect(0, 0, w, h);
    
            // Write white text
            ctx.textBaseline = 'middle';
            ctx.font = this.peso + ' ' + this.tamanoTexto + ' Verdana';
            ctx.textAlign = 'center';
            ctx.fillStyle = 'white';
            ctx.fillText(this.texto, w / 2, h / 2);

            // Copy the canvas into the texture
            // 
            this.texture.upload();            
        },

        // Called every frame, dt is time in seconds since last update
        update: function (dt) {
            
            this.tiempo = this.tiempo + dt;
            console.log(this.tiempo);
            if(this.tiempo>4)
                {
                    this.texto='Lolailo';
                    this.updateText();                    
                    
                }
            
            if(this.tiempo>6)
                {
                    this.texto='Prueba2';
                    this.updateText();
                    this.tiempo=0;
                                        
                }
        }
    };

    return texto_bocadillo;
});

I think the problem was your alpha test value. You should set this to 0 to avoid any partially transparent pixels around the text from being discarded in the shader. However, I’ve made a bunch of other improvements. The script uses emissiveMapTint to allow you to color the text whatever color you like. I have also updated the code to only ever create one canvas.

1 Like

This is just perfect @will, thank you so much. I’m going to check your code to understand what I was doing wrong.

Your help is priceless for us, guys. Thank you.