[SOLVED] How to render to Text on 3d Model by keeping model texture?

Hello :wave:,

I found project Render to Texture.
https://playcanvas.com/project/560797/overview/tutorial-render-to-texture

I wanted to render text on 3d model…
But when i try to work with Text it does not work…

How to render to Text on 3d Model by keeping model’s original texture?

Any help will be thankful! :pray:

maybe this way?

you could also use detail maps, which are not exposed in the editor, but can be set up using the scripts

1 Like

Thank you @mvaligursky for quick reply

I checked PlayCanvas 3D HTML5 Game Engine project which looks great… But

Sorry, I forgot to mention more things about it…

  • So actually i am planning to add animated 3D Cricket player model and i want text to be printed on his jersey at back side…
  • And this text can be changed anytime… (Text could be anything from name, number, rank, score )

So i am looking for way to implement text dynamically which can be printed on cloths…

Anyway

Here is my project https://playcanvas.com/editor/scene/1318008
What i tried so far and what is result…

So this is the texture which is right there for head

And according to project i want that text to appear on face… (Earlier it was appearing right in the middle center of the texture which i dont want. It should appear at specific area of texture.)

But my expectation is according to following image… (following image is edited in photoshop for showing example)

So i modified CSS part from textBoostrap.js and moved text toward face position according to texture position.


// initialize code called once per entity
TextBoostrap.prototype.initialize = function() {
        // text Wrapper
        var wrapperDiv = document.createElement('div');
        wrapperDiv.id = 'engravingText';
        wrapperDiv.style.fontFamily = 'Verdana';
        wrapperDiv.style.fontSize = '60px';
        wrapperDiv.style.background = 'White';
        wrapperDiv.style.color = 'Black';
        // wrapperDiv.style.display = 'table';
        wrapperDiv.style.zIndex = '-10';
        wrapperDiv.style.position = 'absolute';
        // wrapperDiv.style.textAlign = 'center';
        wrapperDiv.style.letterSpacing = '5px';
        wrapperDiv.style.width = '1024px';
        wrapperDiv.style.height = '1024px';
        document.body.appendChild(wrapperDiv);

        // text
        var textDiv = document.createElement('div');
        textDiv.id = 'engravedText';
        // textDiv.style.display = 'table-cell';
        // textDiv.style.verticalAlign = 'middle';
        textDiv.style.position = 'absolute';
        textDiv.style.top = '800px';
        textDiv.style.left = '300px';
        textDiv.innerHTML = 'BOT';
        wrapperDiv.appendChild(textDiv);
        
        this.app = pc.Application.getApplication();
        // this.entity = this.app.root.findByName("3D_Model");
        // this.entity = this.modelEntity;
        this.engravingMaterial = this.modelEntity.model.meshInstances[0].material;
        console.log(this.engravingMaterial);
    
        if (!TextBoostrap.copyShader) {
            TextBoostrap.createShaders(this.app);
        }
    
        this.quad = this.createQuad();
    
        this.createTexture3D(this.app, this.engravingMaterial);
      
};

Now when i launch the project, the CSS code seems somewhat is correct.


But i cant see the text appearing. (You can see head color getting bit more gray but you cant see the text.)

I am not sure what i am doing wrong here… :thinking:

I’m wondering if it would be easier to use the detail map instead, similar to how this developer has added a logo to the knife: Product Configurator for Knife Maker Deglon

1 Like

Hi :wave: @yaustar
Thanks for reply!

I come to know that above project using following two files.

  • canvas2image.js
  • html2canvas.min.js

Also i come to know that one of above js is used to generate following image through base64…
image

And i am guessing :thinking:, He converted text code into canvas and then turn into image (base64). Later on this image(base64) some how used to apply on knife…

Correct me if i am wrong…

@TonyLGC Would you be able to expand on the process here please?

Hi, sorry, didn’t see the notifications ! I hope this is not too late :slight_smile:

The canvas+base64 is just some hacking to be honest haha.
I use this to turn the text in my WYSIWYG editor, located outside of my PlayCanvas canvas, into an image and then a base64 string. This way I can send this data to the canvas through the onmessage event.
I have to do this to pass the cross-origin protection.

Inside my PC canvas, I have an IMG tag. I set my base64 string in this IMG source attribute, and then I use it’s load event.
form.querySelector("img").src = data.b64;

img.addEventListener("load", function (event) {
    // 1- I first make an HTML canvas, and draw my image inside it
    // 2- I edit all the pixels to make it grayscale and transparent (white pixel -> alpha = 0)
    // 3- I turn this canvas in a base64 again! (with canvas.toDataUrl() )
    //     This string is stored for the next step below

});

Now that I’ve written this, it might seem a bit crazy haha, but hey… it works for me ¯\(ツ)

But all this is irrelevant to your question. The part that could interest you is what happens next :slight_smile:
This is a heavily edited part of my code to extract the basic process

Ui.prototype.updateBladeTextureWithUserFile = function () {
    //My image comes from the outside of my  PC project, you wont need this loading part if it is already in your editor
    var file = {
        url: //my edited base64 image, can also be the path to your image
        filename: 'something.png'
    };
    var asset = new pc.Asset('my image', "texture", file, null, null);
    pc.app.assets.add(asset);
    asset.resource.addressU = pc.ADDRESS_CLAMP_TO_EDGE;
    asset.resource.addressV = pc.ADDRESS_CLAMP_TO_EDGE;
    //The texture is ready to be used. Make sure it is correctly loaded. (not included in this example)

    var lame = app.root.findByName("Lame"); //This is my model. Lame = blade in french, it is not "uninspiring" :)     
    var lameMesh = lame.model.meshInstances[0];
    var mat = lameMesh.material;
    mat.diffuseDetailMap = asset.resource;
    mat.diffuseDetailMapChannel = "r";
    mat.diffuseDetailMode = pc.DETAILMODE_ADD; //I didn't use this but it is often useful. I use the default MUL value
    mat.update();        
};

I hope this can help…
The hardest part is putting the text texture at the right place and finding the right blend mode.
You can use a second UV map including only a part of your robot’s head, and use diffuseDetailMapUv = 1.
Or you can use the same UV map as your main texture, and place your diffuseDetailMap texture by changing the tiling/offset.rotation : diffuseDetailMapTiling.set(x,y)

2 Likes

Did a quick test :slight_smile:

https://playcanvas.com/project/876569/

Look in the script “addTextToHead”

Now if you want to change this text, you’ll have to find a way of generating a texture with the new text :slight_smile: (html canvas works fine :ok_hand:)

3 Likes

Thank you very much @TonyLGC!

1 Like

Hello :wave:,

Thank you very much @TonyLGC for very well explanation! :pray:
Thank you very much @yaustar for calling @TonyLGC here… :pray:

After some experiments, I am successfully able to accept users input in and turn in to texture. :slightly_smiling_face: :slightly_smiling_face:

Long story in short:

  • Accept input text from user
  • Create canvas of size of texture (You need to know coord where text will appear)
  • In canvas Fill up background white with 0.01 opacity
  • Then add text in canvas
  • Create base64 of canvas
  • Import and load base64 as texture image
  • Apply this new texture on model.

Here is the project link…
https://playcanvas.com/project/876679/overview/write-text-on-model-fork

Thank you very much again! :slightly_smiling_face:

1 Like