Three.js shape from random points - javascript

I have a N number of random points (in this case 20), with a X,Y and Z constrains.
How can I create ANY (preferably closed) shape (using Three.js library) , given and starting only from N random points.
There are probably many variants, please share yours.
var program = new Program(reset,step)
program.add('g',false)
function reset() {
scene.clear()
scene.add(new THREE.GridHelper(100,1))
}
function step() {
}
program.startup()
var numpoints = 20;
var dots = []; //If you want to use for other task
for (var i = 0 ; i < numpoints ; 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
var dotGeometry = new THREE.Geometry();
dots.push(dotGeometry);
dotGeometry.vertices.push(new THREE.Vector3( x, y, z));
var dotMaterial = new THREE.PointsMaterial( { size: 3, sizeAttenuation: false, color: 0xFF0000 } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add(dot);
}
Triangulation, Voronoi, I don't care, just show me ANY ideas you have, will help me learn a lot!

You can create a polyhedron which is the convex hull of a set of 3D points by using a pattern like so:
var points = [
new THREE.Vector3( 100, 0, 0 ),
new THREE.Vector3( 0, 100, 0 ),
...
new THREE.Vector3( 0, 0, 100 )
];
var geometry = new THREE.ConvexGeometry( points );
var material = new THREE.MeshPhongMaterial( {
color: 0xff0000,
shading: THREE.FlatShading
} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
You must include the following in your project
<script src="/examples/js/geometries/ConvexGeometry.js"></script>
three.js r.78

Related

Three.js: Changing material of one mesh changes all materials in scene

I'm trying to randomly select a mesh in my scene within THREE JS from an array, selecting what appears to be a Mesh within my scene and editing its properties, seems to affect the entire scene, i.e. it changes the colour of all the meshes, however, I haven't in this example merged any polygons. Any ideas on what I'm doing wrong to select a random one>?
var buildingObjs = [];
for ( var i = 0; i < 20; i ++ ) {
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0.5, 0 ) );
var building = new THREE.Mesh( geometry, material );
var geo = new THREE.EdgesGeometry( building.geometry ); // or WireframeGeometry
var mat = new THREE.LineBasicMaterial( { color: 0xcfcfcf } );
var wireframe = new THREE.LineSegments( geo, mat );
building.add( wireframe );
var value = 1 - Math.random() * Math.random();
var color = new THREE.Color().setRGB( value + Math.random() * 0.1, value, value + Math.random() * 0.1 );
var top = color.clone().multiply( light );
var bottom = color.clone().multiply( shadow );
building.position.x = Math.floor( Math.random() * 200 - 100 ) * 10;
building.position.z = Math.floor( Math.random() * 200 - 100 ) * 10;
building.rotation.y = Math.random();
building.scale.x = building.scale.z = Math.random() * Math.random() * Math.random() * Math.random() * 50 + 10;
building.scale.y = ( Math.random() * Math.random() * Math.random() * building.scale.x ) * 8 + 8;
buildingObjs.push(building);
scene.add(building);
}
function randomBuildingSelector()
{
var randomBuilding = buildingObjs[Math.floor(Math.random()*buildingObjs.length)];
return randomBuilding;
}
function startAniLabels() {
var selectedMesh = undefined;
var tt = setInterval(function(){
selectedMesh = randomBuildingSelector();
console.log(selectedMesh);
selectedMesh.material.color.setHex( 0x333333 );
}, 5000);
}
Below fiddle illustrates:
https://jsfiddle.net/60j5z9w3/
You'll see all buildings change colour, whereas I'm expecting only one to change.
The problem stems from your material variable. You're only using a single material for all buildings, so when you change the color of one, you change the color of all. This is a simplified version of your code for clarity:
// Create 1 material
var material = new THREE.MeshPhongMaterial();
for (var i = 0; i < 2000; i++) {
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
// Use that same material on 2000 meshes
var building = new THREE.Mesh( geometry, material );
}
// This is changing the color of the only material,
// effectively changing the color of all meshes
buildingObjs[500].material.color.setHex( 0x333333 );
You would need to create a new material for each mesh if you're planning on changing them individually.

Change the color of mesh created using face3

