Three js particle system with mouse interaction - three.js

I try change behaviour particles with this example:
http://threejs.org/examples/#webgl_particles_random
to more like this:
http://minimal.be/lab/fluGL/
Now when I simply change this fragment of code:
for ( i = 0; i < scene.children.length; i ++ ) {
var object = scene.children[ i ];
if ( object instanceof THREE.ParticleSystem ) {
object.rotation.z = time * ( i < 4 ? i + 1 : - ( i + 1 ) );
}
}
Into that:
for ( i = 0; i < scene.children.length; i ++ ) {
var object = scene.children[ i ];
if ( object instanceof THREE.ParticleSystem ) {
object.position.x = mouseX;
object.position.y = -mouseY;
}
}
All particles move globally without change distance and velocity.
The change, which I present is only example. How to modify the code, to avoid global changes in move particles? Do I have to change something in shaders? Or Particle System in three.js is enough to create mouse attractor behaviour?

Related

Mirrored Raycaster on WebGl Globe (sphere)

For my thesis project I'm using the DataArts WebGL Globe for developing a webpage that will be used in an exhibition on a touch monitor. Being the monitor touch, I need to make the globe clickable in order to select the single country and to make a popup open and the selected country highlighted. I'm using RayCaster to find the coordinates of the touch/click, but with my method I obtain mirrored selection (literally, if I click in a point, the click is localized in the opposite size of the globe). The problem seems to be only in the x axis, but I think that I made more errors. The whole code and the whole project is uploaded on http://www.pietroforino.com/globe/, the raycaster code is located in the onMouseDown function at line 660. Here the code
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector3();
[...]
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
data = intersects[i];
var d = data.point.clone().normalize();
var u = Math.round(4096 * (1 - (0.5 + Math.atan2(d.z, d.x) / (2 * Math.PI))));
var v = Math.round(2048 * (0.5 - Math.asin(d.y) / (Math.PI)));
var p = mapContext.getImageData(u,v,1,10).data;
countryCode = p[0];
for( var prop in countryColorMap ) {
if( countryColorMap.hasOwnProperty( prop ) ) {
if( countryColorMap[ prop ] === countryCode )
console.log(prop, countryCode);
}
} // end for loop
lookupContext.clearRect(0,0,256,1);
for (var j = 0; j < 228; j++)
{
if (j == 0)
lookupContext.fillStyle = "rgba(0,0,0,1.0)"
else if (j == countryCode)
lookupContext.fillStyle = "rgba(240,48,104,0.6)"
else
lookupContext.fillStyle = "rgba(0,0,0,1.0)"
lookupContext.fillRect( j, 0, 1, 1 );
}
lookupTexture.needsUpdate = true;
}
I need this implementation, please help me in solving this problem.
EDIT 1.0
Thank you very much for your answer, I've changed the var from i to j, but nothing has changed. I've tried also to delete
for ( var i = 0; i < intersects.length; i++ ) {
that is useless, but again nothing changed. What could be now?
p.s. the new version of the while code is available online
There is a bug in your code. The outer for loop variable i is modified in an inner for loop. In other words the loop variable here:
for ( var i = 0; i < intersects.length; i++ )
is altered by
for (var i = 0; i < 228; i++)
which breaks the first loop. Just replace i with j in the second loop should solve this issue.
BTW: I'm not sure why you iterate over intersects. I guess it should be sufficient to just select the first entry which is the closest intersection to the camera.

three.js: Calculate faceVertexUvs on custom Geometry for texture mapping

I have this example here:
https://jsfiddle.net/NiklasKnaack/L1cqbdr9/82/
function createPlanetFace( radiusX, radiusY, radiusZ, localUp, resolution ) {
const face = {};
face.geometry = new THREE.Geometry();
face.geometry.faceVertexUvs[ 0 ] = [];
face.verticesOriginal = [];
face.verticesNormalized = [];
const axisA = new THREE.Vector3( localUp.y, localUp.z, localUp.x );
const axisB = new THREE.Vector3().crossVectors( localUp, axisA );
for ( let y = 0; y < resolution; y++ ) {
for ( let x = 0; x < resolution; x++ ) {
const index = x + y * resolution;
const percent = new THREE.Vector2( x, y );
percent.x /= ( resolution - 1 );
percent.y /= ( resolution - 1 );
const vertex = new THREE.Vector3();
vertex.x = ( localUp.x + ( percent.x - 0.5 ) * 2 * axisA.x + ( percent.y - 0.5 ) * 2 * axisB.x ) * radiusX;
vertex.y = ( localUp.y + ( percent.x - 0.5 ) * 2 * axisA.y + ( percent.y - 0.5 ) * 2 * axisB.y ) * radiusY;
vertex.z = ( localUp.z + ( percent.x - 0.5 ) * 2 * axisA.z + ( percent.y - 0.5 ) * 2 * axisB.z ) * radiusZ;
face.verticesOriginal[ index ] = new THREE.Vector3( vertex.x, vertex.y, vertex.z );
vertex.normalize();//create a sphere
vertex.x += vertex.x * radiusX / 2;
vertex.y += vertex.y * radiusY / 2;
vertex.z += vertex.z * radiusZ / 2;
face.verticesNormalized[ index ] = new THREE.Vector3( vertex.x, vertex.y, vertex.z );
face.geometry.vertices[ index ] = vertex;
//if ( index % 6 === 0 && index > 0 && x !== resolution - 1 && y !== resolution - 1 ) {
if ( x !== resolution - 1 && y !== resolution - 1 ) {
const triangle1 = new THREE.Face3( index, index + resolution + 1, index + resolution );
const triangle2 = new THREE.Face3( index, index + 1, index + resolution + 1 );
face.geometry.faces.push( triangle1, triangle2 );
}
}
}
//face.geometry.computeBoundingSphere();
//face.geometry.computeVertexNormals();
//face.geometry.computeFaceNormals();
return face;
};
For this I would like to calculate the UVs so that the loaded texture can be displayed correctly.
In principle, the createPlanetFace function creates a plane. From these 6 planes, a cube or sphere is created. (See it in the example)
So far it already works, only the texture is not displayed because the UVs are missing.
After a lot of research and trying, I get either errors in the console, a totally distorted texture, or just no texture at all. That's why I erased my miserable attempts calculating the UVs.
The examples I have found on this topic are all different. At least most of them. I have now reached a point where I can't get any further and need your help.
Thank you in advance.
Here is a box unwrap I wrote a while ago for regular geometries:
function boxUnwrapUVs(geometry) {
for (var i = 0; i < geometry.faces.length; i++) {
var face = geometry.faces[i];
var faceUVs = geometry.faceVertexUvs[0][i]
var va = geometry.vertices[geometry.faces[i].a]
var vb = geometry.vertices[geometry.faces[i].b]
var vc = geometry.vertices[geometry.faces[i].c]
var vab = new THREE.Vector3().copy(vb).sub(va)
var vac = new THREE.Vector3().copy(vc).sub(va)
//now we have 2 vectors to get the cross product of...
var vcross = new THREE.Vector3().copy(vab).cross(vac);
//Find the largest axis of the plane normal...
vcross.set(Math.abs(vcross.x), Math.abs(vcross.y), Math.abs(vcross.z))
var majorAxis = vcross.x > vcross.y ? (vcross.x > vcross.z ? 'x' : vcross.y > vcross.z ? 'y' : vcross.y > vcross.z) : vcross.y > vcross.z ? 'y' : 'z'
//Take the other two axis from the largest axis
var uAxis = majorAxis == 'x' ? 'y' : majorAxis == 'y' ? 'x' : 'x';
var vAxis = majorAxis == 'x' ? 'z' : majorAxis == 'y' ? 'z' : 'y';
faceUVs[0].set(va[uAxis], va[vAxis])
faceUVs[1].set(vb[uAxis], vb[vAxis])
faceUVs[2].set(vc[uAxis], vc[vAxis])
}
geometry.elementsNeedUpdate = geometry.verticesNeedUpdate = true;
}
Is that helpful?
edit: I rewrote your example because it was too complicated for me to understand...
https://jsfiddle.net/manthrax/dL6kxuf2/1/

How to morphTarget of an .obj file (BufferGeometry)

I'm trying to morph the vertices of a loaded .obj file like in this example: https://threejs.org/docs/#api/materials/MeshDepthMaterial - when 'wireframe' and 'morphTargets' are activated in THREE.MeshDepthMaterial.
But I can't reach the desired effect. From the above example the geometry can be morphed via geometry.morphTargets.push( { name: 'target1', vertices: vertices } ); however it seems that morphTargets is not available for my loaded 3D object as it is a BufferGeometry.
Instead I tried to change independently each vertices point from myMesh.child.child.geometry.attributes.position.array[i], it kind of works (the vertices of my mesh are moving) but not as good as the above example.
Here is a Codepen of what I could do.
How can I reach the desired effect on my loaded .obj file?
Adding morph targets to THREE.BufferGeometry is a bit different than THREE.Geometry. Example:
// after loading the mesh:
var morphAttributes = mesh.geometry.morphAttributes;
morphAttributes.position = [];
mesh.material.morphTargets = true;
var position = mesh.geometry.attributes.position.clone();
for ( var j = 0, jl = position.count; j < jl; j ++ ) {
position.setXYZ(
j,
position.getX( j ) * 2 * Math.random(),
position.getY( j ) * 2 * Math.random(),
position.getZ( j ) * 2 * Math.random()
);
}
morphAttributes.position.push(position); // I forgot this earlier.
mesh.updateMorphTargets();
mesh.morphTargetInfluences[ 0 ] = 0;
// later, in your render() loop:
mesh.morphTargetInfluences[ 0 ] += 0.001;
three.js r90

How to explode a 3D model group in ThreeJs?

I have a 3D model , containing many child meshes.
I want to "explode" that mesh ... meaning that every child mesh has to move away from a central point exactly like that thread :
Exploded view algorithm for CAD
To do that , I generate a bounding box of the ancestor mesh , with THREE.Box3 , and compute the center with .getCenter() .
The issue here comes from threeJS's scene graph ...
when setting the position of each child , the whole 3D model does explode when I set it to do so in all directions (XYZ) , but when I choose other combinations like X alone , the explode either bugs and spreads in all directions when it shouldn't, or doesn't explode at all .
Here is the code I am using:
/**
* obj : the current node on the scene graph
* box_ct_world : a vec3 center of the bounding box
*
*/
explode : function(obj , parent , box_ct_world , dif){
var scene = this.el.sceneEl.object3D ; //I am using Aframe , so this is how I retrieve the whole scene .
var object = this.el.object3D ; //same here , this for retrieving the whole 3D model .
var speed = 1 ;
if(obj instanceof THREE.Mesh){
var box_center = box_ct_world ;
var position = obj.position ;
/**
* so this is the beginning of my troubles : I am considering retrieving a world position instead of a local position...
* I have to translate the nodes without the parent matrices interfering .
* The current ligne works the same way as if I retrieved local transformations ... exploding on XYZ , but glitching on the other cases .
*/
position.setFromMatrixPosition(scene.matrixWorld) ;
var addx =0 ;
var addy =0 ;
var addz =0 ;
/**
* This is the vector from the center of the box to the node . we use that to translate every meshes away from the center
*/
if(this.data.X === true){
var addx =(position.x - box_center.x)*this.data.factor *speed ;
}
if(this.data.Y === true){
var addy =(position.y - box_center.y)*this.data.factor *speed;
}
if(this.data.Z === true){
var addz =(position.z - box_center.z)*this.data.factor *speed;
}
var explode_vectorx= addx;
var explode_vectory= addy;
var explode_vectorz= addz;
/**
* this is for making the nodes translate back to their original locations
*/
if(diff < 0 ){
if(explode_vectorx > 0)
explode_vectorx = -explode_vectorx ;
if(explode_vectory > 0)
explode_vectory = -explode_vectory;
if(explode_vectorz > 0)
explode_vectorz = -explode_vectorz;
}
if(diff > 0 ){
if(explode_vectorx < 0)
explode_vectorx = -explode_vectorx ;
if(explode_vectory < 0)
explode_vectory = -explode_vectory;
if(explode_vectorz < 0)
explode_vectorz = -explode_vectorz;
}
var vector = new THREE.Vector3(explode_vectorx , explode_vectory, explode_vectorz) ;
console.log(vector.x+" " + vector.y+ " " + vector.z );
/**
* and here is my biggest problem :
* this function seems to use ancestors matrices
* I need the nodes to move without calling the ancestors matrices , but still keep their original rotation and scale .
*/
obj.position.set(vector.x , vector.y , vector.z ) ;
if(obj.children.length != 0 ){
for(var i = 0 ; i < obj.children.length ; i++){
this.explode(obj.children[i] ,obj, box_ct_world , dif);
}
}
}
else{
if(obj.children.length != 0 )
{
for(var i = 0 ; i < obj.children.length ; i++){
this.explode(obj.children[i] ,obj, box_ct_world , dif);
}
}
}
},
so here is a screenshot using a XYZ explode :
It works pretty fine .
But when using a single axis , like X :
the mesh still goes on all axis as if it was random, when it is supposed to translate only on the X axis .
I think this could be fixed by translating the meshes directly in world space , but I don't know how that can be done in threeJS , especially in that case , because I cannot change the values in matrixWorld (A frame is updating the world matrix every frame I think for these objects , so even if I change any value in the matrixWorld , these will be overriden)
thank you all for your help.

Dynamically change point color in Three.js PointClouod

I'm trying to render a matrix of points in Three.js but I need to treat each particle in the cloud as an individual "pixel" for which I can change the color of each on the fly. I figured out how to basically render the point cloud, and can set the initial color, but cannot figure out how to change the color of each point once it's set.
I'm generating the point cloud like this:
function generateRegularPointcloud( color, width, length ) {
var geometry = new THREE.Geometry();
var numPoints = width * length;
var colors = [];
var k = 0;
for( var i = 0; i < width; i++ ) {
for( var j = 0; j < length; j++ ) {
var u = i / width;
var v = j / length;
var x = u - 0.5;
var y = 0;
var z = v - 0.5;
var v = new THREE.Vector3( x,y,z );
var intensity = ( y + 0.1 ) * 7;
colors[ 3 * k ] = color.r * intensity;
colors[ 3 * k + 1 ] = color.g * intensity;
colors[ 3 * k + 2 ] = color.b * intensity;
geometry.vertices.push( v );
colors[ k ] = ( color.clone().multiplyScalar( intensity ) );
k++;
}
}
geometry.colors = colors;
geometry.computeBoundingBox();
var material = new THREE.PointCloudMaterial( { size: pointSize, vertexColors: THREE.VertexColors } );
var pointcloud = new THREE.PointCloud( geometry, material );
return pointcloud;
}
My basic code is here: http://jsfiddle.net/dg34sbsk/
Any idea how to change each point color separately and dynamically? (Data for the colors will be coming in from a web service).
You can directly change its's value pointclouds[0].geometry.colors=... and after that pointclouds[0].geometry.colorsNeedUpdate=true.
To set each point's color just set the colors's children's value like pointclouds[0].geometry.colors[22]=new THREE.Color("rgb(255,0,0)");.
see this:http://jsfiddle.net/aboutqx/dg34sbsk/2/ .click and you will see the color of one point changes.

Resources