html5-canvas - webgl 中的文本到纹理

标签 html5-canvas transparency webgl textures

我有一个绘制球体的 webGL 代码,我在旁边添加文本标签。 我正在做的是创建 2D 矩形,然后为我的文本应用纹理。

function createCubeTexture(text) {

var canvas = document.createElement('canvas');
canvas.id     = "hiddenCanvas";
canvas.width  = 512;
canvas.height = 128;
canvas.style.display   = "none";
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);        

var cubeImage = document.getElementById('hiddenCanvas');
var ctx = cubeImage.getContext('2d');
ctx.beginPath();
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);            
ctx.fillStyle = 'rgba(255,255,255,0)';
ctx.fill();
ctx.fillStyle = 'black';
ctx.font = "65px Arial";
ctx.textAlign = 'center';            
ctx.fillText(text, ctx.canvas.width / 2, ctx.canvas.height / 2);
ctx.restore();        

var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
handleTextureLoaded(cubeImage, texture) 

return texture;
}

但我正在寻找的是完全透明的纹理。我想要没有 bgcolor 的文本。 我可以使用 alpha 并获得“类似透明”的颜色,但我的矩形永远不会透明(如果 alpha=0 则它是白色),我从来没有设法通过矩形看到球体。

任何想法

谢谢

最佳答案

为了使用 alpha = 0 进行绘制,您需要在 canvas 2d 中使用不同的 globalCompositeOperation。在 rgba(255,255,255,0) 上面的代码中,source-over 的默认 globalCompositingOperation 基本上是这样做的

dest = dest * (1 - alpha) + source * alpha

由于 alpha 为 0,这意味着它不绘制任何内容,因此您的第一个 fill 调用不绘制任何内容。

而是将 alpha 设置为 1,但使用 'ctx.globalCompositeOperation = "destination-out" 进行填充,然后将文本设置回 source-over`。

看这个问题 How do you draw with alpha = 0 in an html5 canvas to 'erase' .

虽然实际上,在您的情况下,只需删除填充即可。 Canvas 元素开始时完全透明。要将 Canvas 清除回透明调用 ctx.clearRect

这是从另一个示例中复制的片段:

var gl;

function initGL(canvas) {
    try {
        gl = canvas.getContext("webgl");
        gl.viewportWidth = canvas.width;
        gl.viewportHeight = canvas.height;
    } catch (e) {
    }
    if (!gl) {
        alert("Could not initialise WebGL, sorry :-(");
    }
}


function getShader(gl, id) {
    var shaderScript = document.getElementById(id);
    if (!shaderScript) {
        return null;
    }

    str = shaderScript.text;

    var shader;
    if (shaderScript.type == "x-shader/x-fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (shaderScript.type == "x-shader/x-vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
        return null;
    }

    gl.shaderSource(shader, str);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}


var shaderProgram;

function initShaders() {
    var fragmentShader = getShader(gl, "shader-fs");
    var vertexShader = getShader(gl, "shader-vs");

    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert("Could not initialise shaders");
    }

    gl.useProgram(shaderProgram);

    // This is a bad code.
    // If the context is lsot shaderProgram will be null
    // and trying to assign a vertexPositionAttribute to null
    // will throw an exception.
    // better would be 
    // shaderProgram = {};
    // shaderProgram.program = gl.createProgram();
    // shaderProgram.vertexPositionAtrribute = ...
    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);

    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}


var texturen = new Array();
function initTexture(text,texturen)  
{
  var anz = texturen.length;
  texturen[anz] = gl.createTexture();
  // this is a bad code. on context lost gl.createTexture() will return null and
  // an exception will be thrown when you try to attach .image to null
  // Better would be
  // texturen[anz] = {};
  // texturen[anz].texture = gl.createTexture();
  // texturen[anz].image = new Image();
  var c = document.createElement("canvas");
  c.width = 256;
  c.height = 256;
  var ctx = c.getContext("2d"); 
  //ctx.fillStyle = "rgba(0, 0, 0, 1)";
  //ctx.globalCompositeOperation = "destination-out";
  //ctx.fillRect(0, 0, 64, 64);
  //ctx.globalCompositeOperation = "source-over";
  ctx.fillStyle = "rgb(255, 128, 64)";
  ctx.font = "40px Arial";
  ctx.fillText(text, 128 - 64, 128);
  gl.bindTexture(gl.TEXTURE_2D, texturen[anz]);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
} 

var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();

function mvPushMatrix() {
    var copy = mat4.create();
    mat4.set(mvMatrix, copy);
    mvMatrixStack.push(copy);
}

function mvPopMatrix() {
    if (mvMatrixStack.length == 0) {
        throw "Invalid popMatrix!";
    }
    mvMatrix = mvMatrixStack.pop();
}


function setMatrixUniforms() {
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}

function degToRad(degrees) {
    return degrees * Math.PI / 180;
}

