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.
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.
Share Improve this question edited Nov 24, 2019 at 13:05 halfer 20.4k19 gold badges109 silver badges202 bronze badges asked Oct 27, 2013 at 12:56 KishorKishor 2,6774 gold badges18 silver badges34 bronze badges 4-
Unfortunately,
WebGLRender
andCanvasRenderer
do not scale sprites the same. This is something that should be fixed. – WestLangley Commented Oct 28, 2013 at 2:03 - Thanks for the reply. Can I know the whether the difference in sizes is proportional/relative when scaled using CanvasRenderer and WebGLRenderer, so that I can use an if-else block and write different logic for two renderers. It is sufficient for me if text sizes are similar (and not exactly the same). – Kishor Commented Oct 28, 2013 at 2:50
-
With
WebGLRenderer
, aSprite
having scale ( 1, 1, 1 ) should render the same size as aPlaneGeometry
of size ( 1, 1 ) having the same location. (three.js r.62) ForCanvasRenderer
, I am not sure what the scaling logic is. Perhaps you can track it down and suggest an improvement. – WestLangley Commented Oct 28, 2013 at 3:22 - Okay. Thanks for taking your time to help me. I am working on it now. If I find any fix I will suggest. Thanks. – Kishor Commented Oct 28, 2013 at 3:34
1 Answer
Reset to default 6After trying so many binations, 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.