Substract 3D text to a Geometry in Three.js - javascript

I want to transform my 3D text to Geometry so I can use it with CSG (I used a Three.js CSG wrapper also) to substract it from another object like in this question.
My 3D text :
loader.load('optimer_regular.typeface.json', function (font){
var text = new THREE.TextGeometry('Tayst', {
font: font,
size: 4,
height: 3
});
var textMat = new THREE.MeshBasicMaterial({color: 0xffffff});
var textGeo = new THREE.Mesh(text, textMat);
textGeo.position.x = -7;
textGeo.position.z = 6;
scene.add(textGeo);
});
My substract thing I want to do for the 3D text (but here it's from circles):
var dots = new THREE.Geometry();
for(var i = 0; i < coordinates.length; i++){
var coords = coordinates[i];
sphereMesh.position.x = coords[0];
sphereMesh.position.y = coords[1];
sphereMesh.position.z = coords[2];
sphereMesh.updateMatrix();
dots.merge(sphereMesh.geometry, sphereMesh.matrix);
}
var sphereCsg = THREE.CSG.toCSG(dots);
var resultGeo = THREE.CSG.fromCSG(resultCsg.subtract(sphereCsg));
cube = new THREE.Mesh(resultGeo, material);
But the thing is, I think, I need to convert my text to a real Geometry so I can substract it?

Well i found out using the library I already got, but instead I didn't had to do the "merge" for example.
Here is the working code (in case someone needs it) :
var loader = new THREE.FontLoader();
loader.load('helvetiker_regular.typeface.json', function (font){
var text = new THREE.TextGeometry('Test', {
font: font,
size: 4,
height: 0.5
});
var textGeo = new THREE.Mesh(text);
textGeo.position.x = -5;
textGeo.position.z = 7.5;
var txtCsg = THREE.CSG.toCSG(textGeo);
var resultGeo = THREE.CSG.fromCSG(resultCsg.subtract(txtCsg));
cube = new THREE.Mesh(resultGeo, material);
scene.add(cube);
});

Related

How to color a shape in Babylon.js?

Working off the "Basic Scene" example on babylonjs-playground.com here, I am trying to do a simple modification on the color of the sphere.
Here is my attempt, which can be run interactively:
https://www.babylonjs-playground.com/#95BNBS
Here is the code:
var createScene = function () {
// The original example, without comments:
var scene = new BABYLON.Scene(engine);
var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControl(canvas, true);
var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.7;
var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
sphere.position.y = 1;
var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
// My attempt to color the sphere
var material = new BABYLON.StandardMaterial(scene);
material.alpha = 1;
material.diffuseColor = new BABYLON.Color3(1,0,0);
scene.material = material;
return scene;
};
My attempt to add the colored material to the sphere has no effect.
I also tried to look for color-related attributes on the sphere object:
Object.keys(sphere).filter((key) => return key.includes("Color") )
// => "outlineColor", "overlayColor", "_useVertexColors", "edgesColor"
Except for _useVertexColors, all of these seem to be color objects, but changing them has no effect:
sphere.overlayColor.g = 1;
sphere.outlineColor.g = 1;
sphere.edgesColor.g = 1;
You're pretty close. You are setting a color correctly with diffuseColor but you aren't actually adding it specifically to your sphere.
Your sphere object is stored in sphere so what you need to do is you need to set the material you created on sphere and not on scene.
// My attempt to color the sphere
var material = new BABYLON.StandardMaterial(scene);
material.alpha = 1;
material.diffuseColor = new BABYLON.Color3(1.0, 0.2, 0.7);
sphere.material = material; // <--
See this tutorial

three.js fontloader cannot read generateshapes of undefined

I have the following code that generates some meshes. I want to add 3d text to the scene but when i do this i get the following error:
TypeError: Cannot read property 'generateShapes' of undefined
this is the code i have to generate the meshes and the 3d text:
var x = 0;
var y = 0;
var finalSize = 450;
var textureLoader = new THREE.TextureLoader();
var fontLoader = new THREE.FontLoader();
the var font is undefined why?
var font = fontLoader.load( 'css/arial_bold.json');
var fontColor = textMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, overdraw: 0.5 });
for (var i = javascriptProjects.length - 1; i >= 0; i--) {
var object = {};
object.scale = javascriptProjects[i].baseImageData["0"] / finalSize;
var geometry = new THREE.PlaneGeometry(javascriptProjects[i].baseImageData["0"]/object.scale,javascriptProjects[i].baseImageData["1"]/object.scale, 10, 10);
object.texture = textureLoader.load( "data/"+ javascriptProjects[i].base_image );
object.material = new THREE.MeshBasicMaterial( { map: object.texture, overdraw: 0.5, transparent: true } );
object.material.opacity = 0.5;
object.mesh = new THREE.Mesh(geometry, object.material);
//the line below generates the error
object.FontGeo = new THREE.TextGeometry( javascriptProjects[i].project_name , {
font: font,
size: 50,
height: 2,
curveSegments: 12,
bevelThickness: 1,
bevelSize: 1,
bevelEnabled: false
});
object.textMesh = new THREE.Mesh( object.FontGeo, fontColor );
object.textMesh.position.x = object.location.x;
object.textMesh.position.y = object.location.y;
object.textMesh.position.z = object.location.z - 100;
scene.add(object.textMesh);
object.location = new THREE.Vector3(x, 120, y);
object.id = "" + javascriptProjects[i].project_id;
object.mesh.position.x = object.location.x;
object.mesh.position.y = object.location.y;
object.mesh.position.z = object.location.z;
scene.add(object.mesh);
meshes.push(object.mesh);
objects.push(object);
x += 600;
if(i % 3 == 0){
y += 600;
x = 0;
};
};
apparently font is undefined. why i don't see what i am doing wrong. Any suggestions would be great. If something is not clear let me know.
Thanks in advance
FontLoader.load() is an asynchronous function call. This is why there is an onLoad call back function.
The library is calling font.generateShapes() before the font is loaded.
Use a pattern like this one, instead:
var loader = new THREE.FontLoader();
loader.load( 'myFontFile.json', function ( font ) {
// insert your code here
} );
See, for example, this three.js example, and the three.js documentation .
three.js r.84

