2013-10-27 78 views
7

我使用Three JS開發3D圖形。我想顯示一個圖表的單位爲THREE.SPRITE。爲了創建SPRITE,我首先創建了一個畫布元素並向其添加文本。然後,我用之前創建的畫布元素創建了THREE.Texture。用紋理創建THREE.SpriteMaterial作爲貼圖,然後使用此精靈材質創建THREE.SPRITE。將這個精靈材質添加到場景中。當渲染器是THREE.WebGLRenderer的實例時,文本的大小非常小,並且渲染器是THREE.CanvasRenderer的實例時,文本的大小非常大。ThreeJS:Text Sprite的WebGL渲染器和Canvas渲染器之間的字體大小差異

以下是我用來創建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渲染器中工作的任何修補程序。

在此先感謝。

+0

不幸的是,'WebGLRender'和'CanvasRenderer'不能縮放精靈。這是應該解決的問題。 – WestLangley

+0

感謝您的回覆。當我使用CanvasRenderer和WebGLRenderer進行縮放時,可以知道尺寸差異是否與比例/相對有關,以便我可以使用if-else塊併爲兩個渲染器編寫不同的邏輯。如果文本大小相似(不完全相同),對我來說就足夠了。 – Kishor

+0

使用'WebGLRenderer',具有比例(1,1,1)的'Sprite'應該呈現與具有相同位置的大小爲(1,1)的'PlaneGeometry'相同的尺寸。 (three.js r.62)對於'CanvasRenderer',我不確定縮放邏輯是什麼。也許你可以追蹤並提出改進建議。 – WestLangley

回答

6

嘗試這麼多組合後,下面的代碼工作。

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); 

添加THREE JS(版本62)鏈接並使用以下腳本。

希望這可以幫助其他類似問題的人。

更新:這裏是上述代碼的jsfiddle

+0

似乎sprite單元以canvas2d渲染器的像素爲單位(1像素= 1的世界單位),但單位是webgl渲染器的世界單位。因此,在上面,您需要將canvas2d高度縮放2/100,而webgl渲染器縮放爲2.也許這有助於像@WestLangley這樣的人查看不一致性的位置? –

+0

這對WebGL渲染器來說效果很好,唯一的問題是文本是像素化的。你有這個問題嗎? – BuildingJarl