ThreeJS Connecting to various coordinates - three.js

Hi I have an external file that contains many xyz coordinate points. In my threeJS file, I use these points as vertices and push to a geometry and create a point cloud. However, the result looks like many points scattering around. Do you how I can connect these points so that they are more connected than they are now? Here is my code.
var dataxyz = xyz;
//xyz is a variable that is an array containing all xyz coordinates.
var particleCount=Object.keys(dataxyz).length;
var coOef =100;
for (var i=0;i<particleCount;i++) {
var coOrd=dataxyz[i];
var vertex = new THREE.Vector3();
vertex.x = coOrd[0] * coOef;
vertex.y = coOrd[2] * coOef-(coOef*2.5);
vertex.z = coOrd[1] * coOef;
}
var Size = 0.1;
this.materials= new THREE.PointCloudMaterial({size: Size});
this.particles = new THREE.PointCloud(this.geometry, this.materials);
this.scene.add(this.particles);

Related

How to create arrays of cube elements to create a chessboard in 3.js

I am trying to make two arrays to create black and white alternating squares in an 8x8 grid to form a chessboard in Three.js. Where do I begin? I can create basic geometries and have, but don't want to, manually create the board using 64 individual components. I also would like each cube to be named after the corresponding position (eg. a1, a2, a3 etc).
Currently I have this:
var boardGeometryArray = [];
var boardMaterialBlackArray = [];
var boardMaterialWhiteArray = [];
var boardBlackArray = [];
var boardWhiteArray = [];
var boardBlack = 4;
for (var br = -0; br<boardBlack; br++){
boardGeometryArray.push ( new THREE.BoxGeometry(5,0,5));
boardMaterialBlackArray.push ( new THREE.MeshPhongMaterial({color : 0x000000}));
boardBlackArray.push ( new THREE.Mesh(boardGeometryArray[br],boardMaterialBlackArray[br]))
boardBlackArray[br].position.z = 5.0;
boardBlackArray[br].position.x = br*10;
scene.add(boardBlackArray[br]);
}
var boardWhite = 4;
for (var bc = 0; bc<boardWhite; bc++){
boardGeometryArray.push ( new THREE.BoxGeometry(5,0,5));
boardMaterialWhiteArray.push ( new THREE.MeshPhongMaterial({color : 0xffffff}));
boardWhiteArray.push ( new THREE.Mesh(boardGeometryArray[bc],boardMaterialWhiteArray[bc]))
boardWhiteArray[bc].position.z = 5;
boardWhiteArray[bc].position.x = (bc*10)+5;
scene.add(boardWhiteArray[bc]);
}
and I'm chipping away at it but a nudge in the right direction will help as it currently creates a row of alternating colours but not an 8x8 board.

How to calculate the area of merged plane in ThreeJS

image
get the area of merged planes
I can get area of each plane, but planes overlapped with each other, I can get a area of them all, but it's not what I want, the overlapped areas should excluded.
var geom = plane.geometry;
var area = 0;
for (var i = 0; i < geom.faces.length; i++) {
var face = geom.faces[i];
var tri = new THREE.Triangle(geom.vertices[face.a], geom.vertices[face.b], geom.vertices[face.c]);
var area = area + tri.getArea();
}
console.log(area);
There should be a method to calculate the area.
THREE.ShapeUtils.area( contour) gives a negative result.
If you want to highlight the edges of your geometry, you can use EdgesHelper:
var helper = new THREE.EdgesHelper( mesh, 0x00ffff );
helper.material.linewidth = 2;
scene.add( helper )
and get contour from Edges helper if required

How fill a loaded STL mesh ( NOT SIMPLE SHAPES LIKE CUBE ETC) with random particles and animate with this geometry bound in three.js

