Disable boundingbox calculation for certain grouped object3Ds - three.js

I have several objects grouped in a Object3D. I wanna calculate the boundingbox of the whole group, except some specific objects in that group.
Can you disable the calculation of boundingbox for those objects?

Can you disable the calculation of boundingbox for those objects?
If you are using Box3.setFromObject() then no, this is not possible. The code processes all children of the hierarchy and expands the AABB if an object has a geometry property.
three.js R101

As Mugen mentioned it's not possible to do this out of the box but you can achieve it by manually traversing the tree.
Here's an idea for how you might do that.
var box = null;
group.traverse(c => {
// logic for whether or not to include the child
var includeChild = c.isMesh;
if (includeChild) {
// initialize the box to the first valid child found
// otherwise expand the bounds
if (box === null) {
box = new THREE.Box3();
box.setFromObject(c);
} else {
box.expandByObject(c);
}
}
});
You can change the boolean logic for includeChild to determine whether or not you want an object to be included in the bounds calculations or not.
Hope that helps!

Related

Checking if there is an object in the Scene THREE.JS

is there any way to know if there is an object in the scene? is there any function like isEmpty() or something ?
The THREE.Scene is the root of a scene graph, and if scene.children.length > 1 then it has at least one child / object in that scene. Whether any children are things that can be renderered depends on their type. Lights and Cameras affect the scene but are not rendered themselves. The easiest way to check for objects that could be rendered is to traverse the scene and search for Mesh instances:
let hasMesh = false;
scene.traverse(function (object) {
if (object.isMesh) hasMesh = true;
});
console.log(hasMesh ? 'Found meshes!' : 'No meshes.');
Depending on the use case you may want to check for other types, or to check properties like object.visible if you are showing/hiding objects dynamically.

Legend in deck.gl

I am wondering if it is possible to get access to aggregated data from a deck.gl layer to be able to draw a legend.
Because the colour scheme is supplied I would only require the extent of the aggregated values calculated by the screengrid layer to be able to add this to the legend.
I know there are tooltips, but in some circumstances it would be nice to have access to these values.
I'm using the HexagonLayer and for that one you can find the values for the layers by using a semi custom onSetColorDomain function when initializing your layer. Then save the domain range array to a variable and call a make legend function.
for example:
const hexlayer = new HexagonLayer({
id: 'heatmap',
pickable: true,
colorRange: COLOR_RANGE,
data: feats_obj.coords_array,
elevationScale: 9,
extruded: true,
radius: 300,
getColorValue: points => {
if( points.length > max_points) {
max_points = points.length
}
renderCategories( incident_categories )
return points.length
},
onSetColorDomain: (ecol) => {
console.log('color domain set', ecol)
max_span.innerHTML = ecol[1]
color_domain = ecol;
create_legend()
// console.log('max_points: ', max_points)
},...
})
The hacky way i figured out was to make a max points in a polygon global variable outside initializing the layer and have it update the value anytime there's a polygon with more points in it than that max value. An example of it in the wild is: https://mpmckenna8.github.io/sfviz/?start_date=2020-05-01&end_date=2020-05-31 with a link to the repo u can hack on there.

Selecting an object in threejs?

I think the problem might be because it's a loaded object and not a "created" geometry, but I want to be able to select an object and show that it is selected, like in this example.
I load multiple objects in and I keep track of an index for each object (so the first object loaded has objIndex = 0, etc.) and I know that my code recognizes when I "mouse down" from the console. However, it says that intersects.length = 0 so the rest of the function is skipped.
I'm also not sure what "intersects.length" is actually taking the length of.
So I suppose my questions are:
What is "intersects.length" taking the length of?
Why do my objects have an "intersects.length" of 0?
What are some things I could do so that the objects are recognized?
Here's the relevant code:
function onDocumentMouseDown(event) {
event.preventDefault();
// default action of event will not be triggered
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(camera);
// used to pass 3D positions and directions
var raycaster = new THREE.Raycaster(camera.position,
vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(objects);
console.log('Mouse is down.');
console.log(intersects.length);
if (intersects.length > 0) {
controls.enabled = false;
SELECTED = intersects[0].object;
var intersects = raycaster.intersectObjects(plane);
offset.copy(intersects[0].point).sub(plane.position);
container.style.cursor = 'move';
console.log('Clicked object: ' + object.name);
}
}
If you need to see more, let me know! Thank you. :)
Answering your question:
Here is an interesting read on raycast to help clarify raycasting:
http://soledadpenades.com/articles/three-js-tutorials/object-picking/
So what raycasting basically do is to (really) cast an imaginary ray. When you "mouse down" your program will, so called, cast a straight-line array into the scene. Now to answer your question:
For question one(1) and two(2) : Now when you cast a ray, it may or may not intersect an object. For example if you click into an empty space, the ray will not catch an object. However, as the name suggest, a raycast cast a ray and it may also hits multiple objects along the way. For example if you have one object and another object positioned directly behind the first object, casting a ray into the first object will also intersects the second object. The ray cast will "catch" both objects and put in the two objects into into the array "intersects". Therefore, the command
if (intersects.length > 0)
stated that if the raycast "catches" and object, do these. Moreover, it keeps on calling intersects[0] to refer to the first objects in the intersects array. In this case the most front object that the raycast catches. You can test my answer by creating hundreds of objects and state that, for every member in the intersects array, you change the color to red(for example). You will see that if the raycast catches multiple objects, all the objects will turn into that color. Hope for the first two question!
I am not sure of what you are asking for the third question. Can you clarify further? One way for the object to be recognized is to put them into the scene and put a raycast on the scene. However, I am not too sure of what you are asking to give you answer that I think you want.

