2013-10-27 13 views
7

Używam trzech JS do opracowania wykresu 3d. Chcę pokazać jednostki wykresu jako THREE.SPRITE. Aby utworzyć SPRITE, najpierw utworzyłem element canvas i dodałem do niego tekst. Następnie utworzyłem THREE.Texture z elementem canvas, który został wcześniej utworzony. Utworzono THREE.SpriteMaterial z teksturą jako mapą, a następnie utworzono THREE.SPRITE przy użyciu tego sprite'a. Dodano ten sprite materiał do sceny. Gdy renderer jest instancją o rozmiarze THREE.WebGLRenderer, rozmiar tekstu jest bardzo mały, a gdy renderer jest instancją o numerze THREE.CanvasRenderer, rozmiar tekstu jest bardzo duży.ThreeJS: Różnica wielkości czcionki tekstu Sprite między renderem WebGL a rendererem Canvas

Poniżej znajduje się kod, którego użyłem do utworzenia 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); 

Czy jest to zachowanie domyślne, czy też robię coś złego. Zaproponuj mi jakąś poprawkę, która działa konsekwentnie zarówno w renderach Canvas, jak i WebGL.

Z góry dziękuję.

+0

Niestety, 'WebGLRender' i' CanvasRenderer' nie zmieniają sprite'ów tak samo. To jest coś, co powinno zostać naprawione. – WestLangley

+0

Dzięki za odpowiedź. Czy mogę wiedzieć, czy różnica w rozmiarach jest proporcjonalna/względna podczas skalowania za pomocą CanvasRenderer i WebGLRenderer, dzięki czemu mogę użyć bloku if-else i napisać inną logikę dla dwóch renderers. Wystarczy, że rozmiary tekstu są podobne (a nie dokładnie takie same). – Kishor

+0

Używając 'WebGLRenderer',' Sprite' mający skalę (1, 1, 1) powinien renderować ten sam rozmiar co "PlaneGeometry" o rozmiarze (1, 1) o tej samej lokalizacji. (three.js r.62) Dla 'CanvasRenderer', nie jestem pewien jaka jest logika skalowania. Być może uda się go wyśledzić i zaproponować poprawę. – WestLangley

Odpowiedz

6

Po wypróbowaniu tak wielu kombinacji zadziałał poniższy kod.

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

Dodaj TRZY link JS (release 62) i użyj następującego skryptu.

Mam nadzieję, że pomoże to innym osobom z podobnymi problemami.

Aktualizacja: Oto jsfiddle powyższego kodu.

+0

Wygląda na to, że jednostki sprite są w pikselach dla renderer canvas2d (1 piksel = 1 jednostka światowa), ale jednostki są jednostkami światowymi dla renderera webgl. Dlatego powyżej, musisz przeskalować wysokość canvas2d o 2/100, ale renderowanie webgl o 2. Być może pomaga to ktoś taki jak @WestLangley zobaczyć, gdzie jest niespójność? –

+0

Działa to całkiem dobrze w przypadku renderera WebGL, jedynym problemem jest pikselowanie tekstu. Czy masz ten problem? – BuildingJarl