Three.js - How to make my text sprite clearer? - javascript

i need my text sprite to look more clear/strong (easiest to read), here is the code where i create it:
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 8px Arial";
context1.fillStyle = "rgba(255,0,0,0.95)";
context1.fillText(text, 170, 60);
var texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial( { map: texture1, color: 0xffffff, fog: true } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set(window.innerWidth/5, window.innerHeight/5, 1);
var positionsT = positions.split(",");
sprite.position.set(positionsT[0]-20, positionsT[1]-80, positionsT[2]-40);
scene.add(sprite);
Could anybody give me some advice? this is how it looks at this moment: http://postimg.org/image/uqke1k35h/

One thing you can do is to turn off mip-mapping so that no texture filtering is applied texture1.generateMipmaps = false;
The other thing you can do is not scale the texture to an aspect ratio too much different from your canvas aspect ratio which of course depends on the size of your text.

Related

How to use a number of pictures to form a graphic in three.js

I want to use three.js to generate a shape(maybe some word) composed of some pictures like that:
I think what i have to do is get some points which form a shape, then put the picture to these points. I have searched for something information , but i still have no idea how can i get these points because the shape maybe irregular. Is there any solutions?
The way I see it, you have two ways to proceed here:
You can use a modeling software like Blender to first generate the shape along with the pictures, and then export the JSON (refer this for how to setup the threejs json exporter in blender ) and then use the JSON loader to load that JSON.
The other way is that you create simple geometries of your requried shape using the ones threejs provides like box, circle, etc ( refer docs ) and then add textures to it as shown here .
Hope one of these solutions is what you're looking for.
I would use the canvas to plot the 3d positions of each photo.
I created a fiddle here with text:
https://jsfiddle.net/2qu6m4h3/
And one with random shapes:
https://jsfiddle.net/d2th9ekb/
It creates a canvas element to draw text to. It interrogates the canvas for pixel positions. Those positions are then sent to a function which places cubes in 3d. Rather than place cubes you could place sprite objects which display each one of your photos. Use the scale property to give yourself more room between positions.
Here's the code:
/*
Start Setup text canvas and tools
*/
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.canvas.width = 400;
ctx.canvas.height = 200;
function createTextSourceCanvas(text,src) {
src.font = '50pt Times';
src.fillStyle = '#00ff00';
src.fillRect(0, 0, canvas.width, canvas.height);
src.fillStyle = '#FFFFFF';
src.textAlign = "center";
src.textBaseline = "middle";
src.fillText(text, canvas.width /2, canvas.height /2);
}
function examineText(src, fi){
var positiveResults = [];
var width = src.canvas.width;
var height = src.canvas.height;
var imgData = src.getImageData(0, 0,width, height);
for(var x = 0; x < width; x+=fi){
for(var y = 0; y < height; y+=fi ){
var pixel = getPixelXY(imgData, x, y)
if(pixel[0] == 0 && pixel[1] == 255 && pixel[2] == 0){
continue;
}
positiveResults.push([x,y]);
}
}
return positiveResults;
}
function getPixel(imgData, index) {
var i = index*4, d = imgData.data;
return [d[i],d[i+1],d[i+2],d[i+3]]
}
function getPixelXY(imgData, x, y) {
return getPixel(imgData, y*imgData.width+x);
}
/*
End Setup text canvas and tools
*/
/*
Start Setup Threejs canvas and tools
*/
var scene;
var renderer;
var camera;
var cube;
var controls;
function init3d(){
renderer = new THREE.WebGLRenderer( {antialias:true} );
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize (width, height);
document.body.appendChild (renderer.domElement);
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera (45, width/height, 1, 10000);
camera.position.y = 160;
camera.position.z = 400;
camera.lookAt (new THREE.Vector3(0,0,0));
controls = new THREE.OrbitControls (camera, renderer.domElement);
var gridXZ = new THREE.GridHelper(100, 10);
scene.add(gridXZ);
var pointLight = new THREE.PointLight (0xffffff);
pointLight.position.set (0,300,200);
scene.add (pointLight);
window.addEventListener ('resize', onWindowResize, false);
}
function onWindowResize (){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize (window.innerWidth, window.innerHeight);
}
function animate(){
controls.update();
requestAnimationFrame ( animate );
renderer.render (scene, camera);
}
/*
End Setup Threejs canvas and tools
*/
/*
Start create 3d from text examination
*/
function create3dProjectionText(scene, positions, wExtent, hExtent, scale){
if(scale == undefined){
scale = 1;
}
var group = new THREE.Object3D();
var cubeGeometry = new THREE.BoxGeometry (2,2,2);
var cubeMaterial = new THREE.MeshLambertMaterial ({color: 0xFFFFFF});
for(var i in positions){
cube = new THREE.Mesh (cubeGeometry, cubeMaterial);
cube.position.set (positions[i][0]*scale - (wExtent*scale/2), positions[i][1]*scale -(hExtent*scale/2), 0);
group.add (cube);
}
group.rotateX( -Math.PI );
scene.add(group);
}
/*
End create 3d from text examination
*/
//initialize the 3d space
init3d();
//initialize the text canvas
createTextSourceCanvas("Hello World", ctx);
//
create3dProjectionText(scene, examineText(ctx ,4), ctx.canvas.width, ctx.canvas.height, 1.5);
animate();

Babylonjs load two images on top of eachother with the second image being transparent

I am using babylonjs to load up two images. One is a standard jpg image and teh second is a png image with transparent background When i load both the image loads on top of each other but the jpg image doesnt show through the area that should be transparent. Anyone know how i can do this.
var createScene = function() {
var scene = new BABYLON.Scene(engine);
//Create a light
var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(-60, 60, 80), scene);
//Create an Arc Rotate Camera - aimed negative z this time
var camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, 1.0, 210, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
//Creation of a repeated textured material
var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
materialPlane.diffuseTexture = new BABYLON.Texture("images/art.jpg", scene);
//materialPlane.emissiveTexture = new BABYLON.Texture('images/scodix1.png', scene);
//materialPlane.useAlphaFromDiffuseTexture
materialPlane.specularColor = new BABYLON.Color3(0, 0, 0);
materialPlane.backFaceCulling = false; //Allways show the front and the back of an element
var spotPlain = new BABYLON.StandardMaterial("texture", scene, true);
spotPlain.emissiveTexture = new BABYLON.Texture("images/scodix1.png", scene);
spotPlain.anisotropicFilteringLevel = 50;
//materialPlane.emissiveTexture = new BABYLON.Texture('images/transparent.png', scene);
//materialPlane.useAlphaFromDiffuseTexture
spotPlain.specularColor = new BABYLON.Color3(0, 0, 0);
spotPlain.backFaceCulling = false; //Allways show the front and the back of an element
//Creation of a plane
//var plane = BABYLON.Mesh.CreatePlane("plane", 120, scene);
var plane = BABYLON.MeshBuilder.CreatePlane("plane", {
width: 261,
height: 153
}, scene);
plane.rotation.x = Math.PI / 2;
plane.material = materialPlane;
plane.material = spotPlain;
return scene;
};
var scene = createScene();
engine.runRenderLoop(function() {
scene.render();
});
you are overwriting the material here:
plane.material = materialPlane;
plane.material = spotPlain;
I suggest creating two planes

