将多个画布添加到画布纹理

时间:2017-05-18 10:09:08

标签: three.js

这个问题与[一] [1]有些相关。我想要实现的是允许用户将多个文本图层和图像图层添加到单个网格中的方法。

我正在创建每个文本/图像作为使用自己的画布构建的自己的图层,如下所示:

getTextCanvas(textLayer) {
    var textPositions, textXPos, textYPos, styleToAdd = '';
    if(textLayer.bold) {
      styleToAdd += ' bold ';
    }
    if(textLayer.italic) {
      styleToAdd += ' italic '
    }
    var textCanvas = this.getCanvasTextureObject(textLayer.guid, 512, 512);
    textCanvas.canvas.style.backgroundColor = 'red';

    var ctx = textCanvas.ctx;
    ctx.font = styleToAdd + " 12px arial";

    var txtWidth = ctx.measureText(textLayer.text).width;   
    textXPos = (textCanvas.canvas.width / 2) - (txtWidth / 2);
    textYPos = textCanvas.canvas.height / 2;
    ctx.fillText(textLayer.text, textXPos, textYPos);

    return textCanvas.canvas;
}

getCanvasTextureObject()看起来像这样:

getCanvasTextureObject(id, width?, height?) {
    var canvasEle = document.createElement('canvas');
    canvasEle.id = id;
    // When painted on the bag this style isn't honoured
    canvasEle['style'].backgroundColor = 'red';
    var ctx = canvasEle.getContext('2d');
    var texture = new THREE.CanvasTexture(canvasEle);

    return { 
      canvas: canvasEle,
      ctx: ctx,
      texture: texture
    }
}

最后我将它全部添加到网格中,从画布纹理映射到Mesh Phong材质(我认为这是错误的材料,但也许是Shader?):

updateBag() {

        if(!this.mainCanvas) {
          this.mainCanvas = this.getCanvasTextureObject('main-canvas', 1024, 1024);
        }
        _.forEach(this.layers, (l) => { 
            this.mainCanvas.ctx.drawImage(l.canvas, 0, 0); 
        });

        var canvasTexture = new THREE.CanvasTexture(this.mainCanvas.canvas);
        var material = new THREE.MeshPhongMaterial({color: 0x00ff00, map: canvasTexture, transparent: true, overdraw: false, opacity: 1, depthTest: false });
        this.selectedProduct[0]['children'][0].material.materials[1] = material;

    }

我遇到的几个问题是:

  • 在主画布上未添加个别图层中添加的样式集(例如背景色)。也没有在主画布上设置样式。
  • 我需要能够在添加图层后更改图层的顺序。我已尝试在每个画布上设置 globalCompositeOperation 属性,但这似乎不起作用,并在主画布上尝试过相同的操作。

那我在这里做错了什么?

由于

1 个答案:

答案 0 :(得分:0)

Thanks to @TheJim01 for putting me on the right path. The key, as described above was to ensure that each side is unique and added to one texture.

For me I wanted the option of adding either text or an image to any side of my object and not have them overwrite each other. First - each side of the object is an array. In that array we can have many objects, each one represents either a text or an image layer:

layers = {
        front: [],
        back: [],
        left: [],
        right: [],
        base: [],
        top: []
    };

Then when any of these arrays are modified I would redraw that side of the object by creating a canvas, assigning that canvas to a Texture and ensuring that each drawn image is the same size (if not then the text or the image will appear pixelated):

    updateBag() {
        if(this.selectedProduct) {
            var mainCanvas, canvasTexture;
            var sidesModified = this.getSidesModified();
            var side, sides = _.keys(sidesModified);

            for(var i = 0; i < sides.length; i++) {
                side = sides[i];
                mainCanvas = this.getCanvas('main-canvas', 'main');
                canvasTexture = new THREE.Texture(mainCanvas.canvas);

                for(var j = 0; j < this.layers[side].length; j++) { 
                    if(side === 'front' || side === 'back'){
                        canvasTexture.wrapS = THREE.RepeatWrapping;
                      canvasTexture.repeat.x = -1;
                    }
                    mainCanvas.ctx.drawImage( this.layers[side][j].canvas, 0, 0, this.canvasWidth, this.canvasHeight);
                }
                var material = new THREE.MeshBasicMaterial({map: canvasTexture, side: THREE.FrontSide, transparent: false});
                this.setMaterialToBag(material, side);
                canvasTexture.needsUpdate = true;
            }
        }
    }