function initBuffers() {
    vertBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
    var vertices = [
        // Front face
        -1.0, -1.0,  1.0,
         1.0, -1.0,  1.0,
         1.0,  1.0,  1.0,
        -1.0,  1.0,  1.0,

        // Back face
        -1.0, -1.0, -1.0,
        -1.0,  1.0, -1.0,
         1.0,  1.0, -1.0,
         1.0, -1.0, -1.0,

        // Top face
        -1.0,  1.0, -1.0,
        -1.0,  1.0,  1.0,
         1.0,  1.0,  1.0,
         1.0,  1.0, -1.0,

       // Bottom face
        -1.0, -1.0, -1.0,
         1.0, -1.0, -1.0,
         1.0, -1.0,  1.0,
        -1.0, -1.0,  1.0,

        // Right face
         1.0, -1.0, -1.0,
         1.0,  1.0, -1.0,
         1.0,  1.0,  1.0,
         1.0, -1.0,  1.0,

        // Left face
        -1.0, -1.0, -1.0,
        -1.0, -1.0,  1.0,
        -1.0,  1.0,  1.0,
        -1.0,  1.0, -1.0,
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    
    // This is bad code. See the above examples of bad code.
    // vertBuffer will be null on context lost and this code
    // will throw an exception.
    vertBuffer.itemSize = 3;
    vertBuffer.numItems = 24;

    CoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER,CoordBuffer);
    var textureCoords = [
      // Front face
      1.0, 0.0,
      0.0, 0.0,
      0.0, 1.0,
      1.0, 1.0,

      // Back face
      0.0, 0.0,
      0.0, 1.0,
      1.0, 1.0,
      1.0, 0.0,

      // Top face
      1.0, 1.0,
      1.0, 0.0,
      0.0, 0.0,
      0.0, 1.0,

   // Bottom face
      0.0, 1.0,
      1.0, 1.0,
      1.0, 0.0,
      0.0, 0.0,

      // Right face
      0.0, 0.0,
      0.0, 1.0,
      1.0, 1.0,
      1.0, 0.0,

      // Left face
      1.0, 0.0,
      0.0, 0.0,
      0.0, 1.0,
      1.0, 1.0,
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
    CoordBuffer.itemSize = 2;
    CoordBuffer.numItems = 24;

    IndexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
    var Indices = [
        0, 1, 2,      0, 2, 3,    // Front face
        4, 5, 6,      4, 6, 7,    // Back face
        8, 9, 10,     8, 10, 11,  // Top face
        12, 13, 14,   12, 14, 15, // Bottom face
        16, 17, 18,   16, 18, 19, // Right face
        20, 21, 22,   20, 22, 23  // Left face
    ];
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(Indices), gl.STATIC_DRAW);
    IndexBuffer.itemSize = 1;
    IndexBuffer.numItems = 36;
}


var xRot = 0;
var yRot = 0;
var zRot = 0;

function drawScene() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);

    mat4.identity(mvMatrix);

    mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -5.0]);

    mat4.rotate(mvMatrix, mvMatrix, degToRad(xRot), [1, 0, 0]);
    mat4.rotate(mvMatrix, mvMatrix, degToRad(yRot), [0, 1, 0]);
    mat4.rotate(mvMatrix, mvMatrix, degToRad(zRot), [0, 0, 0]);
    setMatrixUniforms();


    gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,vertBuffer.itemSize, 
       gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ARRAY_BUFFER, CoordBuffer);
    gl.vertexAttribPointer(shaderProgram.textureCoordAttribute,CoordBuffer.itemSize, 
       gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, IndexBuffer);

// Draw face 0
gl.bindTexture(gl.TEXTURE_2D, texturen[0]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);

// Draw face 1
gl.bindTexture(gl.TEXTURE_2D, texturen[1]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 12);

// Draw face 2
gl.bindTexture(gl.TEXTURE_2D, texturen[2]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 24);

// Draw face 3
gl.bindTexture(gl.TEXTURE_2D, texturen[3]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 36);

// Draw face 4
gl.bindTexture(gl.TEXTURE_2D, texturen[4]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 48);

// Draw face 5
gl.bindTexture(gl.TEXTURE_2D, texturen[5]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 60);
}


var lastTime = 0;

function animate() {
    var timeNow = new Date().getTime();
    if (lastTime != 0) {
        var elapsed = timeNow - lastTime;

        xRot += (90 * elapsed) / 1000.0;
        yRot += (90 * elapsed) / 1000.0;
        zRot += (90 * elapsed) / 1000.0;
    }
    lastTime = timeNow;
}


function tick() {
    requestAnimationFrame(tick);
    drawScene();
    animate();
}


function webGLStart() {
    var canvas = document.getElementById("lesson05-canvas");
    initGL(canvas);
    initShaders();
    initBuffers();
    initTexture("face 0",texturen);
    initTexture("face 1",texturen);
    initTexture("face 2",texturen);
    initTexture("face 3",texturen);
    initTexture("face 4",texturen);
    initTexture("face 5",texturen);

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    tick();
}


webGLStart();
    
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;

varying vec2 vTextureCoord;

uniform sampler2D uSampler;

void main(void) {
    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
</script>

<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

varying vec2 vTextureCoord;


void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vTextureCoord = aTextureCoord;
}
</script>

<canvas id="lesson05-canvas" style="border: none;" width="500" height="500">    </canvas>    

关于html5-canvas - webgl 中的文本到纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15367909/

相关文章:

javascript - HTML5 Javascript 画笔

javascript - Three.js作为网站背景可以吗?

javascript - 是什么导致我的绘制数组调用无效操作?

c++ - SDL:全屏半透明背景

android - 为什么我的 Android Listview 在我点击它时会从透明变为不透明?

python - 在 PyGame 中混合 per-alpha 和颜色键的解决方法

javascript - 在运行时更改 three.js 中加载的 .obj 的纹理

javascript - 在新窗口中打开时,图像未在 Canvas 中绘制

javascript - 为什么canvas和webgl渲染器不一样? (三.js)

javascript - 在 JS 执行之前应用 CSS 字体