I am using Three JS to develop a 3d graph. I want to show units of a graph as THREE.SPRITE
. For creating SPRITE
, I have first created a canvas element and added text to it. Then I have created THREE.Texture
with the canvas element that was previously created. Created THREE.SpriteMaterial
with the texture as a map and then created THREE.SPRITE
using this sprite material. Added this sprite material to scene. When the renderer is an instance of THREE.WebGLRenderer
the size of text is very small and when the renderer is an instance of THREE.CanvasRenderer
then the size of text is very large.
Following is the code that I have used to create 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);
Is it the default behavior or am I doing anything wrong. I am seeking a fix that works in both Canvas and WebGL renderers consistently.
After trying so many combinations, the following code worked.
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);
Add THREE JS (release 62) link and use the following script.
Hope this helps others with similar problems.
Update: Here is the jsfiddle of the above code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With