Texture in threejs is not updating

I'm using the threejs editor as base for some threejs work.
I'm trying to show some tooltips when the user hovers over certain elements.
To achieve this I use a canvas which is rendered as texture on a sprite.
// create a canvas element
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);
// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;
// use the texture as material
var spriteMaterial = new THREE.SpriteMaterial({
map: texture1,
useScreenCoordinates: false
});
// create the sprite and add it tho the scene
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(1000, 500, 1.0);
sprite1.position.set(50, 50, 0);
scene.add(sprite1);
var i = 0;
// change the canvas' content
setInterval(function () {
context1.clearRect(0, 0, canvas1.width, canvas1.height);
var message = 'test' + i++;
context1.fillText(message, 4, 20);
texture1.needsUpdate = true;
}, 1000)
"test0" is shown, but the sprite does not update. How to update the text on the sprite? Am I missing some cache invalidation here?
Why render the text box on your 3D canvas? It would be much better IMO to position your 2D html object by projecting the 3D object position in the 2D context of your page.
The advantage is that there won't be any rendering performance decrease and you can use normal CSS/HTML styling for your info box.
Check a great example on how you can do that here.
And another one belonging to this stackoverflow answer. Works as simple as this:
var proj = toScreenPosition(divObj, camera);
divElem.style.left = proj.x + 'px';
divElem.style.top = proj.y + 'px';
But if you do some googling you can easily find more examples...
Here is a fiddle to fool around with.
I think it is not working because you have not set the height and width of the canvas.
canvas1.width = 256;
canvas1.height = 256;
This line was also a problem: context1.fillStyle = "rgba(0.0,0,0,0.95)";
I changed it to : context1.fillStyle = '#ff0000'; for mine to work
Here is a fiddle with your code implemented, just added height and width to canvas and changed fillStyle
Wilt's answer is probably an better alternative if it fills your needs.
EDIT: I'm a moron. This question is 2 years old.
It seems to be working for me... Are you sure you're not overlooking some errors in the console? Did you put a breakpoint in your setInterval to make sure it's getting called?
I did have to move the update to the renderloop as setInterval didn't seem to be defined for SO snippets, but check it out here:
var renderer = new THREE.WebGLRenderer();
var w = 300;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
45, // Field of view
w / h, // Aspect ratio
0.1, // Near
10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.PointLight(0xFFFF00);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);
var sphereGeom = new THREE.SphereGeometry(5, 16, 16);
for (var i = 0; i < sphereGeom.vertices.length; i++) {
var v = sphereGeom.vertices[i];
if (v.y < 0) v.y = 0;
}
sphereGeom.verticesNeedUpdate = true;
sphereGeom.computeFaceNormals();
sphereGeom.computeVertexNormals();
var material = new THREE.MeshLambertMaterial({
color: 0x808080
});
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
renderer.setClearColor(0xdddddd, 1);
// create a canvas element
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);
// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;
// use the texture as material
var spriteMaterial = new THREE.SpriteMaterial({
map: texture1,
useScreenCoordinates: false
});
// create the sprite and add it tho the scene
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(40, 20, 1.0);
sprite1.position.set(-5, 0, -5);
scene.add(sprite1);
var i = 0;
(function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
context1.clearRect(0, 0, canvas1.width, canvas1.height);
var message = 'test' + i++;
context1.fillText(message, 4, 20);
texture1.needsUpdate = true;
})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

