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?
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 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?
I have a BufferGeometry triangular prism; where I have specified the 6 vertices and then added indexes to create the 8 faces (2 triangle faces per square plane).
I have then setup 5 groups, so that each side of the prism is a group.
And it works here when I have a single material assigned to the whole object: https://jsfiddle.net/30ez17dw/1/
However I want to be able to assign an array of materials, so that each side (group) has it's own materials. But when I do this the object disappears:
https://jsfiddle.net/30ez17dw/2/
How can I fix my code to make the array of materials work?
You have not specified your groups correctly. Try it like so:
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 5;
camera.position.y = 2;
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
var geometry = new THREE.BufferGeometry();
const y = 0.866025404;
const y2 = 0.5;
const h = 1;
const vertices = new Float32Array([
-y2, 0, 0,
y2, 0, 0,
0, 0, y,
-y2, h, 0,
y2, h, 0,
0, h, y,
]);
const indices = [
0, 1, 2, // Top
5, 4, 3, // Bottom
3, 1, 0, // Back
1, 3, 4, // Back
0, 2, 3, // Left
5, 3, 2, // Left
4, 2, 1, // Right
2, 4, 5, // Right
];
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(indices);
geometry.computeVertexNormals();
geometry.clearGroups();
geometry.addGroup(0, 3, 0);
geometry.addGroup(3, 6, 1);
geometry.addGroup(6, 12, 2);
geometry.addGroup(12, 18, 3);
geometry.addGroup(18, 24, 4);
var material = [
new THREE.MeshBasicMaterial({
color: 0x00ff00
}),
new THREE.MeshBasicMaterial({
color: 0xff0000
}),
new THREE.MeshBasicMaterial({
color: 0x0000ff,
}),
new THREE.MeshBasicMaterial({
color: 0xffff00
}),
new THREE.MeshBasicMaterial({
color: 0x00ffff
})
];
var mesh = new THREE.Mesh(geometry, material); // , side: THREE.DoubleSide
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.132.0/build/three.min.js"></script>
The indices you pass to addGroup() are meant to be consecutive.
Is there something equivalent to CSS's overflow: hidden in aframe? For example, can I constrain an entire to be within a bounding and have everything that is bigger than the box geometry to be hidden/invisible?
There is clipping planes: https://threejs.org/examples/webgl_clipping.html
https://github.com/mrdoob/three.js/blob/master/examples/webgl_clipping.html
// ***** Clipping planes: *****
var localPlane = new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0.8 );
var globalPlane = new THREE.Plane( new THREE.Vector3( - 1, 0, 0 ), 0.1 );
// Geometry
var material = new THREE.MeshPhongMaterial( {
color: 0x80ee10,
shininess: 100,
side: THREE.DoubleSide,
// ***** Clipping setup (material): *****
clippingPlanes: [ localPlane ],
clipShadows: true
} );
var geometry = new THREE.TorusKnotBufferGeometry( 0.4, 0.08, 95, 20 );
object = new THREE.Mesh( geometry, material );
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>