Remove object from three js scene by selecting it - javascript

My three js scene contains many OBJ models, some of which are preloaded with the scene, some of which are added to the scene via button click.
A user of my application may add an object but then decide to remove it. I am trying to figure out how to this but need guidance.
Ideally I would do this my holding shift and clicking the object to delete, or by adding the object to a group with shift + select and then deleting with a keyboard press (similar to the grouping here: https://threejs.org/examples/?q=drag#misc_controls_drag).
I would imagine the first way is easier to implement as I had a lot of trouble trying to group the OBJ models this way previously (I think due to their associated MTL files preventing their material being of type Lambert).
Thank you for your support!

If you are able to identify the object by raycasting from the 'Shift-Click' event then you should be able to go up to the object's parent and remove it. The next animate frame will not draw it.
const intersects = raycaster.intersectObjects( objects, true );
if (intersects.length > 0) {
const doomed = intersects[0].object;
doomed.parent.remove(doomed);
}

Related

How to undo the dots on this grid?

Refering to a live javascript playground at https://codepen.io/Maximusssssu/pen/MWrzpav?editors=1011 .When you click on the grid, it will put a triangle or a square depending on your liking using the buttons (triangle & square below the grid). However, I am trying to build an Undo function for both triangle and square. Can anyone offer me some guidance on this? Thank you for reading and have a nice day :) I use the code below to put square or triangle on the grid.
newDot.style.top = y + 'px';
newDot.style.left = x + 'px';
// Add the new element to the end of the body:
document.body.appendChild(newDot);
I would use Memento pattern to implement the undo functionality with the classes listed below.
Basically, the client (main function in my example) invokes const s = Grid.snapshot() method to take a snapshot of the current state of the Grid, and invokes History.push(s) to save the snapshot. When the client needs to undo the change, it retrieves the previous grid state, i.e. snapshot, by invoking const pre = History.pop(), and then feed the previous snapshot to the grid by Grid.restore(pre). The Grid.restore() method can internally invoke Grid.render() method to render the previous state of the grid, i.e. draw the previous set of dots.
Grid Class
Grid holds information about the grid, i.e. all the coordinates of the dots, shapes of the dots, etc.
Snapshot Class
Snapshot captures the state of the grid at some point in the past. Grid is responsible for producing an instance of Snapshot.
History Class
History saves all the previous states of the Grid by storing Snapshot objects. It it essentially a "stack", so it can push or pop a snapshot in a LIFO manner.
main
main function handle all the above objects to realize the required functionalities of the app.
UML Diagram
In order to implement the undo functionality separately for the square and triangle dots, I would tweak this design in such a way that it keeps track of two sets of previous states, one being the triangles and the other being squares. This would result in having two History objects, one recording previous states of square dots and the other recording those of triangle dots, as well as the Grid object producing separate snapshots for squares and triangles.

Hidding objects between specific object and camera in threejs

I am currently using three.js with multiple objects in the scene. I want to be able to select one object and then every object between the camera and the selected object is hidden or removed.
How could this be done?
You select objects using the THREE.RayCaster. The raycaster returns ALL the objects under the cursor, in depth order.. so you can loop through the list of raycast hits and set all but the last one to .visible = false for instance.

Instancing Multiple Objects Lowers Framerate of WEBGL Application

I am developing a THREE.JS WebGL application where I need to render multiple objects with the same geometry and I've stumbled upon a bottleneck. It seems that my instancing of objects has some issue, that I can't really understand/realize, maybe someone can help me with that. For context, I have a PointCloud with normals, that gives me information about where to position my instanced objects, and also the orientation of the object through the normal quaternion. Then, I loop through this array, and place each instanced object accordingly. After looking at various posts about instancing, merging, etc, I can't figure out what I'm doing wrong.
I attach the code snippet of the method in question :
bitbucket.org/snippets/electricganesha/Mdddz
After reviewing it multiple times, I'm really wondering what is wrong here, and why does this particular method slow down my application from 60fps to 20fps.
You might be overcompensating with the optimization.
In your loop where you merge all these geometries try to add something like this
var maxVerts = 1 << 16;
//if merging a new object causes the vert number to go over 2^16 push the merged geometry somewhere, and make a new one for the next batch
if( singleGeometry.vertices.length + newObject.geometry.vertices.length > maxVerts ){
scene.add(singleGeometry);
singleGeometry = new Geometry();
}
singleGeometry.merge(newObject.geometry, newObject.matrix);

Sigma JS node animation

I want to move nodes in Sigma JS on click event. Say from position x 0.7 to position x -0.7.
Is it possible to move nodes in Sigma js, and if it is, kindly guide me to achieve that.
Yes, it is possible. I created a jsfiddle showing how to change node position, size, and color on mouse click here:
http://jsfiddle.net/kaliatech/P255K/
You can bind to custom "downnodes" events like this:
sigInst.bind('downnodes',onNodeDown);
The event callback contains an array of selected node ids. I don't know when it would be more than one when clicking. Perhaps when zoomed out in a complex graph.
One of the more subtle issues when using sigmajs, is that most methods, such as getNodes, return clones, not the instances themselves. This is to protect "private" data in the graph I think, especially data that can not be redrawn after initialization. To actually modify properties, you need to use the iterator methods. Even then, you are only given clones. The library updates the actual node instances using a list of predefined allowable properties. (See the checkNode function in graph.js).
After properties have been set, you then need to refresh/redraw the graph. While the "refresh" method would seem to be an obvious candidate, it did not work. I was able to get it to redraw using the draw method though. You will need to review the source code to understand the different parameters. Example:
function onNodeDown(evt) {
var sigmajs = evt.target;
var nodeId = evt.content[0];
sigmajs.iterNodes(function(n){
n.size = 10;
n.color = "#0000FF";
},[nodeId]);
sigmajs.draw(2, 2, 2, true);
};
For more advanced needs, the sigmajs website includes plugin examples showing other ways of getting mouse events and updating nodes dynamically. One is the advanced plugin example for a fisheye effect:
http://sigmajs.org/examples/a_plugin_example_advanced.html
Another is the example for accessing node attributes:
http://sigmajs.org/examples/more_node_info.html
The sigmajs documentation is weak, so you will need to review the source code to understand things.
There are plugins permitting to move isolated nodes from the graph.
Check
https://github.com/Linkurious/linkurious.js/blob/develop/examples/lasso.html

How to remove children from Layer without removing events associated to them - KineticJS

This question is related with one I asked before here. I'm currently using KineticJS 4.0.5 and I'm using multiple layers to display some shapes with different properties. Since I need to change the layers contents frequently I'm using removeChildren to remove a layer content, but it seems that removeChildren also removes the events associated to childrens. I would like to remove the layer childrens without removing their events because I may have to add them to the layer again.
I tried to set the layer.childrens attribute equal to an empty Array instead of using the removeChildren function. At first it seemed to work but on some cases, some weird things happen :/ Some shapes disappear and the only way to get them back is by setting their Z index. I think the main problem with this approach is related with some properties that must be reseted when contents are removed from the layer, but I don't know which are they.
I also tried to set the events again on each shape before drawing them but it doesn't work... They remain static on the screen... I event tried to use the setDraggable(true) on all shapes before drawing them but no luck... Do I need to create the objects again and apply the events to them again each time I want to redraw a layer with shapes I used before? Or would it be a good approach to store layers for each screen on my application? (I can have a lot of different screens, which would result in a lot of layers and only one would be displayed at a time...)
If you know a solution for this problem please tell me. I really need to solve this problem because it is very important for my project to be able to draw and redraw :/
Thank you!
Sounds to me that what you need is a way to visually remove objects from layers, but not actually delete them. Instead of using remove, try creating a new layer specifically for storage, where your main group within that layer is hidden. You'll want this group, and its layer, to be globals for easy access. Then, when you need to remove an object from view, use moveTo to move it into storage, and moveTo again to restore it to view.
var gObj = {storage : '', storageGroup : ''};
gObj.storage = new Kinetic.Layer();
gObj.storageGroup = new Kinetic.Group({name:'storage', x:0, y:0});
gObj.storage.add(gObj.storageGroup);
// assumes stage is already built
stage.add(gObj.storage);
gObj.storageGroup.hide();
function wareHouse(obj, group, store) {
// obj is an object to store when store === true, otherwise it's a name or id when retreiving, group is the group where object either is or needs to be, store is a boolean value
if (store) {
obj.moveTo(gObj.storageGroup);
} else {
// change the dot to pound ('.' = '#') if using id's
var box = gObj.storageGroup.get('.' + obj)[0];
box.moveTo(group);
}
var parent = group.getLayer();
parent.draw();
}

Categories