ILNumeric continuous rendering plots

Is there a way to continously plot changing array data? I've got a ILLinePlot to graph the line to changing data on a button event, but I would like to make it continuous.
while (true)
{
float[] RefArray = A.GetArrayForWrite();
//RefArray[0] = 100;
Shuffle<float>(ref RefArray);
Console.Write(A.ToString());
scene = new ILScene();
pc = scene.Add(new ILPlotCube());
linePlot = pc.Add(new ILLinePlot(A.T, lineColor: Color.Green));
ilPanel1.Scene = scene;
ilPanel1.Invalidate();
}
The problem I'm running into is that the loop runs, and i can see updates of the array, but the ILPanel does not update. I'm thinking maybe it's because the main loop can't be accessed due to this infinite loop, so I put it in its own thread as well, but it's still not rendering as I hoped...
As Paul pointed out, there is a more efficient attempt to do this:
private void ilPanel1_Load(object sender, EventArgs e) {
using (ILScope.Enter()) {
// create some test data
ILArray<float> A = ILMath.tosingle(ILMath.rand(1, 50));
// add a plot cube and a line plot (with markers)
ilPanel1.Scene.Add(new ILPlotCube(){
new ILLinePlot(A, markerStyle: MarkerStyle.Rectangle)
});
// register update event
ilPanel1.BeginRenderFrame += (o, args) =>
{
// use a scope for automatic memory cleanup
using (ILScope.Enter()) {
// fetch the existint line plot object
var linePlot = ilPanel1.Scene.First<ILLinePlot>();
// fetch the current positions
var posBuffer = linePlot.Line.Positions;
ILArray<float> data = posBuffer.Storage;
// add a random offset
data = data + ILMath.tosingle(ILMath.randn(1, posBuffer.DataCount) * 0.005f);
// update the positions of the line plot
linePlot.Line.Positions.Update(data);
// fit the line plot inside the plot cube limits
ilPanel1.Scene.First<ILPlotCube>().Reset();
// inform the scene to take the update
linePlot.Configure();
}
};
// start the infinite rendering loop
ilPanel1.Clock.Running = true;
}
}
Here, the full update runs inside an anonymous function, registered to BeginRenderFrame.
The scene objects are reused instead of getting recreated in every rendering frame. At the end of the update, the scene needs to know, you are done by calling Configure on the affected node or some node among its parent nodes. This prevents the scene from rendering partial updates.
Use an ILNumerics arteficial scope in order to clean up after every update. This is especially profitable once larger arrays are involved. I added a call to ilPanel1.Scene.First<ILPlotCube>().Reset() in order to rescale the limits of the plot cube to the new data content.
At the end, start the rendering loop by starting the Clock of ILPanel.
The result is a dynamic line plot, updating itself at every rendering frame.
I think you need to call Configure() after any modification of a shape or its buffers. Use the BeginRenderFrame event to do your modifications and you should not add infinitely many shapes / new scenes. It is better to reuse them!
Let me know, if you need an example...

XNA: Identifying identical sprites created with for loop

G'day all,
In short, I'm using a for loop to create a bunch of identical sprites that I want to bounce around the screen. The problem is how do I write a collision detection process for the sprites. I have used the process of placing rectangles around sprites and using the .intersects method for rectangles but in that case I created each sprite separately and could identify each one uniquely. Now I have a bunch of sprites but no apparent way to pick one from another.
In detail, if I create an object called Bouncer.cs and give it the movement instructions in it's update() method then create a bunch of sprites using this in Game.cs:
for (int i = 1; i < 5; ++i)
{
Vector2 position = new Vector2(i * 50, i * 50);
Vector2 direction = new Vector2(i * 10, i * 10);
Vector2 velocity = new Vector2(10);
Components.Add(new Bouncer(this, position, direction, velocity, i));
}
base.Initialize();
I can draw a rectangle around each one using:
foreach (Bouncer component1 in Components)
{
Bouncer thing = (Bouncer)component1;
Rectangle thingRectangle;
thingRectangle = new Rectangle((int)thing.position.X, (int)thing.position.Y, thing.sprite.Width, thing.sprite.Height);
But now, how do I check for a collision? I can hardly use:
if (thingRectangle.Intersects(thingRectangle))
I should point out I'm a teacher by trade and play with coding to keep my brain from turning to mush. Recently I have been working with Python and with Python I could just put all the sprites into a list:
sprites[];
Then I could simply refer to each as sprite[1] or sprite[2] or whatever its index in the list is. Does XNA have something like this?
Please let me know if any more code needs to be posted.
Thanks,
Andrew.
One solution, which I use in my game engine, is to have a Logic code run inside the objects for every game Update, ie. every frame. It seems you already do this, according to the variable names, which indicate you run some physics code in the objects to update their positions.
You might also want to create the collision rectangle inside the Bouncer's constructor so it's more accessible and you make good use of object oriented programming, maybe even make it an accessor, so you can make it update every time you call it instead of manually updating the bounding/collision box. For example:
public Rectangle #BoundingBox {
get { return new Rectangle(_Position.X, _Position.Y, width, height); }
}
Whichever way works, but the collision checks can be run inside the Bouncer object. You can either make the reference list of the Bouncer objects static or pass it to the objects itself. The code for collisions is very simply:
foreach(Bouncer bouncer in Components) //Components can be a static List or you can pass it on in the constructor of the Bouncer object
{
if (bouncer.BoundingBox.Intersects(this.BoundingBox))
{
//they collided
}
}

Resources