可以在运行时绘制一个字符串(" Hello World")作为纹理?

时间:2014-07-02 07:35:00

标签: textures webgl

我理解如何将纹理贴图应用于多边形。

但是,是否可以在运行时创建字符串的纹理(如每秒显示的当前帧数)并将其映射到多边形?

更新

这可能会奏效。我必须为自己测试一下。 Drawing text as textures on squares does not show anything

2 个答案:

答案 0 :(得分:2)

使用2D画布API

可以轻松地在运行时创建纹理
var gl = someCavnasInThePage.getContext("webgl");

// create an offscreen canvas with a 2D canvas context
var ctx = document.createElement("canvas").getContext("2d");

// make it a desired size 
ctx.canvas.width = 128;
ctx.canvas.height = 64;

// fill it a certain color
ctx.fillStyle = "rgb(255,0,0)";  // red
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

// draw some text into it.
ctx.fillStyle = "rgb(255,255,0)";  // yellow
ctx.font = "20px sans-serif";
ctx.fillText("Hello World", 5, 40);

// Now make a texture from it
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, ctx.canvas);

// generate mipmaps or set filtering 
gl.generateMipmap(gl.TEXTURE_2D);

这是一个有效的例子



var m4 = twgl.m4;
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);

var arrays = {
  position: [1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1],
  normal:   [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1],
  texcoord: [1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1],
  indices:  [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);


var tex = createTextTexture(gl, "Hello World", 256, 128);
gl.bindTexture(gl.TEXTURE_2D, tex);

function render(time) {
  time *= 0.001;
  
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);

  var fieldOfView = Math.PI * 0.25;
  var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  var projection = m4.perspective(fieldOfView, aspect, 0.0001, 500);
  var radius = 5;
  var eye = [
    Math.sin(time) * radius,
    2,
    Math.cos(time) * radius];
  var target = [0, 0, 0];
  var up = [0, 1, 0];
  var camera = m4.lookAt(eye, target, up);
  var view = m4.inverse(camera);

  var worldViewProjection = m4.multiply(view, projection);
  var uniforms = {
    u_worldViewProjection: worldViewProjection,
  };
  
  gl.useProgram(programInfo.program);
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  twgl.setUniforms(programInfo, uniforms);
  gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

var ctxForMakingTextures;
function createTextTexture(gl, str, width, height) {
    // create an offscreen canvas with a 2D canvas context
    if (!ctxForMakingTextures) {
       ctxForMakingTextures = document.createElement("canvas").getContext("2d");
    }
    var ctx = ctxForMakingTextures;
    
    // make it a desired size 
    ctx.canvas.width = width;
    ctx.canvas.height = height;
    
    // fill it a certain color
    ctx.fillStyle = "rgb(255,0,0)";  // red
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    
    // draw some text into it.
    ctx.fillStyle = "rgb(255,255,0)";  // yellow
    ctx.font = "40px sans-serif";
    ctx.fillText("Hello World", 5, 40);
    
    // Now make a texture from it
    var tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, ctx.canvas);
    
    // generate mipmaps or set filtering 
    gl.generateMipmap(gl.TEXTURE_2D);
    
    return tex;
};

html, body, canvas {
  width: 100%;
  height: 100%;
  margin: 0;
}

<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<script id="vs" type="not-js">
attribute vec4 position;
attribute vec2 texcoord;

varying vec2 v_texcoord;
    
uniform mat4 u_worldViewProjection;

void main() {
   gl_Position = u_worldViewProjection * position;
   v_texcoord = texcoord;
}
</script>
<!-- fragment shader -->
<script id="fs" type="not-js">
precision mediump float;
    
varying vec2 v_texcoord;

uniform sampler2D u_texture;
void main() {
   gl_FragColor = texture2D(u_texture, v_texcoord);
}
</script>
<canvas id="c"></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

如果我理解正确,您正尝试使用OpenGL在3D中显示文本。以下是您应该考虑的几个选项:

  1. 使用要显示的文本创建常规矩形纹理,并在简单的4顶点矩形上进行渲染。这是最简单的实现,但它需要为要显示的每个字符串生成不同的纹理。

  2. 如上所述,创建一个矩形纹理,但这一次,为您希望能够支持的每个字母/字符创建一个。然后,构建一个工厂,为某个字符串中的每个字母生成4个顶点矩形,为每个形状选择合适的字母。你需要做一些好的定位,但这会给你一个相当灵活的解决方案。

  3. 与#2类似,但这一次,使用一些无缝纹理,但为您希望支持的每个字母/字符生成形状。每个形状将包含多个顶点,除非您使用外部图形资源,否则可能需要一些时间才能完成。但是,这个实现将为您提供最令人印象深刻的显示文本的方法,因为每个字母在空间中显示为三维对象。