Multiple random points Three.js - javascript

I am constructing a point with a random x,y,z (in a certain min and max for x,y,z).
How can I multiply the point (e.g. 20 points), but the have different values (random)for x,y and z also.
//Math.random() * (max - min) + min
var x = Math.random() * (80 - 1) + 1
var y = Math.random() * (80 - 1) + 1
var z = Math.random() * (80 - 1) + 1
var dotGeometry = new THREE.Geometry();
dotGeometry.vertices.push(new THREE.Vector3( x, y, z));
var dotMaterial = new THREE.PointCloudMaterial( { size: 10, sizeAttenuation: false, color: 0xFF0000 } );
var dot = new THREE.PointCloud( dotGeometry, dotMaterial );
scene.add( dot );
I tried something, but the point multiplies at the same position over and over.

If you want to create 20 random points, you only have to do the same into a for loop. I've not used Three.js library, but I suppose that it has be something like this:
var NUM_POINTS = 20;
var dots = []; //If you want to use for other task
for (var i = 0 ; i < NUM_POINTS){
var x = Math.random() * (80 - 1) + 1
var y = Math.random() * (80 - 1) + 1
var z = Math.random() * (80 - 1) + 1
var dotGeometry = new THREE.Geometry();
dots.push(dotGeometry);
dotGeometry.vertices.push(new THREE.Vector3( x, y, z));
var dotMaterial = new THREE.PointCloudMaterial( { size: 10, sizeAttenuation: false, color: 0xFF0000 } );
var dot = new THREE.PointCloud( dotGeometry, dotMaterial );
scene.add(dot);
}
More info about for loop here
Good luck!

Related

How to get LatLng by clicking on rotating sphere (three.js)?

1) create earth object
self.earth = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), new THREE.MeshBasicMaterial({map: tex}));
THREE.ImageUtils.crossOrigin = '';
self.obj = new THREE.Object3D();
self.obj.add(self.earth);
// self.obj.rotation.y = 34.3;
2) intersects
var mouse3D = new THREE.Vector3( );
var raycaster = new THREE.Raycaster();
mouse3D.set( ( (event.clientX) / window.innerWidth ) * 2 - 1, -( (event.clientY) / window.innerHeight ) * 2 + 1, 0.5 ).unproject(self.camera);raycaster.set(self.camera.position, mouse3D.sub(self.camera.position ).normalize());
var intersects = raycaster.intersectObject( self.earth );
if (intersects.length > 0) {
object = intersects[0];
r = 50; // radius
x = object.point.x ;
y = object.point.y ;
z = object.point.z ;
3) coords
var lat = ( 90 - (Math.acos(y / r)) * 180 / Math.PI ) - 10;
var lon = ((270 + (Math.atan2(x , z)) * 180 / Math.PI) % 360) - 10;
Its work, but rotating (self.obj.rotation.y = 34.3;) broke calculating, why?

Planes trimmed by mesh three.js

I have a mesh, which should represent a "building" and I want to add planes every 3 units (different floor levels) and trim them with the mesh faces, so they appear only inside the mesh.
How do I do that? I can't figure it out and the mesh is quite complex for me to define the plane to normally cover only the inside.
var program = new Program(reset, step)
function reset() {
scene.clear()
scene.add(new THREE.GridHelper(100, 1))
}
function step() {
}
program.startup()
// the points group
var spGroup;
// the mesh
var hullMesh;
generatePoints();
render();
function generatePoints() {
// add 10 random spheres
var points = [];
for (var i = 0; i < 50; i++) {
var x = Math.random() * (80 - 1) + 1 //Math.random() * (max - min) + min
var y = Math.random() * (80 - 1) + 1
var z = Math.random() * (80 - 1) + 1
points.push(new THREE.Vector3(x, y, z));
}
spGroup = new THREE.Object3D();
var material = new THREE.MeshBasicMaterial({
color: 0xff0000,
transparent: false
});
points.forEach(function(point) {
var spGeom = new THREE.SphereGeometry(0.5);
var spMesh = new THREE.Mesh(spGeom, material);
spMesh.position.copy(point);
spGroup.add(spMesh);
});
// add the points as a group to the scene
scene.add(spGroup);
// use the same points to create a convexgeometry
var hullGeometry = new THREE.ConvexGeometry(points);
hullMesh = createMesh(hullGeometry);
scene.add(hullMesh);
}
function createMesh(geom) {
// assign two materials
var meshMaterial = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0.2
});
meshMaterial.side = THREE.DoubleSide;
var wireFrameMat = new THREE.MeshBasicMaterial();
wireFrameMat.wireframe = true;
// create a multimaterial
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);
return mesh;
}