How I can fill a loaded STL mesh ( like suzane NOT SIMPLE SHAPES LIKE CUBE etc) with random particles and animate it inside this geometry bounds with three.js ?
I see many examples but all of it for simple shapes with geometrical bounds like cube or sphere with limit by coordinates around center
https://threejs.org/examples/?q=points#webgl_custom_attributes_points3
TNX
A concept, using a ray, that counts intersections of the ray with faces of a mesh, and if the number is odd, it means that the point is inside of the mesh:
Codepen
function fillWithPoints(geometry, count) {
var ray = new THREE.Ray()
var size = new THREE.Vector3();
geometry.computeBoundingBox();
let bbox = geometry.boundingBox;
let points = [];
var dir = new THREE.Vector3(1, 1, 1).normalize();
for (let i = 0; i < count; i++) {
let p = setRandomVector(bbox.min, bbox.max);
points.push(p);
}
function setRandomVector(min, max){
let v = new THREE.Vector3(
THREE.Math.randFloat(min.x, max.x),
THREE.Math.randFloat(min.y, max.y),
THREE.Math.randFloat(min.z, max.z)
);
if (!isInside(v)){return setRandomVector(min, max);}
return v;
}
function isInside(v){
ray.set(v, dir);
let counter = 0;
let pos = geometry.attributes.position;
let faces = pos.count / 3;
let vA = new THREE.Vector3(), vB = new THREE.Vector3(), vC = new THREE.Vector3();
for(let i = 0; i < faces; i++){
vA.fromBufferAttribute(pos, i * 3 + 0);
vB.fromBufferAttribute(pos, i * 3 + 1);
vC.fromBufferAttribute(pos, i * 3 + 2);
if (ray.intersectTriangle(vA, vB, vC)) counter++;
}
return counter % 2 == 1;
}
return new THREE.BufferGeometry().setFromPoints(points);
}
The concepts from the previous answer is very good, but it has some performance limitations:
the whole geometry is tested with every ray
the recursion on points outside can lead to stack overflow
Moreover, it's incompatible with indexed geometry.
It can be improved by creating a spatial hashmap storing the geometry triangles and limiting the intersection test to only some part of the mesh.
Demonstration

Three.js - How to use the frames option in ExtrudeGeometry

