I have 3D text that is created by new THREE.FontLoader():
const loader1 = new THREE.FontLoader();
loader1.load(
// resource URL
'./fonts/helvetiker_regular.typeface.json',
// onLoad callback
(font) => {
const textGeometry1 = new THREE.TextBufferGeometry(
"A",
{
font: font,
size: 0.6,
height: 0.1,
curveSegments: 20,
bevelEnabled: true,
bevelThickness: 0.015,
bevelSize: 0.02,
bevelOffset: 0,
bevelSegments: 50
}
)
const textMaterial1 = new THREE.MeshBasicMaterial({ color: 'black' })
const text1 = new THREE.Mesh(textGeometry1, textMaterial1)
text1.position.set(15.2, 0.2, 6.7)
text1.rotation.set(0, 0.8, 0)
scene.add(text1);
}
);
How can I call function once this text is clicked? I tried to work with mesh but seems like it does not work or I am doing something incorrectly?
Related
I am trying to add a 3D text over the BoxGeometry sides for front, right, left and top.
I implmented this code as below :
loadFont = () =>{
const loader = new THREE.FontLoader();
loader.load( 'https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', function ( response ) {
console.log("response "+response);
return response;
} );}
createText = () => {
let font = this.loadFont();
this.textGeo = new THREE.TextGeometry( "Hello", {
font: font,
size: 70,
height: 20,
curveSegments: 4,
bevelThickness: 2,
bevelSize: 1.5,
bevelEnabled: true
});
const materials = [
new THREE.MeshPhongMaterial( { color: 0xffffff, flatShading: true } ), // front
new THREE.MeshPhongMaterial( { color: 0xffffff } ) // side
];
this.textMesh1 = new THREE.Mesh(this.textGeo, materials );
this.textMesh1.position.y = 80;
this.textMesh1.position.z = 0;
this.textMesh1.rotation.x = 0;
this.textMesh1.rotation.y = Math.PI * 2;
this.scene.add(this.textMesh1);
this.root.add(this.textMesh1);
I am not able to receive a 3D text in my scene?
Getting Error - "THREE.TextGeometry: font parameter is not an instance of THREE.Font."
When I try using
const loader = new FontLoader();
this.textGeo = new TextGeometry( "Hello", {
font: font,
size: 70,
height: 20,
curveSegments: 4,
bevelThickness: 2,
bevelSize: 1.5,
bevelEnabled: true
});
I don't get exact place from where I am required to import these FontLoader and TextGeometry classes.
Any help, guidance or reference would be helpful. Thanks
TextGeometry and FontLoader have been moved out of the core some time ago so you have to import them from three/examples/jsm/geometries/TextGeometry.js and three/examples/jsm/loaders/FontLoader.js.
Next, the following line of code does not work since loadFont() actually works asynchronous:
let font = this.loadFont();
loadFont() will always return undefined since you return the font in the onLoad() callback function of FontLoader.load(). You have to rewrite your listing to account for the asynchronous nature of the code flow.
I am creating a TextGeometry but not able to convert in Points like a sphere or like a detailed 3d object.
In the below image I have created a sphere using
var dotGeometry = new THREE.SphereBufferGeometry(2, 100, 100);
var dotMaterial = new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
var dot = new THREE.Points(dotGeometry, dotMaterial);//new THREE.MeshBasicMaterial()
scene.add(dot);
and the for text I use
const fontloader = new THREE.FontLoader();
fontloader.load('./models/font.json', function (font) {
const textgeometry = new THREE.TextGeometry('Hello', {
font: font,
size: 1,
height: 0.5,
curveSegments: 12,
bevelEnabled: false,
bevelThickness: 10,
bevelSize: 8,
bevelOffset: 0,
bevelSegments: 5
});
var dotMaterial = new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
let textmesh = new THREE.Points(textgeometry, dotMaterial) //new THREE.MeshBasicMaterial({
// color: 0xffffff,
// wireframe: true
// }));
textmesh.geometry.center();
scene.add(textmesh);
// textmesh.position.set(0, 2, 0)
});
So how to create a geometry having many points for text also, Why I am not able to use MeshBasicMaterial for Points in sphere?
What you see is actually the expected result. TextGeometry produces a geometry intended for meshes. If you use the same data for a point cloud, the result is probably not as expected since you just render each vertex as a point.
When doing this with TextGeometry, you will only see points at the front and back side of the text since points in between are not necessary for a mesh.
Consider to author the geometry in a tool like Blender instead and import it via GLTFLoader.
I've got a button that has addEventListener with a parameter about to be passed. If I console.log(referenced button element) it consoles just fine. As a result I get Vector3 {x: 15, y: 0, z: 0} with no error displayed on console. The problem is that I cannot / not acknowledged yet on how to / update changes dynamically via dom / console in order to set cube X position to be RErendered whenever the button with argument is presented (pressed). My code fragment:
var button = document.getElementById("increment");
button.addEventListener("click", function() { onButtonClick (15)}, false);
function onButtonClick(customX) {
var webGLcontext = document.getElementById("WebGL-output");
webGLcontext = cube.position;
webGLcontext.set(customX, 0, 0);
scene.add(webGLcontext);}
// all the rest stuff of three.js skeleton presented
}
// THREE.Object3D.add: object not an instance of THREE.Object3D. Vector3 {x: 15, y: 0, z: 0}
Any help or reference to an article of this topic would be appreciated.
You can to the things with this option (it's just a concept, not the ultimate solution):
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(0, 8, 13);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var box = new THREE.Mesh(new THREE.BoxBufferGeometry(), new THREE.MeshNormalMaterial());
scene.add(box);
[{
id: 'btnUp',
move: new THREE.Vector3(0, 0, -1)
},
{
id: 'btnRight',
move: new THREE.Vector3(1, 0, 0)
},
{
id: 'btnDown',
move: new THREE.Vector3(0, 0, 1)
},
{
id: 'btnLeft',
move: new THREE.Vector3(-1, 0, 0)
}
].forEach(a => {
let btn = document.getElementById(a.id);
btn.addEventListener("click", event => {
box.position.add(a.move); // move the cube in the desired direction
});
});
renderer.setAnimationLoop(() => { // animation loop
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
#btnButtons {
position: absolute;
}
button {
width: 32px;
height: 32px;
margin: 10px;
}
<script src="https://threejs.org/build/three.min.js"></script>
<div id="btnButtons">
<button id="btnUp">↑</button>
<button id="btnRight">→</button>
<button id="btnDown">↓</button>
<button id="btnLeft">←</button>
</div>
When you move the cube, you'll see how its position change automatically, as the scene will be rendered in the animation loop at certain frame rate.
Apologies for asking this, but I am losing my mind.
In the context of a three.js scene I have built a cube with the following bit of code.
var gcap = new THREE.BoxGeometry( 10, 10, 1, 2, 2, 2 );
mcap = new THREE.MeshBasicMaterial( { color: 0x3182bd, wireframe: false, transparent: true, opacity: 0.5} );
cap = new THREE.Mesh( gcap, mcap );
cap.position.set( - 12, 19, 0 );
gcap.center();
cap.rotation.z = (28 * Math.PI)/180; //convert to radians
app.scene.add(cap);
So why does this tween not work (and by not working I mean there is not noticeable change in the scene):
new TWEEN.Tween(cap.position)
.to(-12, 19, 100 ).start();
but this one does:
new TWEEN.Tween(app.controls.target).to({
x: 31/2,
y: 29/2,
z: 11/2
}).start();
I realize this is probably a super-dumb question, but I'm new to tween (and really three.js in general).
In .to() you have to pass an object of the same structure that you pass in .Tween(), fully or partially. It depends on what values of the object you want to change.
And the second paremeter in .to() is duration.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var box1 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({
color: "red",
wireframe: true
}));
box1.position.set(-3, 0, 0);
scene.add(box1);
var box2 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({
color: "blue",
wireframe: true
}));
box2.position.set(3, 0, 0);
scene.add(box2);
var tween1 = new TWEEN.Tween(box1.position) // here you pass the position {x, y, z}
.to({ // here you pass an object with properties you want to change (now you want to change all of them)
x: 1,
y: 3,
z: -2
}, 2000).delay(500).repeat(Infinity).yoyo(true).start();
var tween2 = new TWEEN.Tween(box2.position) // the same, position {x, y, z}
.to({ // but you want to change only y-coordinate, so you pass an object of {y}
y: 3
}, 1000).delay(500).repeat(Infinity).yoyo(true).start();
render();
function render() {
requestAnimationFrame(render);
TWEEN.update();
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/90/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>
I'm designing a model of a city and want to implement LOD, based on this example: http://threejs.org/examples/#webgl_lod
For testing purposes, I have loaded a subset of my buildings and created a LOD instance for each of them.
The problem is that, they all seem to change state at the same time when I try to zoom in on one of them. I was expecting that the concrete building I was zooming towards would change state, but not those far away.
Here I create the LODs and add them to the scene
var geometries = [
[ new THREE.ExtrudeGeometry(rectShape, {steps: 2, amount: height, bevelEnabled: true, bevelSegments: 1, bevelSize: 0.1, bevelThickness: 0.1 }), 50 ],
[ new THREE.ExtrudeGeometry(rectShape, {steps: 1, amount: height, bevelEnabled: true, bevelSegments: 1, bevelSize: 0.1, bevelThickness: 0.1 }), 300 ],
[ new THREE.ExtrudeGeometry(rectShape, {steps: 0, amount: height, bevelEnabled: true, bevelSegments: 1, bevelSize: 0.1, bevelThickness: 0.1 }), 1000 ]
];
var materials = [
new THREE.MeshLambertMaterial( {color: "rgb(255,0,0)" }),
new THREE.MeshLambertMaterial( {color: "rgb(0,255,0)" }),
new THREE.MeshLambertMaterial( {color: "rgb(0,0,255)" })
];
var lod = new THREE.LOD();
for (var i = 0; i < geometries.length; i ++ ) {
//update
geometries[i][0].computeBoundingBox();
if(geometries[i][0].boundingBox.min.z<0){
zDiff = geometries[i][0].boundingBox.min.z;
}
matrix.makeTranslation(-fCenterX,-fCenterY,-zDiff);
geometries[i][0].applyMatrix(matrix);
geometries[i][0].rotateX(-3.1415*0.5);
//end update
var mesh = new THREE.Mesh( geometries[ i ][ 0 ], materials[i] );
mesh.updateMatrix();
lod.addLevel( mesh, geometries[ i ][ 1 ] );
}
scene.add( lod );
As per the example, in my render():
scene.updateMatrixWorld();
scene.traverse(function(obj){
if(obj instanceof THREE.LOD){
obj.update(camera);
}
});
renderer.render(scene, camera);
rendererStats.update(renderer);
Am I ignorant of something obvious?