Strange result with ThreeCSG and subtract

I'm learning three.js and for a project i need to create an inersection between a cylinder and a sphere.
Here is the interesting part of the code :
var sphere_mesh_3 = createSphereMesh(rayon_1, 145, color);//,-2,2,-2,2);
sphere_mesh_3.position.z = 6;
//scene.add(sphere_mesh_3);
var sphere_mesh_4 = createSphereMesh(rayon_2, 145, color);//,-2,2,-2,2);
sphere_mesh_4.position.z = 7.5;
//scene.add(sphere_mesh_4);
function getZmaxRelSurfaceAspherique(mesh)
{
var zMax = 0;
for(var i = 0; i < mesh.geometry.vertices.length; i++)
{
var vec = mesh.geometry.vertices[i].clone();
var x = vec.x;
var y = vec.y;
var z = vec.z;
var abs_z = Math.abs(z);
if(x!== 0 && y!==0 && Math.abs(z) !== 1.0)
{
zMax = abs_z;
}
}
return zMax;
}
var min_sph_2 = getZmaxRelSurfaceAspherique(sphere_mesh_3);
var max_sph_2 = getZmaxRelSurfaceAspherique(sphere_mesh_4);
var pos_z_1 = 6 + min_sph_2;
var pos_z_2 = 7.5 + max_sph_2;
var cylindre_sph = cylindreJointure(0,0,pos_z_2,0,0,pos_z_1,Math.abs(rayon_1*80),0xffff00);
var distance = Math.abs(pos_z_1 - pos_z_2);
scene.add(cylindre_sph);
R_sph = (max_sph_2*max_sph_2 + rayon_2*rayon_2)/(2*max_sph_2);
var geometry = new THREE.SphereGeometry( R_sph, 40, 40 );
var material = new THREE.MeshBasicMaterial( {color: 0x00ffff} );
var sphere = new THREE.Mesh( geometry, material );
sphere.position.z = pos_z_2 + R_sph - max_sph_2 ;
scene.add( sphere );
var cylindre_bsp = new ThreeBSP(cylindre_sph);
var sphere_bsp = new ThreeBSP(sphere);
var inter = cylindre_bsp.subtract(sphere_bsp);
var result_1 = inter.toMesh(new THREE.MeshBasicMaterial({color : 0x0000ff}));
result_1.position.z = 15;
result_1.rotateX( Math.PI/2 );
scene.add(result_1);
Here is my two objets:
Cylinder and Sphere
....And the result :
After cylinder.subtract(sphere)...strange result
I don't understand why the substract betwwen the cylinder and the sphere give me these results.
thank you in advance :)
PS : I'm using three.js r74 and the latest version for threeCSG. Like it's impossible for the CSG to maintain the position of the Mesh with the r74 version ... but i can't change my version of three.js ^^''