I can't find anywhere an explaination about how to use the frames option for ExtrudeGeometry in Three.js. Its documentation says:
extrudePath — THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)
frames — THREE.TubeGeometry.FrenetFrames. containing arrays of tangents, normals, binormals
but I don't understand how frames must be defined. I think using the "frames" option, passing three arrays for tangents, normals and binormals (calculated in some way), but how to pass them in frames?... Probably (like here for morphNormals):
frames = { tangents: [ new THREE.Vector3(), ... ], normals: [ new THREE.Vector3(), ... ], binormals: [ new THREE.Vector3(), ... ] };
with the three arrays of the same lenght (perhaps corresponding to steps or curveSegments option in ExtrudeGeometry)?
Many thanks for an explanation.
Edit 1:
String.prototype.format = function () {
var str = this;
for (var i = 0; i < arguments.length; i++) {
str = str.replace('{' + i + '}', arguments[i]);
}
return str;
}
var numSegments = 6;
var frames = new THREE.TubeGeometry.FrenetFrames( new THREE.SplineCurve3(spline), numSegments );
var tangents = frames.tangents,
normals = frames.normals,
binormals = frames.binormals;
var tangents_list = [],
normals_list = [],
binormals_list = [];
for ( i = 0; i < numSegments; i++ ) {
var tangent = tangents[ i ];
var normal = normals[ i ];
var binormal = binormals[ i ];
tangents_list.push("({0}, {1}, {2})".format(tangent.x, tangent.y, tangent.z));
normals_list.push("({0}, {1}, {2})".format(normal.x, normal.y, normal.z));
binormals_list.push("({0}, {1}, {2})".format(binormal.x, binormal.y, binormal.z));
}
alert(tangents_list);
alert(normals_list);
alert(binormals_list);
Edit 2
Times ago, I opened this topic for which I used this solution:
var spline = new THREE.SplineCurve3([
new THREE.Vector3(20.343, 19.827, 90.612), // t=0
new THREE.Vector3(22.768, 22.735, 90.716), // t=1/12
new THREE.Vector3(26.472, 23.183, 91.087), // t=2/12
new THREE.Vector3(27.770, 26.724, 91.458), // t=3/12
new THREE.Vector3(31.224, 26.976, 89.861), // t=4/12
new THREE.Vector3(32.317, 30.565, 89.396), // t=5/12
new THREE.Vector3(31.066, 33.784, 90.949), // t=6/12
new THREE.Vector3(30.787, 36.310, 88.136), // t=7/12
new THREE.Vector3(29.354, 39.154, 90.152), // t=8/12
new THREE.Vector3(28.414, 40.213, 93.636), // t=9/12
new THREE.Vector3(26.569, 43.190, 95.082), // t=10/12
new THREE.Vector3(24.237, 44.399, 97.808), // t=11/12
new THREE.Vector3(21.332, 42.137, 96.826) // t=12/12=1
]);
var spline_1 = [], spline_2 = [], t;
for( t = 0; t <= (7/12); t+=0.0001) {
spline_1.push(spline.getPoint(t));
}
for( t = (7/12); t <= 1; t+=0.0001) {
spline_2.push(spline.getPoint(t));
}
But I was thinking the possibility to set the tangent, normal and binormal for the first point (t=0) of spline_2 to be the same of last point (t=1) of spline_1; so I thought if that option, frames, could return in some way useful for the purpose. Could be possible to overwrite the value for a tangent, normal and binormal in the respective list, to obtain the same value for the last point (t=1) of spline_1 and the first point (t=0) of spline_2, so to guide the extrusion? For example, for the tangent at "t=0" of spline_2:
tangents[0].x = 0.301;
tangents[0].y = 0.543;
tangents[0].z = 0.138;
doing the same also for normals[0] and binormals[0], to ensure the same orientation for the last point (t=1) of spline_1 and the first one (t=0) of spline_2
Edit 3
I'm trying to visualize the tangent, normal and binormal for each control point of "mypath" (spline) using ArrowHelper, but, as you can see in the demo (on scene loading, you need zoom out the scene slowly, until you see the ArrowHelpers, to find them. The relative code starts from line 122 to line 152 in the fiddle), the ArrowHelper does not start at origin, but away from it. How to obtain the same result of this reference demo (when you check the "Debug normals" checkbox)?
Edit 4
I plotted two splines that respectively end (blue spline) and start (red spline) at point A (= origin), displaying tangent, normal and binormal vectors at point A for each spline (using cyan color for the blue spline's labels, and yellow color for the red spline's labels).
As mentioned above, to align and make continuous the two splines, I thought to exploit the three vectors (tangent, normal and binormal). Which mathematical operation, in theory, should I use to turn the end face of blue spline in a way that it views the initial face (yellow face) of red spline, so that the respective tangents (D, D'-hidden in the picture), normals (B, B') and binormals (C, C') are aligned? Should I use the ".setFromUnitVectors (vFrom, VTO)" method of quaternion? In its documentation I read: << Sets this quaternion to the rotation required to rotate vFrom direction vector to vector direction VTO ... vFrom VTO and are assumed to be normalized. >> So, probably, I need to define three quaternions:
quaternion for the rotation of the normalized tangent D vector in the direction of the normalized tangent D' vector
quaternion for the rotation of the normalized normal B vector in the direction of the normalized normal B' vector
quaternion for the rotation of the normalized binormal C vector in the direction of the normalized binormal C' vector
with:
vFrom = normalized D, B and C vectors
VTO ​​= normalized D', B' and C' vectors
and apply each of the three quaternions respectively to D, B and C (not normalized)?
Thanks a lot again
Edit 5
I tried this code (looking in the image how to align the vectors) but nothing has changed:
var numSegments_1 = points_1.length; // points_1 = list of points
var frames_1 = new THREE.TubeGeometry.FrenetFrames( points_1_spline, numSegments_1, false ); // path, segments, closed
var tangents_1 = frames_1.tangents,
normals_1 = frames_1.normals,
binormals_1 = frames_1.binormals;
var numSegments_2 = points_2.length;
var frames_2 = new THREE.TubeGeometry.FrenetFrames( points_2_spline, numSegments_2, false );
var tangents_2 = frames_2.tangents,
normals_2 = frames_2.normals,
binormals_2 = frames_2.binormals;
var b1_b2_angle = binormals_1[ binormals_1.length - 1 ].angleTo( binormals_2[ 0 ] ); // angle between binormals_1 (at point A of spline 1) and binormals_2 (at point A of spline 2)
var quaternion_n1_axis = new THREE.Quaternion();
quaternion_n1_axis.setFromAxisAngle( normals_1[ normals_1.length - 1 ], b1_b2_angle ); // quaternion equal to a rotation on normal_1 as axis
var vector_b1 = binormals_1[ binormals_1.length - 1 ];
vector_b1.applyQuaternion( quaternion_n1_axis ); // apply quaternion to binormals_1
var n1_n2_angle = normals_1[ normals_1.length - 1 ].angleTo( normals_2[ 0 ] ); // angle between normals_1 (at point A of spline 1) and normals_2 (at point A of spline 2)
var quaternion_b1_axis = new THREE.Quaternion();
quaternion_b1_axis.setFromAxisAngle( binormals_1[ binormals_1.length - 1 ], -n1_n2_angle ); // quaternion equal to a rotation on binormal_1 as axis
var vector_n1 = normals_1[ normals_1.length - 1 ];
vector_n1.applyQuaternion( quaternion_b1_axis ); // apply quaternion to normals_1
nothing in this other way also:
var numSegments_1 = points_1.length; // points_1 = list of points
var frames_1 = new THREE.TubeGeometry.FrenetFrames( points_1_spline, numSegments_1, false ); // path, segments, closed
var tangents_1 = frames_1.tangents,
normals_1 = frames_1.normals,
binormals_1 = frames_1.binormals;
var numSegments_2 = points_2.length;
var frames_2 = new THREE.TubeGeometry.FrenetFrames( points_2_spline, numSegments_2, false );
var tangents_2 = frames_2.tangents,
normals_2 = frames_2.normals,
binormals_2 = frames_2.binormals;
var quaternion_n1_axis = new THREE.Quaternion();
quaternion_n1_axis.setFromUnitVectors( binormals_1[ binormals_1.length - 1 ].normalize(), binormals_2[ 0 ].normalize() );
var vector_b1 = binormals_1[ binormals_1.length - 1 ];
vector_b1.applyQuaternion( quaternion_n1_axis );
var quaternion_b1_axis = new THREE.Quaternion();
quaternion_b1_axis.setFromUnitVectors( normals_1[ normals_1.length - 1 ].normalize(), normals_2[ 0 ].normalize() );
var vector_n1 = normals_1[ normals_1.length - 1 ];
vector_n1.applyQuaternion( quaternion_b1_axis );

Smart Centering and Scaling after Model Import in three.js

Is there a way to determine the size and position of a model and then auto-center and scale the model so that it is positioned at the origin and within the view of the camera? I find that when I import a Collada model from Sketchup, if the model was not centered at the origin in Sketchup, then it is not centered in three.js. While that makes sense, it would be nice to auto-center to origin after importing.
I've seen some discussion in the different file loaders about getting the bounds of the imported model, but I have been unable to find any references to how to do that.
The scaling issue is less important, but I feel like it relates to a bounds function, which is why I asked it too.
EDIT:
More info after playing around a bit and a few more google searches...
The code for my callback function on loading the collada file now looks like this:
loader.load(mURL, function colladaReady( collada ) {
dae = collada.scene;
skin = collada.skins[ 0 ];
dae.scale.x = dae.scale.y = dae.scale.z = 1;
dae.updateMatrix();
//set arbitrary min and max for comparison
var minX = 100000;
var minY = 100000;
var minZ = 100000;
var maxX = 0;
var maxY = 0;
var maxZ = 0;
var geometries = collada.dae.geometries;
for(var propName in geometries){
if(geometries.hasOwnProperty(propName) && geometries[propName].mesh){
dae.geometry = geometries[propName].mesh.geometry3js;
dae.geometry.computeBoundingBox();
bBox = dae.geometry.boundingBox;
if(bBox.min.x < minX) minX = bBox.min.x;
if(bBox.min.y < minY) minY = bBox.min.x;
if(bBox.min.z < minZ) minZ = bBox.min.z;
if(bBox.max.x > maxX) maxX = bBox.max.x;
if(bBox.max.y > maxY) maxY = bBox.max.x;
if(bBox.max.z > maxZ) maxZ = bBox.max.z;
}
}
//rest of function....
This is generating some interesting data about the model. I can get an overall extreme coordinate for the model, which I'm assuming (probably incorrectly) would be close to an overall bounding box for the model. But trying to do anything with those coordinates (like averaging and moving the model to the averages) generates inconsistent results.
Also, it seems inefficient to have to loop through every geometry for a model, is there a better way? If not, can this logic be applied to other loaders?
You can use THREE.Box3#setFromObject to get the bounding box of any Object3D, including an imported model, without having to loop through the geometries yourself. So you could do something like
var bBox = new THREE.Box3().setFromObject(collada.scene);
to get the extreme bounding box of the model; then you could use any of the techniques in the answers that gaitat linked in order to set the camera position correctly. For instance, you could follow this technique (How to Fit Camera to Object) and do something like:
var height = bBox.size().y;
var dist = height / (2 * Math.tan(camera.fov * Math.PI / 360));
var pos = collada.scene.position;
camera.position.set(pos.x, pos.y, dist * 1.1); // fudge factor so you can see the boundaries
camera.lookAt(pos);
Quick fiddle: http://jsfiddle.net/p19r9re2/ .
try geometry.center()
center: function () {
var offset = new Vector3();
return function center() {
this.computeBoundingBox();
this.boundingBox.getCenter( offset ).negate();
this.translate( offset.x, offset.y, offset.z );
return this;
};
}(),

Resources