Hello all. I´m quite new to Three.js in particular and 3D rendering in general. I´m trying to solve the following problem:
I need to represent a volume from a set of points determined by polar coordinates (phi and theta) a magnitude.
The final result it should be something similar to a bumped sphere
So far I´ve been able to render the mesh using THREE.ConvexGeometry providing the coordinates and radius = 1
but when I try to represent the mesh applying the magnitude the resulting volume makes no sense at all.
Could you guide me here please?
var points = [];
var data = newRaw.Positions;
var weight = newRaw.Power;
var normalizationFactor = 20;
for (var i = 0; i < data.length / 3; i++) {
var x = data[3 * i];
var y = data[3 * i + 1];
var z = data[3 * i + 2];
var radius = weight[i];
var point = new THREE.Vector3(
x * normalizationFactor * radius,
y * normalizationFactor * radius,
z * normalizationFactor * radius,
);
points.push(point);
}
const geometry = new THREE.ConvexGeometry(points);
geometry.computeBoundingSphere();
let meshmaterial = new THREE.MeshBasicMaterial({ color: 0xd3d3d3 });
var mesh = new THREE.Mesh(geometry, meshmaterial);
scene.add(mesh)
const wireframe = new THREE.WireframeGeometry(geometry);
const material = new THREE.LineBasicMaterial({
color: 0xffffff,
linewidth: 1,
linejoin: 'miter'
});
line = new THREE.LineSegments(wireframe, material);
scene.add(line);
ConvexGeometry always computes the convex hull for a set of points and then represents this bounding volume as a geometry. If you say you need a sphere, use Sphere.setFromPoints(). You can then use the radius and center property in order to create a mesh based on SphereGeometry.
Thank you, I´d give it a try, but maybe I did not explain myself correctly.
The points does not have the same radius so the mesh is not sphere. this only happens when the points have the same radius.
I think what you could do is 1 project this in 2d, something like mercator projection, 2 create 2d mesh from that using some https://github.com/r3mi/poly2tri.js/, 3 map it back to 3D and 4 extrude vertices to their original distances
edit: actually, you could do with three.js only,
1 project all the vertices onto 3D sphere of some radius, 2 do the convex hull, 3 extrude vertices to their original distances
but in 3D with polar coordinates. Instead of the plane you have the surface of the unit sphere. The points are projected onto this sphere.
After triangulation the original values of the radius are restored.
In delaunator.js the algorithm is commented quite well. You can try to transfer it.
// pick a seed point close to the center
// find the point closest to the seed
// find the third point which forms the smallest circumcircle with the first two
// swap the order of the seed points for counter-clockwise orientation
Maybe makes sense to set points at the same distance (radius) from center and then try to triangulate just a spherical surface somehow. Then use the index you get from triangulation with the original set of points for a geometry.
“Delaunay triangulation of a set of points on a sphere is the same as convex hull of the point set. I agree that it’s not easily intuitive, but it saves you all this trouble.”
If that´s true then THREE.ConvexGeometry is the triagulation you are mentioning in fact I get this:
I didn’t think three.js already included that. But I also lack the overview to recognize it immediately. So I would have done a lot of work for nothing if I had tried to implement the algorithm.
Once again an efficient solution!
I played around a little.
With THREE.LineSegments you see the sphere very beautiful.
// ****************** + *********************
const lsGeo = new THREE.BufferGeometry( );
const lsPos = new Float32Array( 200 * 3 );
lsGeo.setAttribute( 'position', new THREE.BufferAttribute( lsPos, 3 ) );
for ( i = 0; i < pts.length; i ++ ) {
lsPos[ i * 6 ] = pts[ i ].x;
lsPos[ i * 6 + 1 ] = pts[ i ].y;
lsPos[ i * 6 + 2 ] = pts[ i ].z;
lsPos[ i * 6 + 3 ] = unitPts[ i ].x;
lsPos[ i * 6 + 4 ] = unitPts[ i ].y;
lsPos[ i * 6 + 5 ] = unitPts[ i ].z;
}
const lsMaterial = new THREE.LineBasicMaterial({ color: "white"});
const ls = new THREE.LineSegments( lsGeo, lsMaterial );
scene.add( ls );
// *******************************************
One would still have to display the colors according to the distance from the origin.
@pardogojo
Looking at your last pics of examples, I’ve got a strong impression that it looks like a usual THREE.SphereGeometry() (just rotated around x or z axis at 90 degrees) with defined width and height segmentations.
Maybe we made an overcomplicated solution and somehow it’s possible to use a built-in primitive of sphere for your case
Maybe we just need to change length of vertices’ vectors in a sphere geometry.
Maybe you are right, In fact I was trying that at the time you sent your post.
Would you mind to explain the reason of this code in the HTML part of the jsfiddle?
It’s better to compare vectors with some tolerance, as you can’t get the same exact result with calculation by the reason of precision.
I took it from here:
And used something very similar in this SO answer before: