How to drag and drop Object3D elements with three.js? - javascript

I took this example for drag&drop objects, it works perfect. But now I want to group some elements to drag&drop them together. I replaced the Cubes from the example with some Spheres and grouped them together in an Object3D().
var data = [[0,10],[50,20],[100,7],[150,18],[200,15],[250,3],[300,10],[350,25]];
var group = new THREE.Object3D();
for(var i = 0; i< data.length; i++){
var mesh = new THREE.Mesh( new THREE.SphereGeometry(data[i][1],20,20), sphereMaterial);
mesh.position.y = data[i][0];
mesh.updateMatrix();
group.add(mesh);
}
objects.push(group);
scene.add(group);
But I can't select this group of objects in my scene :( What I'm doing wrong? Isn't it possible to select a group? Or how must it look like?

It's hard to tell without the code, but i think you might be using .intersectObjects(objects), you should try using .intersectObjects(objects, true) instead.
Here is the documentation :
.intersectObjects( objects, recursive )
objects — The objects to check for intersection with the ray.
recursive — If set, it also checks all descendants of the objects. Otherwise it only checks intersecton with the objects.
checks all intersection between the ray and the objects with or without the descendants.
three.js Raycaster

Related

Three.js child ignore parent transformation

Let's say I have a parent and n children objects of the parent in a scene.
Edit: added code for mesh creation (assuming that I have a basic scene and camera set up)
parent group creation:
var geometry = new THREE.PlaneGeometry( 0, 0 );
var surface = new THREE.Group();
surface.geometry = geometry;
Child Mesh:
surface.add(new Sprite());
scene.add(surface);
Is there a way I can ignore the parent's transformation matrix for the children only (but keep its transformation intact as a parent )?
I know that matrixAutoUpdate = false; lets me update the child's transformation matrix manually, but it still applies the parent transformation matrix.
I want to ignore it completely for the children, but still be able to preserve its world transform and extract its rotation, translation, and scaling values.
In sense, there is only one object in the group so the group will behave like a single entity. And you can't associate the geometry with the group so my suggestion will add the plane as mesh and then do whatever you want to.
So updated code shall look like as follows:
var geometry = new THREE.PlaneGeometry( 0, 0 );
var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
var surface = new THREE.Group();
surface.add(plane);
surface.add(new Sprite());
scene.add(surface);
Whatever there is to say about javascript, it's a pleasure to hack with!
You can just overload the #updateMatrix function of the specific child Object3D instance by doing something like this:
myChildObject3D.updateMatrixWorld = function( force ) {
if ( this.matrixAutoUpdate ) this.updateMatrix();
if ( this.matrixWorldNeedsUpdate || force ) {
this.matrixWorld.copy( this.matrix );
this.matrixWorldNeedsUpdate = false;
force = true;
}
}
The original Object3D#updateMatrixWorld will multiply the local matrix and the parent's matrix. It also calls the update function on its children.
Here, I switch it with a function that only copies the local transformation matrix so that it's transformation is independent of its parent.

Rotating looped meshes results unexpectedly