I have created a mesh using face 3 and three js. But the desired colour is not reflecting on the mesh. Here is the code used by me.
var geometry = new THREE.Geometry();
var f = 0;
for (var i = 0; i < data.real.length; i++, f += 4) {
var o2 = i == data.real.length - 1 ? 0 : i + 1;
var tl = data.real[i];
var tr = data.real[o2];
var bl = data.zeroAxis[i];
var br = data.zeroAxis[o2];
geometry.vertices.push(tl, tr, br, bl);
geometry.faces.push(new THREE.Face3(f, f + 1, f + 2));
face.materials = [ new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) ];
geometry.faces.push(new THREE.Face3(f, f + 3, f + 2));
}
var material = new THREE.MeshPhongMaterial({
color : new THREE.Color(0x008000),
side : THREE.DoubleSide,
transparent : true,
opacity : 0.5
});
var object = new THREE.Mesh(geometry, material);
object.position.set(0, 0, 0);
this.plot = object;
this.tb.scene.add(object);
this.tb.render();
The following line is not correct:
face.materials = [ new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) ];
If you want to apply a color per face, do it like that:
var faces = geometry.faces;
for ( var i = 0, l = faces.length; i < l; i ++ ) {
var face = faces[ i ];
face.color = new THREE.Color( Math.random() * 0xffffff );
}
Also set the property vertexColors of the corresponding material to THREE.FaceColors. Check out the following live demo so see a complete example: https://jsfiddle.net/f2Lommf5/8539/
If you don't provide the face normals, you need to compute the normals. Look at Face3 docs top example:
//the face normals and vertex normals can be calculated automatically if not supplied above
geometry.computeFaceNormals();
geometry.computeVertexNormals();
Thanks for the reply, I resolved the above problem using the following code.
var normal = new THREE.Vector3(0, 1, 0); // optional
var color = new THREE.Color(color); // optional
var materialIndex = 0; // optional
geometry.faces.push(new THREE.Face3(f, f + 1, f + 2, normal, color,
materialIndex));
geometry.faces.push(new THREE.Face3(f, f + 2, f + 3, normal, color,
materialIndex));
Please suggest the improvement.

Three JS Circle Line Geom Color for Negative Values

I've been testing some ideas on how to get a circle to have a different color for the part of the circle that has positive Z values. I tried one approach, creating two separate line segments and using different materials. It works if the circle has segments that don't jump across Z=0. The problem I'm working on is more complicated as the line segments will jump across the Z=0 boundary so I end up with gaps if I try to do it in two segments. Is there a way to just use one line Geom and then change the color of the part of the line that falls into negative Z values? I'm not sure this is the right approach. Thanks!
Here is what I have so far for a test (using X,Y):
<html>
<head>
<title>Cirle Color</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="three.min.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 500, window.innerWidth/window.innerHeight, 0.1, 100000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var segmentCount = 100,
radius = 10,
geometry = new THREE.Geometry();
geometry2 = new THREE.Geometry();
material = new THREE.LineBasicMaterial({ color: "#5fd119" }); // light green
material2 = new THREE.LineBasicMaterial({ color: "#3d8710" }); // darker green
//PUSH THE ORIGIN VERTICY IN
geometry2.vertices.push(new THREE.Vector3(-10,0,0));
for (var i = 0; i <= segmentCount; i++) {
var theta = (i / segmentCount) * Math.PI * 2;
x = Math.cos(theta) * radius;
y = Math.sin(theta) * radius;
z = 0;
if (y >=0 ){
geometry.vertices.push(new THREE.Vector3(x, y, z));
} else {
geometry2.vertices.push(new THREE.Vector3(x, y, z));
}
}
scene.add(new THREE.Line(geometry, material));
scene.add(new THREE.Line(geometry2, material2));
camera.position.z = 5;
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
Update using the answer below. Works great:
I hope I get you correctly. You can set colours of vertices of a geometry and then use vertexColors parameter of a material.
var radius = 5;
var shape = new THREE.Shape();
shape.moveTo(radius, 0);
shape.absarc(0, 0, radius, 0, 2 * Math.PI, false);
var spacedPoints = shape.createSpacedPointsGeometry(360);
var vertexColors = []; // array for our vertex colours
spacedPoints.vertices.forEach( function( vertex ){ // fill the array
if( vertex.y < 0 )
vertexColors.push( new THREE.Color( 0xff0000 ))
else
vertexColors.push( new THREE.Color( 0x0000ff ));
});
spacedPoints.colors = vertexColors; // assign the array
var orbit = new THREE.Line(spacedPoints, new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors // set this parameter like it shown here
}));
scene.add(orbit);
jsfiddle example

THREE.js - position particles evenly on objects faces rather than verticies

Currently I've managed to create a particleCloud with the particles appearing at each vertex of an object I've imported. However I'm trying to get the particles to firstly position on the flat faces of the object rather than the points between them and secondly evenly distribute particles on those faces.
Basically I'm trying to get my 3d object made out of particles
This is what I have so far:
var loader = new THREE.JSONLoader();
loader.load('./resources/model.json', function (geometry, materials) {
var material = new THREE.MeshFaceMaterial(materials);
var model = new THREE.Mesh(geometry, material);
var particleCount = geometry.vertices.length,
particles = new THREE.Geometry(),
pMaterial = new THREE.PointCloudMaterial({
color: 0xFFFFFF,
size: 1
});
for (var p = 0; p < particleCount; p ++) {
particle = model.geometry.vertices[p];
particles.vertices.push(particle);
}
particleSystem = new THREE.PointCloud(particles, pMaterial);
particleSystem.position.set(0, -100, 0)
particleSystem.scale.set(100,100,100)
scene.add(particleSystem);
});
EDIT - 1
I've attached an image to try describe what i currently have and what i'm trying to achieve. Its using the front on a cube as an example. My object will have more sides to it.
EDIT: The previous answer was outdated.
You can now use MeshSurfaceSampler to generate random samples on the surface of a mesh.
The MeshSurfaceSampler.js file is located in the examples/jsm/math directory.
three.js r.128
You have to set the position of each particle individually to build up your 3d object out of particles. Here's an example that makes a cube:
var particles = 500000;
var geometry = new THREE.BufferGeometry();
var positions = new Float32Array( particles * 3 );
var colors = new Float32Array( particles * 3 );
var color = new THREE.Color();
var n = 1000, n2 = n / 2; // particles spread in the cube
for ( var i = 0; i < positions.length; i += 3 ) {
// positions
var x = Math.random() * n - n2;
var y = Math.random() * n - n2;
var z = Math.random() * n - n2;
positions[ i ] = x;
positions[ i + 1 ] = y;
positions[ i + 2 ] = z;
// colors
var vx = ( x / n ) + 0.5;
var vy = ( y / n ) + 0.5;
var vz = ( z / n ) + 0.5;
color.setRGB( vx, vy, vz );
colors[ i ] = color.r;
colors[ i + 1 ] = color.g;
colors[ i + 2 ] = color.b;
}
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
geometry.computeBoundingSphere();
//
var material = new THREE.PointCloudMaterial( { size: 15, vertexColors: THREE.VertexColors } );
particleSystem = new THREE.PointCloud( geometry, material );
scene.add( particleSystem );
source: this threejs example

Physijs update object mass

I am trying to work with a three.js environment with multiple objects that change mass when they are clicked on. Unfortunately the documentation hasn't been helpful and I haven't been able to find any examples of the best way to do this.
Here is the portion in which I am adding a random number of objects to the scene.
var random = getRandomArbitrary(4, 50);
for (var i = 0; i <= random; i++) {
var geometry = new THREE.IcosahedronGeometry( 5, 0 );
var physijsMaterial = Physijs.createMaterial(
new THREE.MeshLambertMaterial( { color: 0xffffff, emissive: 0x333333, shading: THREE.FlatShading } ),
0, // high friction
0 // medium restitution /bouciness
);
var smallSphere = new Physijs.SphereMesh(
geometry,
physijsMaterial,
0
);
smallSphere.position.y = getRandomArbitrary(-50, 50);
smallSphere.position.z = getRandomArbitrary(-50, 50);
smallSphere.position.x = getRandomArbitrary(-50, 50);
smallSphere.name = "Crystals";
scene.add(smallSphere);
}
Here is the portion in which I am trying to update the mass of an object.
function generateGravity(event)
{
event.preventDefault();
var vector = new THREE.Vector3();
vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
vector.unproject( camera );
raycaster.ray.set( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( scene.children, true );
console.log(intersects);
// intersects.object
length = intersects.length;
for (var x = 0; x < length; x++) {
if (intersects[x].object.name == "Crystals") {
console.log(intersects[x].object.mass);
intersects[x].object._physijs.mass = 50;
// intersects[x].object.remove();
}
}
}
What I'm curious to know is the best approach to updating the mass of an object during an event. Right now this function generateGravity is being called in the "render" method.
I realized this was happening because I placed scene.simulate() after render().

Categories