How to turn off the mesh in THREE.MeshBasicMaterial

I'm using THREE.js to draw an image and its reflection. How do I turn off the mesh that appears in the reflection? It seems to only happen when I'm altering the alpha channel.
imageReflection = document.createElement('canvas');
imageReflection.width = 480;
imageReflection.height = 204;
imageReflectionContext = imageReflection.getContext('2d');
imageReflectionContext.fillStyle = '#000000';
imageReflectionContext.fillRect(0, 0, 480, 204);
textureReflection = new THREE.Texture(imageReflection);
var materialReflection = new THREE.MeshBasicMaterial({map:textureReflection, side:THREE.BackSide, transparent:true, overdraw:0.5});

THREE.js How to stop truncation of text in texture made from 2D canvas

It seems quite common for people to use this 2d canvas texture method for producing text billboards, sprites, overlays in THREE.js scenes as an alternative to making textures from imported image files e.g. Lee Stemkoski's example.
However when I try such method for text strings longer than a few characters the text in the finished graphic object is truncated.
Here is a JSFiddle
Here is the relevant code
function F_Text_Plane_Make_wo_box(text)
{
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 40px Arial";
context1.fillStyle = "rgba(155,0,200,0.95)";
context1.fillText(text, 0, 50);
var texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;
var material1 = new THREE.MeshBasicMaterial
( { map: texture1, side:THREE.DoubleSide } );
material1.transparent = true;
var mesh1 = new THREE.Mesh(
new THREE.PlaneGeometry(canvas1.width, canvas1.height),
material1
);
return mesh1;
}
It occurs in Chrome, Opera and Firefox on Windows7 laptop.
UPDATE
Thanks to West Langley for clarifying matters. It appears that we can't easily and automatically construct a plane which contains the supplied text string and no trailing white space. This limitation can be worked around using transparency or a fixed-width destination container.
Here is a JSFiddle
Here is relevant code
//=============================================================================
function F_Text_onto_Plane(text, Tbox_width, Tbox_depth)
{
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
canvas1.width = Tbox_width; canvas1.height = Tbox_depth;
context1.font = "Bold 40px Arial"; //... font as big and simple as possible so graphics look smooth
var metric = context1.measureText(text);
var text_len_pixels = metric.width;
//------------ Backing Rectangle ------------
context1.fillStyle = "rgba(255,255,255,0.95)"; //... White
//..x1,y1, x2,y2 origin in top left corner x increasing rightwards, y increasing downwards.
context1.fillRect(0,0, Tbox_width, Tbox_depth); //... rectangle matches the Tbox_width and Tbox_depth
context1.fillStyle = "rgba(255,255,0,0.95)"; //... Yellow, probably change to white in practice.
context1.fillRect(0,0,5+text_len_pixels+5,Tbox_depth); //... very good fit to the particular text
//------------- Paint the Text onto canvas ----------------
context1.fillStyle = "rgba(0,0,0,1)";//... Black.
context1.fillText(text , 0+5, Tbox_depth-5);//... text string, start_x, start_y (start point is bottom left of first character).
//------------------------------------------------
//... canvas contents will be used for a texture
//... note this takes the everything within the canvas area, including the canvas background.
var texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;
var material1 = new THREE.MeshLambertMaterial( { map: texture1, side:THREE.DoubleSide } );
material1.transparent = true;
var mesh1 = new THREE.Mesh(
new THREE.PlaneGeometry(Tbox_width, Tbox_depth),
material1 );
//... can scale the plane e.g. mesh1.scale.set(100,50,1.0);
//... alert ("Checkout: http://stackoverflow.com/questions/4532166/how-to-capture-a-section-of-a-canvas-to-a-bitmap?lq=1");
//... can use .lookat to make plane face a single camera in the scene.
//... can use THREE.js Sprite to make plane look at all cameras in the scene.
return mesh1;
}
You need to set the canvas width:
var canvas1 = document.createElement( 'canvas' );
canvas1.width = 512;
canvas1.height = 64;
var texture1 = new THREE.Texture( canvas1 );
texture1.needsUpdate = true;
var material1 = new THREE.MeshLambertMaterial( { map: texture1, side:THREE.DoubleSide, transparent = true } );
Now, when you create your mesh geometry, you specify its size in world units, not in pixels:
var mesh1 = new THREE.Mesh( new THREE.PlaneGeometry( 1024, 128 ), material1 );
three.js r.70

Categories

Resources