I have a three.js project where I'm adding in 100 meshes, that are divided into 10 scenes:
//add 100 meshes to 10 scenes based on an array containing 100 elements
for (var i = 0; i < data.length; i++) {
mesh = new THREE.Mesh(geometry, material);
//random positions so they don't spawn on same spot
mesh.position.x = THREE.Math.randInt(-500, 500);
mesh.position.z = THREE.Math.randInt(-500, 500);
They're added in by a loop, and all these meshes are assigned to 10 scenes:
// Assign 10 meshes per scene.
var sceneIndex = Math.floor(i/10);
scenes[sceneIndex].add(mesh);
I also wrote a functionality where I can rotate a mesh around the center of the scene.
But I don't know how to apply the rotation functionality to all meshes while still keeping them divided into their corresponding scenes. This probably sounds way too vague so I have a fiddle that holds all of the relevant code.
If you comment these two lines back in you'll see that the meshes all move to scenes[0], and they all rotate fine the way I wanted, but I still need them divided in their individual scenes.
spinningRig.add(mesh);
scenes[0].add(spinningRig);
How is the code supposed to look like? Waht is the logic to it?
The logic is fairly simple. The simplest format would be to have a separate spinningRig for each scene -- essentially a grouping of the meshes for each scene.
When you create each scene, you'll also create a spinningRig and add + assign it to that scene:
// Setup 10 scenes
for(var i=0;i<10;i++) {
scenes.push(new THREE.Scene());
// Add the spinningRig to the scene
var spinningRig = new THREE.Object3D();
scenes[i].add(spinningRig);
// Track the spinningRig on the scene, for convenience.
scenes[i].userData.spinningRig = spinningRig;
}
Then instead of adding the meshes directly to the scene, add them to the spinningRig for the scene:
var sceneIndex = Math.floor(i/10);
scenes[sceneIndex].userData.spinningRig.add(mesh);
And finally, rotate the spinningRig assigned to the currentScene:
currentScene.userData.spinningRig.rotation.y -= 0.025;
See jsFiddle: https://jsfiddle.net/712777ee/4/

Babylon.js Mesh Picking & Ignoring Some Meshes

I am currently working on a small project using the new Babylon.js framework. One of the issues I have run into is that I basically have two meshes. One of the meshes is supposed to be the background, and the other is supposed to follow the cursor to mark where on the other mesh you are targeting. The problem is that when I move the targeting mesh to the position of the cursor, it blocks the background mesh when I use scene.pick, resulting in the other mesh having its position set on its self.
Is there any way to ignore the targeting mesh when using scene.pick so that I only pick the background mesh or is there some other method I could use? If not, what would be the steps to implement this sort of feature to essentially raycast only through certain meshes?
If you need code samples or any other forms of description, let me know. Thanks!
Ok, it's easy.
So, we have two meshes. One is called "ground", the second "cursor". If you want to pick only on the ground you have two solutions :
First:
var ground = new BABYLON.Mesh("ground",scene);
ground.isPickable = true ;
var cursor = new BABYLON.Mesh("cursor", scene);
cursor.isPickable = false;
...
var p = scene.pick(event.clientX, event.clientY); // it return only "isPickable" meshes
...
Second:
var ground = new BABYLON.Mesh("ground",scene);
var cursor = new BABYLON.Mesh("cursor", scene);
...
var p = scene.pick(event.clientX, event.clientY, function(mesh) {
return mesh.name == "ground"; // so only ground will be pickable
});
...
regards.

normalizing mesh in three.js

I'm loading a mesh from an obj file, then trying to normalize it. However, I'm getting strange results. Here is the code for loading and centering the mesh:
var manager = new THREE.LoadingManager();
var loader = new THREE.OBJLoader(manager);
loader.load('http://jamesdedge.com/threejs/bunny.obj', function(object) {
object.traverse(function(child) {
if(child instanceof THREE.Mesh)
{
var geometry = child.geometry;
var verts = geometry.vertices;
var ctr = new THREE.Vector3(0.0, 0.0, 0.0);
for(i = 0; i < verts.length; ++i)
ctr.add(verts[i]);
ctr.divideScalar(verts.length);
for(i = 0; i < verts.length; ++i)
verts[i].sub(ctr);
}
});
scene.add(object);
});
This code should just center the mesh on the average of the vertex positions, but it seems to be causing a strange effect. You can see it on my website here: http://jamesdedge.com/threejs/tjs_demo.html
I don't see what is causing this, the ctr variable is giving me a valid vector and subtracting a vector from all the vertices will only reposition it.
Many of the vertices in this model are duplicates (i.e. the same javascript object is contained in the object multiple times), so ctr gets detracted from those vertices multiple times.
One way to address this is issue is to merge the vertices at the start of your traversal function, i.e.
var geometry = child.geometry;
geometry.mergeVertices();
This will also make your code run a bit faster as it has to process a lot less vertices.
You can use GeometryUtils.center() to center your whole mesh conveniently in the middle of the scene at (0,0,0). Anyway, just look at the source code of that function
https://github.com/mrdoob/three.js/blob/master/src/extras/GeometryUtils.js
This should give you a good idea on how to conquer your problem.

Accessing group child for rollover in three.js

So I have a raycaster in three.js that allows me to detect when my group is rolled over. It currently works so that when I mouse over any child of the group, the entire group's material changes.
Here's my question : how can I detect which specific child was rolled over and highlight only that specific child ?
Here's the code :
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(tiles_group.children, true);
if ( intersects.length > 0 ) {
intersectedObject = intersects[0].object;
intersectedObject.material.emissive.setHex( 0xffffff );
intersected = true;
} else {
intersected = false;}
This should be easy but after hours of searching and trying I can't seem to find the proper logic/syntax. Thanks in advance to anyone reading/replying to this post !
SHORT ANSWER : create one material per object instead of one material for all of them
EXPLANATION : As WestLangley pointed out, I just needed to create a separate material for each child object instead of having them all share the same material, ie putting the material creation INSIDE the loop used to generate the objects so that every object gets its own material. This way, material is changed individually for each object.

Categories