Please see attached fiddle. I would like to update the amount of particles with a click event.
So far I have only been able to update the camera settings.
Have gone through the three.js docs on updating things, but would appreciate a push in the right direction.
I was trying something along the lines of:
document.onclick = myClickHandler;
function myClickHandler() {
particle = new THREE.Sprite( material );
particle.position.x = Math.random() * 2 - 1;
particle.position.y = Math.random() * 2 - 1;
particle.position.z = Math.random() * 2 - 1;
particle.position.normalize();
particle.position.multiplyScalar( Math.random() * 10 + 150 );
particle.scale.x = particle.scale.y = 10;
scene.add( particle );
geometry.vertices.push( particle.position );
}
Thanks!
https://jsfiddle.net/007zmukr/8/
I got it working.
Basically by...
Making the geometry and material variables global.
Separating the particle generation into a separate function, addParticle.
calling addParticle within the initial particle generation loop and from within the click handler.
Pretty much what you did above except moving it into it's own function.
https://jsfiddle.net/2pha/007zmukr/26/
Related
I'm very new to three js and is currently trying to implement a feature where the user can zoom in where the cursor is. The plan is to use a raycaster to get the point of intersection and then and use it to update the vector of the orbit controls every time the cursor moves.
the orbit control is initialized like so
this.controls = new OrbitControls( this.camera_, this.threejs_.domElement );
this.controls.listenToKeyEvents( window );
this.controls.screenSpacePanning = false;
this.controls.minDistance = 30;
this.controls.maxDistance = 500;
this.controls.maxPolarAngle = Math.PI / 2;
this is the eventlistener
document.addEventListener('pointermove', (e) => this.onPointerMove(e), false);
and the onPointerMove function looks like this
onPointerMove(event){
const pointer = {
x: (event.clientX / window.innerWidth) * 2 - 1,
y: -(event.clientY / window.innerHeight) * 2 + 1,
}
this.rayCaster.setFromCamera( pointer, this.camera_);
const intersects = this.rayCaster.intersectObjects( this.scene_.children, false);
if ( intersects.length > 0 ) {
this.controls.target(intersects[0].point);
this.controls.update();
}
}
so far, intersects[0].point seems to be getting the intersect coordinate correctly but the orbit control is simply not getting updated. I have also tried changing the camera's position using
this.camera_.position.set(intersects[0].point.x+20,intersects[0].point.y+20,intersects[0].point.z+20);
this.controls.update();
however that just moves my camera everywhere i point.
Edit:
this doesnt work either
const newTarget = new Vector3(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z);
this.controls.target.copy(newTarget);
found the answer here.
Apparently you need to use either copy or set to change the target of the orbit controls. Without calling update().
like so
this.controls.target.set(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z);
I use OrbitControls now but still i have strange bug. It is hard to explain. When i drag mouse down in the begin work normally and then in one moment whole scene begin to rotate in wrong direction and flip my whole scene.
I got warnings :
OrbitControls.js:1103 [Violation] Added non-passive event listener to
a scroll-blocking 'wheel' event. Consider marking event handler as
'passive' to make the page more responsive. See
https://www.chromestatus.com/feature/5745543795965952
Here is my code:
controls = new THREE.OrbitControls(camera, renderer.domElement);
//controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)
controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
controls.dampingFactor = 0.05;
controls.screenSpacePanning = true;
controls.minDistance = 14;
controls.maxDistance = 120;
controls.maxPolarAngle = Math.PI / 3;
controls.target.set(5, 4, -20);
I need to limit rotation , disable 360 rotating scene.
For example i wanna allow max angle of 45.
Try this, i had a familiar issue and applied it to my code and worked
camera.up = new THREE.Vector3( 0, 0, 1 );
Did you take a look at the documentation? It outlines four different properties to limit angles of rotation. These are the defaults:
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
controls.minPolarAngle = 0; // radians
controls.maxPolarAngle = Math.PI; // radians
// How far you can orbit horizontally, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
controls.minAzimuthAngle = - Infinity; // radians
controls.maxAzimuthAngle = Infinity; // radians
Edit:
The above solution is for OrbitControls, which is not what the original question asked. TrackballControls does not offer the ability to limit angles of rotation.
I am using the FlyControl, and I want it to always have the camera upright. If I look down, and then look left, the whole view is tilted however far I looked down. Just setting the euler order somehow doesn't seem to do it, because it's still messed up. I've been trying to research this for quite a bit and I've gotten nowhere.
How do I rotate the camera so it is upright, but still pointed in the right direction?
Main app
camera.up = new THREE.Vector3( 0, 0, 1 );
camera.rotation.order = "ZYX";
FlyControl.js:
this.update = function( delta ) {
var moveMult = delta * this.movementSpeed * this.movementSpeedMultiplier;
var rotMult = delta * this.rollSpeed;
var cur = this.object.rotation;
this.object.translateX( this.moveVector.x * moveMult );
this.object.translateY( this.moveVector.y * moveMult );
this.object.translateZ( this.moveVector.z * moveMult );
//this.tmpQuaternion.set( this.rotationVector.x * rotMult, this.rotationVector.y * rotMult, this.rotationVector.z * rotMult, 1 ).normalize();
//this.object.quaternion.multiply( this.tmpQuaternion );
//this.object.lookAt(this.object.getWorldDirection())
this.object.rotation.set( cur.x + this.rotationVector.x * rotMult, /*cur.y + this.rotationVector.y * rotMult*/ 0, cur.z + this.rotationVector.y * rotMult, cur.order );
console.log(this.rotationVector);
// expose the rotation vector for convenience
//this.object.rotation.setFromQuaternion( this.object.quaternion, this.object.rotation.order );
};
Originally I was using ParticleSystem, but I discovered that Raycaster does not work with it. So I'm now modifying my code to simply use individual Particle objects.
The problem is, I can't seem to set the color of the image I'm mapping to the particles like I was able to with ParticleSystem.
I tried the following:
texture = THREE.ImageUtils.loadTexture("ball.png");
material = new THREE.ParticleBasicMaterial({
size : 10,
color: 0x00C1BF,
map : texture,
transparent : true,
});
// Generate some random points...
for (var i = 0; i < pointCount; i++) {
var particle = new THREE.Particle(material);
particle.position.x = Math.random() * (max - min) + min;
particle.position.y = Math.random() * (max - min) + min;
particle.position.z = Math.random() * (max - min) + min;
particle.scale.x = particle.scale.y = particle.scale.z = 3;
plot.add(particle);
}
But the color of ball.png remains the same. If I comment out the image I'm mapping to the points, the colors are changing. But it's not working with the mapped image. When I was using ParticleSystem, inside the for loop where I generate the points, I was adding this:
colors[i] = new THREE.Color(0xffffff);
colors[i].setHSL((x + 1000 ) / 2000, 1, 0.5);
And then set particleSys.colors = colors; outside the loop. That changed the color of the points, but this doesn't seem to work with Particle.
I hate to keep bugging the community with questions like this, but I really would appreciate any guidance on this. Many thanks, as always! :)
Also, here's a link to ball.png that I'm using: http://threejsdoc.appspot.com/doc/three.js/examples/textures/sprites/ball.png
I have a 3D scene in three.js in which I need to get an array of objects that are within X range of a source object. At the moment, the example I'm using is utilizing raycasting inside of a for loop that iterates an array of "collidable objects" that exist in the scene. I feel like there must be a better way to handle this because this approach is exponentially more complex if every object in the array has to raycast from itself to every other object in the array. This has massive performance impacts as the array of collidable objects grows.
//hold collidable objects
var collidableObjects = [];
var scene = new THREE.Scene();
var cubeGeo = new THREE.CubeGeometry( 10 , 10 , 10 );
var materialA = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var materialB = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cubeA = new THREE.Mesh( cubeGeo , materialA );
collidableObjects.push( cubeA );
scene.add( cubeA );
//Change this variable to a larger number to see the processing time explode
var range = 100;
for( var x = 0 ; x < range ; x += 20 ) {
for( var z = 0; z < range ; z += 20 ) {
if( x === 0 && z === 0 ) continue;
var cube = new THREE.Mesh( cubeGeo , materialB );
scene.add( cube );
cube.position.x = x;
cube.position.z = z;
collidableObjects.push( cube );
var cube = cube.clone();
scene.add( cube );
cube.position.x = x * -1;
cube.position.z = z;
collidableObjects.push( cube );
var cube = cube.clone();
scene.add( cube );
cube.position.x = x;
cube.position.z = z * -1;
collidableObjects.push( cube );
var cube = cube.clone();
scene.add( cube );
cube.position.x = x * -1;
cube.position.z = z * -1;
collidableObjects.push( cube );
}
}
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.y = 200;
camera.lookAt( scene.position );
function render() {
//requestAnimationFrame(render);
renderer.render(scene, camera);
console.log( getObjectsWithinRange( cubeA , 30 ) );
}
function getObjectsWithinRange( source , range ) {
var startTime = new Date().getTime();
var inRange = [];
for( var i = 0; i < collidableObjects.length ; ++i ) {
var ray = new THREE.Raycaster( source.position , collidableObjects[i].position , 0 , range );
if( ( obj = ray.intersectObject( collidableObjects[i] ) ) && obj.length ) {
inRange.push( obj[0] );
}
}
var endTime = new Date().getTime();
console.log( 'Processing Time: ' , endTime - startTime );
return inRange;
}
render();
You can see the JSfiddle of this here.
If you change the indicated variable to a larger number say 200, then you'll see the processing time start to get out of control. I feel like there has to be a simpler way to reduce down the array of doing this so I looked at the documentation for the Raycaster of three.js and I noticed that both the near and far attributes say "This value indicates which objects can be discarded based on the distance." so I presume there's some internal function that is used to refine the results down based on distance before casting all the rays.
I did a little digging on this and came up with a single function inside of Ray.js.
distanceToPoint: function () {
var v1 = new THREE.Vector3();
return function ( point ) {
var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
// point behind the ray
if ( directionDistance < 0 ) {
return this.origin.distanceTo( point );
}
v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
return v1.distanceTo( point );
};
}(),
I guess what I'm looking for is a better way to get all of the objects in the scene that are within X radius of a source object. I don't even need to use the Raycasting because I'm not interested in mesh collision, rather just a list of the objects within X radius of the source object. I don't even need to recurse into the children of those objects because of the way the scene is set up. So I feel like there must be some internal function or something that simply uses the THREE.Vector3 objects and math to refine them by distance. That has to be a lot cheaper math to run than Raycasting in this case. If there's already a function that handles this somewhere in three.js, I don't want to recreate one from scratch. I also realize this may be a very long-winded question for what could very well be a single line answer, but I wanted to make sure I have all the details and whatnot here in case someone else looking to do this searches for it later.
Collision checking is a more general problem and I think you'll have more success if you think about it in a context outside of Three.js. There are a number of methods for managing large numbers of objects that need to check for collision with each other. Here are a few optimizations that might be relevant to you here:
The first optimization is for each object to have a boolean property indicating whether it moved since the last physics update. If both objects you're comparing haven't moved, you don't need to recalculate collision. This is mostly relevant if you have a large number of objects in a steady state (like crates you can push around). There are a number of other optimizations you can build on top of this; for example, often if two objects haven't moved, they won't be colliding, because if they were colliding they would be recoiling (moving apart).
The second optimization is that you usually only need to check collision within a certain distance. For example, if you know that all of your objects are smaller than 100 units, then you can just check whether (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 > 100^2. If the check is true (indicating the distance between the two objects is large) then you don't need to calculate detailed collisions. In fact this is more or less the near/far optimization that Raycaster provides for you, but you are not making use of it in your code, since you are always calling the intersectObject method.
The third optimization is that you are allocating a bunch of new Raycaster and related objects in every physics update. Instead, you can keep a pool of Raycasters (or even a single Raycaster) and just update their properties. This will avoid a lot of garbage collecting.
Finally, the most common generalized approach to dealing with a large number of collideable objects is called spatial partitioning. The idea is basically that you divide your world into a given number of spaces and keep track of which space objects are in. Then, when you need to calculate collision, you only need to check other objects that are in the same space. The most common approach for doing this is to use an Octree (an 8-ary tree). As WestLangley mentioned, Three.js has an Octree implementation starting in r59, along with an example (source). Here is a reasonable introduction to the concept of spatial partitioning using 2D examples.
Outside of these optimizations, if you need to do anything particularly complicated, you may want to consider using an external physics library, which will manage optimizations like these for you. The most popular ones for use with Three.js at the moment are Physijs, Cannon.js, and Ammo.js.