I'm experimenting with Bjørn Sandvik's really great process for importing terrain data into a scene.
Check it out:
http://blog.thematicmapping.org/2013/10/terrain-building-with-threejs.html
var terrainLoader = new THREE.TerrainLoader();
terrainLoader.load('../assets/jotunheimen.bin', function(data) {
var geometry = new THREE.PlaneGeometry(60, 60, 199, 199);
for (var i = 0, l = geometry.vertices.length; i < l; i++) {
geometry.vertices[i].z = data[i] / 65535 * 10;
}
var material = new THREE.MeshPhongMaterial({
color: 0xdddddd,
wireframe: true
});
var plane = new THREE.Mesh(geometry, material);
scene.add(plane);
});
My intent is to use this to display elevation data from a time series, so multiple .bin files will be loaded to provide data representing a period of several years to show change over time.
I am having difficulties updating the geometry with new data. I think that my difficulties stem from the plane and geometry variables being defined inside of a function, meaning that they are undefined in the global context. So later when I call those variables they don't have any value associated with them.
Does anyone have an idea of how I can update this geometry with new data loaded using the TerrainLoader?
anything you .add() to the scene object is visible as an element of the scene.children array -- to you can still reference your plane and the geometry of it as plane.geometry -- the the plane is the only object in the scene, it will probably be scene.children[0].geometry
See this page: https://github.com/mrdoob/three.js/wiki/Updates for hints on how to let THREE know the geometry is changing
Related
I am attempting to make one 3D model orbit another, but as soon as I change my mesh from a wireframe box to a 3D Model's geometry it disappears.
//this is inside a GLTFLoader.load (glftLoader.load('<model path>', (gltfScene) => {)
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial( {
color: 0xffffff,
wireframe: true
});
let pivot = new THREE.Object3D()
pivot.rotation.z = 0;
gltfScene.scene.add(pivot);
//let mesh = new THREE.Mesh(geometry, material); WORKING LINE
let mesh = new THREE.Mesh(gltfScene.scene.geometry, gltfScene.scene.material);
mesh.position.y = 2;
pivot.add(mesh);
What am I doing wrong? I get no errors, I have a feeling it may be to do with the scale of the 3D model but I'm unsure. Am I getting the geometry and material properties correctly?
let mesh = new THREE.Mesh(gltfScene.scene.geometry, gltfScene.scene.material);
I suppose this line breaks your code since gltfScene.scene (the result of GLTFLoader's onLoad() callback) is an instance of THREE.Group which has no material or geometry property.
A glTF asset can hold more than one mesh so if you really want to extract the geometries and materials from it, you have to traverse through gltfScene.scene and process all meshes.
I have two models loaded in a scene using OBJloader and the Three.JS library. Some of the models are billboarded by use of model.setRotationFromQuaternion( camera.quaternion );
My goal is to draw lines from a vertex on a billboard to a vertex on the corresponding model - it should be drawn between the nearest points on the two models when the scene is first loaded. The models rotate freely so the lines will need to change as it rotates, staying connected to the same initial verticies.
Think of it like the billboard is a label and the line is connected between the label and somewhere on the rotating model.
How can I achieve this?
Below is a snippet of my code - the issue is that the position of all the models is 0,0,0 so I need to know how to get the location of a vertex on both the label and model and connect the two.
addLabelLines(){
var geometry = new THREE.Geometry();
for ( var i = 0; i < this.labels.length; i ++ ) {
var currentLabel = this.labels[i];
var modelMatchingLabel;
//find matching model
for(var j = 0; j < this.models.length; j++){
if(currentLabel.name.toLowerCase().indexOf(this.models[j].name) >= 0){
modelMatchingLabel = this.models[j];
}
}
if(!modelMatchingLabel){
console.warn("no model matching label "+currentLabel.name);
return;
}
else{
console.log('found model '+modelMatchingLabel.name +" matches label "+currentLabel.name);
geometry.vertices.push( currentLabel.position );
geometry.vertices.push( modelMatchingLabel.position );
}
}
var material = new THREE.LineBasicMaterial( { color: 0x800080 } );
line = new THREE.Line( geometry, material, THREE.LineSegments );
scene.add( line );
}
To get the closest point to be able to draw a line requires your typical "nearest neighbor" algorithms. Take a look at this example, as it'll provide you a very efficient way for achieving what you're looking for
https://threejs.org/examples/webgl_nearestneighbour.html
I am creating a line and added to the scene and shows well.
but when I try to create a mesh (using the same coordinates that I formed the line) I get errors that no duplicate points.
"Warning, unable to triangulate polygon!
Duplicate point 653.4789181355854: 204.0166729191409
Either or not infinite solutions!
Its finite solutions.
Either or not infinite solutions!
Too bad, not solutions. "
The strange thing about all this is that the coordinates are more than 4000 points, and I'm sure none of them is repeated. (I even checked in excel, and are only repeated the coordinates of start and end which I understand to be the same) .
what can I do?. no way that from the points of the line can create the mesh without me these errors appear ?. or what other steps should I follow?
for(var x in features.features){
materialLinea[x] = new THREE.LineBasicMaterial( { color: "#FFFFFF"} );
array_extrude[x]=new Array();
material[x] = new THREE.MeshBasicMaterial({
color: "#FF0000"
});
geometria[x] = new THREE.Geometry();
for(var s in features.features[x].geometry.coordinates[0]){
geometria[x].vertices.push(new THREE.Vector3(features.features[x].geometry.coordinates[0][s][0],features.features[x].geometry.coordinates[0][s][1],0))
array_extrude[x].push(new THREE.Vector3(features.features[x].geometry.coordinates[0][s][0],features.features[x].geometry.coordinates[0][s][1],0));
}
line[x] = new THREE.Line( geometria[x], materialLinea[x])
scene.add(line[x])
object3d[x] = new THREE.Shape( array_extrude[x] );
var extrusionSettings = {bevelEnabled: false,amount:10, };
figuraExtrude[x] = new THREE.ExtrudeGeometry( object3d[x], extrusionSettings );
municipios[x] = new THREE.Mesh( figuraExtrude[x], material[x] );
scene.add(municipios[x]);
}
You can merge vertices on your geometries
Geometry.mergeVertices()
I'm using a web-worker to load a .json file of an animated 3D model. For each of the big arrays (vertices, normals, etc.), I'm transferring an Float32Array buffer back to the UI thread. Since such buffers are transferable objects, this will take (almost) zero time.
Now, it turns out that WebGL (and therefore, Three.js) use Float32Array buffers internally, too. This means I could probably load this 3D animation without copying anything, spending almost zero time in the main thread. Isn't that nice?
But it's not clear how to do that part: In the main thread, we have array buffers available for the vertices, normals (the main ones, and the 'morph' ones) and faces. How do I create a working Geometry (or BufferGeometry) from these, without translating or copying the data?
var scene,
vertices, normals, faces,
morphVertices, morphNormals; // <-- we have all these as typed arrays
var geometry = ...; // <-- insert code here
var material = new THREE.MeshLambertMaterial({ morphTargets: true });
var object3D = new THREE.MorphAnimMesh(geometry, material);
scene.add(object3D);
This answer gives a hint, but only point 7 seems relevant, it assumes there is already some Geometry instance, and it doesn't handle morph-targets.
Here's an example based on the mesh loading portion of THREE.GLTF2Loader.
// Create BufferGeometry and assign vertices and normals.
var geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
geometry.setIndex( new THREE.BufferAttribute( faces, 3 ) );
// Create material.
var material = new THREE.MeshStandardMaterial({
morphTargets: true,
morphNormals: true
});
// Set up morph target attributes.
var posAttr = new THREE.BufferAttribute( morphVertices, 3 );
var normAttr = new THREE.BufferAttribute( morphNormals, 3 );
for (var i = 0; i < posAttr.array.length; i++) {
posAttr.array[i] += geometry.attributes.position.array[i];
}
for (var j = 0; j < normAttr.array.length; j++) {
normAttr.array[j] += geometry.attributes.normal.array[j];
}
// Assign morph target attributes.
geometry.morphAttributes.position = [ posAttr ];
geometry.morphAttributes.normal = [ normAttr ];
// Create Mesh.
var mesh = new THREE.Mesh(geometry, material);
mesh.updateMorphTargets();
// Apply 50/50 blend of morph targets and default position/normals.
mesh.morphTargetInfluences[0] = 0.5;
three.js r86-dev.
I have a system of tubes. More precisely, I create a tubes from this code
tube_color - obviously, color of tube,
spline_points - huge number of THREE.Vector3 objects,
segments, radiusSegments are just numbers
var material = new THREE.MeshLambertMaterial( { color: tube_color, shading: THREE.SmoothShading } );
var spline = new THREE.SplineCurve3(spline_points);
var tube = new THREE.TubeGeometry(spline, segments, 10, radiusSegments, false, false);
var tubeMesh = new THREE.Mesh(tube, material);
scene.add(tubeMesh);
This code creates one particular mesh object in space. For each mesh I can have an array of Vector3's by using myMesh.geometry.vertices.
The problem is: I have the point in 3d space. Around this point I create Cube, which does intersect with tubes. For example, this cube can be created like this
var cube = new THREE.CubeGeometry(xSize,ySize,zSize, 5, 5, 5);
var material = new THREE.MeshBasicMaterial({
color: 0xff0000,
opacity: 1,
wireframe: true,
transparent: false
});
var selectionMesh = new THREE.Mesh(cube, material);
scene.add(selectionMesh);
Is it possible at least to find objects(meshes) that have intersection with by cubic area? I know that in scene object I have all meshes, and I can iterate over them, get vertices, iterate over them with a condition if there is at least one its point is in cubic area. But I believe... I hope there is a method/algorithm/magic much more simple then this...
As #WestLangley recommended the solution of this problem was to build octree.
octree=new THREE.Octree({
undeferred:false,
depthMax:Infinity,
objectsThreshold:8,
overlapPct:0.15
} );
and search it
var meshesSearch=octree.search( rayCaster.ray.origin, radiusSphere, true, rayCaster.ray.direction );
However, to have specific intersection we need to provide the recursive flag
raycaster.intersectOctreeObjects( objects, true )
I ended up with more complicated processing of my specific case however this was enough to solve the problem at that moment.