How to add faces to THREE.BufferGeometry?

I have created programmatically a simple mesh:
var CreateSimpleMesh = new function () {
var xy = [],
maxX = 7,
maxY = 10,
river = [[0, 5], [0, 4], [1, 3], [2, 2], [3, 2], [4, 1], [5, 1], [6, 0]],
grassGeometry = new THREE.BufferGeometry(),
grassVertexPositions = []
this.init = function () {
for (i = 0; i < maxX; i++) {
for (j = 0; j < maxY; j++) {
xy.push([i, j])
}
}
for (var i = 0; i < xy.length; i++) {
grassVertexPositions.push([xy[i][0], xy[i][1], 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1], 0])
grassVertexPositions.push([xy[i][0], xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0], xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1], 0])
}
for (var i = 0; i < grassVertexPositions.length; i++) {
for (var j = 0; j < river.length; j++) {
if (river[j][0] == grassVertexPositions[i][0] && river[j][1] == grassVertexPositions[i][1]) {
grassVertexPositions[i][2] = -0.5
}
}
}
var grassVertices = new Float32Array(grassVertexPositions.length * 3)
for (var i = 0; i < grassVertexPositions.length; i++) {
grassVertices[i * 3 + 0] = grassVertexPositions[i][0];
grassVertices[i * 3 + 1] = grassVertexPositions[i][1];
grassVertices[i * 3 + 2] = grassVertexPositions[i][2];
}
grassGeometry.addAttribute('position', new THREE.BufferAttribute(grassVertices, 3))
var grassMaterial = new THREE.MeshLambertMaterial({color: 0x00ff00}),
grassMesh = new THREE.Mesh(grassGeometry, grassMaterial)
grassMesh.rotation.x = -Math.PI / 2
Test.getScene().add(grassMesh);
}
}
Problem is that this mesh has only vertices. I have tried to add to it faces like in this question using THREE.Shape.Utils.triangulateShape but BufferGeometry is different than normal geometry and it does not work. Is it possible to add faces to BufferGeometry?
EDIT:
Working fiddle
Here is how to create a mesh having BufferGeometry. This is the simpler "non-indexed" BufferGeometry where vertices are not shared.
// non-indexed buffer geometry
var geometry = new THREE.BufferGeometry();
// number of triangles
var NUM_TRIANGLES = 10;
// attributes
var positions = new Float32Array( NUM_TRIANGLES * 3 * 3 );
var normals = new Float32Array( NUM_TRIANGLES * 3 * 3 );
var colors = new Float32Array( NUM_TRIANGLES * 3 * 3 );
var uvs = new Float32Array( NUM_TRIANGLES * 3 * 2 );
var color = new THREE.Color();
var scale = 15;
var size = 5;
var x, y, z;
for ( var i = 0, l = NUM_TRIANGLES * 3; i < l; i ++ ) {
if ( i % 3 === 0 ) {
x = ( Math.random() - 0.5 ) * scale;
y = ( Math.random() - 0.5 ) * scale;
z = ( Math.random() - 0.5 ) * scale;
} else {
x = x + size * ( Math.random() - 0.5 );
y = y + size * ( Math.random() - 0.5 );
z = z + size * ( Math.random() - 0.5 );
}
var index = 3 * i;
// positions
positions[ index ] = x;
positions[ index + 1 ] = y;
positions[ index + 2 ] = z;
//normals -- we will set normals later
// colors
color.setHSL( i / l, 1.0, 0.5 );
colors[ index ] = color.r;
colors[ index + 1 ] = color.g;
colors[ index + 2 ] = color.b;
// uvs
uvs[ index ] = Math.random(); // just something...
uvs[ index + 1 ] = Math.random();
}
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
// optional
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
// set the normals
geometry.computeVertexNormals(); // computed vertex normals are orthogonal to the face for non-indexed BufferGeometry
See the three.js examples for many additional examples of creating BufferGeometry. Also check out the source code for PlaneGeometry and SphereGeometry, which are reasonably easy to understand.
three.js r.143
You can add faces using three.js internal function- fromBufferGeometry. In your case it would be something like this.
var directGeo = new THREE.Geometry();
directGeo.fromBufferGeometry(grassGeometry);
Then use directGeo to build your mesh, and it will have faces.

What is this particle system position bug?