Create 50000+ Text Particles in THREE.js

Im trying to create a character particlesystem with more than 50000 single letters.
Found something similar but written with XG here.
Problem with creating this is the performance of the application.
Here some short pseudo code:
var field = new THREE.Object3D();
for (var i = 0; i < 50000; i++) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.fillText(char);
var texture = new THREE.Texture(canvas)
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({map: texture});
var sprite = new THREE.Sprite(spriteMaterial);
sprite .position.set(x, y, z);
field.add(textSprite);
}
scene.add(field);
So my question is now, is there some example or something where i can see the best way to create this number of textsprites?!
I've also tried this example without a good result.
As vals noted, you are creating material and a texture for every letter. The fact that you are creating a canvas too is beside the point, that's just a one-off overhead.
Every texture you create will have to take up graphics memory. After the fact of texture, every material is computed separately in every render pass, so for 50000 materials you have a lot of computation.
A simple way to speed what you have up would be to use look-up tables:
var materialLUT = {};
function getMaterialForLetter(c){
var m = materialLUT[c];
if(m === void 0){
//material doesn't exist, lets create it
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.fillText(c);
var texture = new THREE.Texture(canvas)
texture.needsUpdate = true;
m = materialLUT[c] = new THREE.SpriteMaterial({map: texture});
}
return m;
}
var field = new THREE.Object3D();
for (var i = 0; i < 50000; i++) {
var spriteMaterial = getMaterialForLetter(char);
var sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(x, y, z);
field.add(textSprite);
}
scene.add(field);
Another thing i see that should be improved here is use of PointCloud. And lastly - I think it would be best to use a single texture and get relevant characters via UV.

Three.js - Edit plane geometry

So, I want to make a simple terrain editor. So, on mouseDown, I want the selected face to move up.
The intersection works great, and I try to modify the geometry like so:
var intersects2 = ray.intersectObjects([plane]);
if (intersects2.length > 0) {
var face = intersects2[0].face;
var obj1 = intersects2[0].object;
var geo = obj1.geometry;
geo.vertices[face.a].z += 50;
geo.vertices[100].z += 50;
geo.vertices[0].z += 50;
geo.computeVertexNormals();
geo.computeFaceNormals();
geo.__dirtyVertices = true;
geo.__dirtyNormals = true;
console.log(face.a);
}
The console log shows the correct vertex index, but nothing on the plane moves. Any ideas why?
The plane is created like this:
var planegeo = new THREE.PlaneGeometry( 500, 500, 10, 10 );
planegeo.dynamic = true;
plane = new THREE.Mesh( planegeo, new THREE.MeshPhongMaterial( { color: 0x99ff66 } ) );
plane.receiveShadow = true;
scene.add( plane );
Looking at your code, it looks like you are using syntax pre R49. It may just be that you need to update your dirty flag code to (assuming you are now using a newer library!):
geo.verticesNeedUpdate = true;
geo.normalsNeedUpdate = true;

Categories

Resources