【问题标题】:ThreeJS: Text Sprite's font size difference between WebGL renderer and Canvas rendererThreeJS:Text Sprite 的 WebGL 渲染器和 Canvas 渲染器的字体大小差异
【发布时间】:2013-11-06 06:01:06
【问题描述】:

我正在使用 Three JS 开发 3d 图形。我想将图表的单位显示为THREE.SPRITE。为了创建SPRITE,我首先创建了一个画布元素并向其中添加了文本。然后我用之前创建的画布元素创建了THREE.Texture。使用纹理作为贴图创建THREE.SpriteMaterial,然后使用此精灵材质创建THREE.SPRITE。将此精灵材质添加到场景中。当渲染器是THREE.WebGLRenderer 的实例时,文本的大小非常小,而当渲染器是THREE.CanvasRenderer 的实例时,文本的大小非常大。

以下是我用来创建 Sprite 的代码。

var canvas = document.createElement('canvas'),
    context = canvas.getContext('2d'),
    metrics = null,
    textHeight = 100,
    textWidth = 0,
    actualFontSize = 20;

context.font = "normal " + textHeight + "px Arial";
metrics = context.measureText("Sample Text");
var textWidth = metrics.width;

canvas.width = textWidth;
canvas.height = textHeight;
context.font = "normal " + textHeight + "px Arial"; 
context.textAlign = "center";
context.textBaseline = "middle";
context.fillStyle = "#ff0000";
context.fillText("Sample Text", textWidth / 2, textHeight / 2);

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;

var material = new THREE.SpriteMaterial({ map: texture, useScreenCoordinates: false, alignment: THREE.SpriteAlignment.center });
material.transparent = true;
//var textObject = new THREE.Sprite(material);
var textObject = new THREE.Object3D();
var sprite = new THREE.Sprite(material);
textObject.textHeight = actualFontSize;
textObject.textWidth = (textWidth / textHeight) * textObject.textHeight;
//sprite.scale.set(textObject.textWidth / textWidth, textObject.textHeight / textHeight, 1);
textObject.add(sprite);

scene.add(textObject);

这是默认行为还是我做错了什么。我正在寻找一种在 Canvas 和 WebGL 渲染器中始终有效的修复程序。

【问题讨论】:

  • 不幸的是,WebGLRender 和 CanvasRenderer 缩放精灵的比例不同。这是应该解决的问题。
  • 感谢您的回复。我可以知道使用 CanvasRenderer 和 WebGLRenderer 缩放时大小的差异是否成比例/相对,以便我可以使用 if-else 块并为两个渲染器编写不同的逻辑。如果文本大小相似(并且不完全相同),对我来说就足够了。
  • 对于WebGLRenderer,具有比例( 1, 1, 1 ) 的Sprite 应该呈现与具有相同位置的大小( 1, 1 ) 的PlaneGeometry 相同的大小。 (three.js r.62) 对于CanvasRenderer,我不确定缩放逻辑是什么。也许您可以追踪它并提出改进建议。
  • 好的。感谢您花时间帮助我。我现在正在努力。如果我找到任何解决方法,我会建议。谢谢。

标签: javascript html5-canvas three.js


【解决方案1】:

在尝试了这么多组合之后,下面的代码成功了。

var SCREEN_WIDTH = 400,
    SCREEN_HEIGHT = 300,
    VIEW_ANGLE = 45,
    ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT,
    NEAR = 0.1,
    FAR = 20000,
    webGLScene = new THREE.Scene(),
    canvasScene = new THREE.Scene(),
    webGLCamera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR),
    canvasCamera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR),
    webGLRenderer = new THREE.WebGLRenderer({ antialias: true }),
    canvasRenderer = new THREE.CanvasRenderer();

webGLScene.add(webGLCamera);
canvasScene.add(canvasCamera);

webGLCamera.position.set(0, 0, 20);
webGLCamera.lookAt(webGLScene.position);

canvasCamera.position.set(0, 0, 20);
canvasCamera.lookAt(canvasScene.position);

webGLRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
canvasRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

container = document.body;
container.appendChild(webGLRenderer.domElement);
container.appendChild(canvasRenderer.domElement);

makeSprite(webGLScene, "webgl");
makeSprite(canvasScene, "2d");

function makeSprite(scene, rendererType) {
    var canvas = document.createElement('canvas'),
        context = canvas.getContext('2d'),
        metrics = null,
        textHeight = 100,
        textWidth = 0,
        actualFontSize = 2;

    context.font = "normal " + textHeight + "px Arial";
    metrics = context.measureText("Sample Text");
    var textWidth = metrics.width;

    canvas.width = textWidth;
    canvas.height = textHeight;
    context.font = "normal " + textHeight + "px Arial";
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillStyle = "#ff0000";
    context.fillText("Sample Text", textWidth / 2, textHeight / 2);

    var texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;

    var material = new THREE.SpriteMaterial({ map: texture, useScreenCoordinates: false, alignment: THREE.SpriteAlignment.center });
    material.transparent = true;
    //var textObject = new THREE.Sprite(material);
    var textObject = new THREE.Object3D();
    var sprite = new THREE.Sprite(material);
    textObject.textHeight = actualFontSize;
    textObject.textWidth = (textWidth / textHeight) * textObject.textHeight;
    if (rendererType == "2d") {
        sprite.scale.set(textObject.textWidth / textWidth, textObject.textHeight / textHeight, 1);
    } else {
        sprite.scale.set(textWidth / textHeight * actualFontSize, actualFontSize, 1);
    }

    textObject.add(sprite);

    scene.add(textObject);
}

canvasRenderer.render(canvasScene, canvasCamera);
webGLRenderer.render(webGLScene, webGLCamera);

添加三个 JS(版本 62)链接并使用以下脚本。

希望这可以帮助其他有类似问题的人。

更新:这是上面代码的jsfiddle。

【讨论】:

  • 对于 canvas2d 渲染器,精灵单位似乎以像素为单位(1 像素 = 1 个世界单位),但这些单位是 webgl 渲染器的世界单位。因此,在上面,您需要将 canvas2d 高度缩放 ​​2/100,但将 webgl 渲染器缩放 2。也许这有助于像 @WestLangley 这样的人看到不一致的地方?
  • 这对 WebGL 渲染器非常有效,唯一的问题是文本被像素化了。你有这个问题吗?
猜你喜欢
  • 2015-02-16
  • 1970-01-01
  • 2020-11-25
  • 2011-09-14
  • 2015-02-26
  • 1970-01-01
  • 2013-03-28
  • 2014-11-29
  • 1970-01-01
相关资源
最近更新 更多