This particle cloud of sprites should sit to the right of the x-axis and above the y-axis. However, as you can see in this fiddle it mystifyingly hangs just below the y-axis and despite all my editing and rearranging and can't figure out what's going on here. I'd appreciate a fresh pair of eyes to help me out. Thanks!
Here is the basis for my math in the elliptical cloud.
function pointInEllipticalCloud(radiusA, radiusB, pZ) {
var pX = Math.random() * (radiusA * 2);
var rightBisector = Math.abs( radiusA - pX );
var chord = (2 * radiusB) * Math.sqrt(1 - Math.pow((rightBisector / radiusA), 2));
var pY = (Math.random() * chord) + ((radiusB - chord) / 2);
return new THREE.Vector3(pX, pY, pZ);
}
var pZ = 1;
var particleGroup = new THREE.Object3D();
for( var i = 0; i < 300; i++ ) {
var radiusA = 200;
var radiusB = 50;
var particle = new THREE.Sprite( spriteMaterial );
particle.scale.set( 20, 20, 1 );
var spritePoint = pointInEllipticalCloud(radiusA, radiusB, pZ);
// *** Why the resulting form hanging below the y axis?
particle.position = spritePoint ;
particleGroup.add( particle );
pZ += 0.1;
}
particleGroup.position.set(0,0,0);
scene.add( particleGroup );
Ah! Found it. The bug was in part of the calculation for pointInEllipticalCloud(). pY should instead equal this:
var pY = (Math.random() * chord) + (((radiusB * 2) - chord) / 2);
...where radiusB is multiplied by two to make it the vertical diameter of the ellipse.

Creating clickable polygons three.js

I'm using three.js for creating clickable polygons, when i create polygon in this way
var geo = new THREE.Geometry();
geo.vertices.push(new THREE.Vector3(0.3, 0.3, 0.5));
geo.vertices.push(new THREE.Vector3(0.3, 0.4, 0.5));
geo.vertices.push(new THREE.Vector3(0.4, 0.4, 0.5));
geo.vertices.push(new THREE.Vector3(0.6, 0.35, 0.5));
geo.vertices.push(new THREE.Vector3(0.4, 0.3, 0.5));
for (var face = 0 ; face < 5 - 2; face++) {
// this makes a triangle fan, from the first +Y point around
geo.faces.push(new THREE.Face3(0, face + 1, face + 2));
}
var mesh = new THREE.Mesh(geo, new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, opacity: 0.5 }));
geo.computeFaceNormals();
layer.add(mesh);
objects.push(mesh);
it displaying, but the polygon is not clickable.
If I cretae in this way
var geometry = new THREE.CubeGeometry(0.02, 0.02, 0.02);
var object = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, opacity: 0.5 }));
object.position.x = 0.5;
object.position.y = 0.5;
object.position.z = 0.5;
layer.add(object);
objects.push(object);
everything is work fine and cube is clickable, but I need a polygon.
Click Event method
function onDocumentMouseClick(event) {
layerMap.update();
var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
var ray = projector.pickingRay(vector, camera);
var intersects = ray.intersectObjects(objects);
if (intersects.length > 0) {
intersects[0].object.material.color.setHex(Math.random() * 0xffffff);
}
}
I have too much different polygons
How to create clickable polygon?
You have two errors.
Your OrthographicCamera constructor args are incorrect -- it is upside down, and the near plane is behind the camera.
//this.camera = new THREE.OrthographicCamera(0, 1, 0, 1, -3000, 3000);
this.camera = new THREE.OrthographicCamera(0, 1, 1, 0, 1, 3000);
The winding order on your geometry is clockwise; it should be counter-clockwise (CCW).
//geo.faces.push(new THREE.Face3(0, face + 1, face + 2));
geo.faces.push(new THREE.Face3(0, face + 2, face + 1));
Tip: debug with the non-minified version of three.js. Also, download a local copy for your use.
three.js r.60
You have to use the intersectTriangle() function of the THREE.Ray class.
If object is your THREE.Mesh loop over your triangles and check for intersections like this:
function onDocumentMouseClick(event)
{
var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
var ray = projector.pickingRay(vector, camera);
var currentTriangle;
var currentIntersection, chosenIntersection;
var currentDistance, chosenDistance;
var distanceVector;
chosenIntersection = null;
chosenDistance = Infinity;
var vertices = object.geometry.vertices;
for (var i = 0; i < object.geometry.faces.length; i++)
{
currentTriangle = object.geometry.faces[i];
currentIntersection = ray.intersectTriangle( vertices[ currentTriangle.a ], vertices[ currentTriangle.b ], vertices[ currentTriangle.c ], true );
if( currentIntersection !== null )
{
// The following code checks if a found intersection is closer to the camera than a previous one.
distanceVector.subVectors(currentIntersection, ray.origin);
currentDistance = distanceVector.length();
if( currentDistance < chosenDistance)
{
chosenIntersection = currentIntersection;
chosenDistance = currentDistance;
}
}
}
}

Categories

Resources