Ray-cast to find the closest geometry

Hello everyone:

I use the ray-cast to find the closest geometry, but I got the result that the speed of ray-cast is too slow for me, it’s about 5~20ms once. Is there any solution to make it faster?

Thank you very much.

What do you need it for?

What are you really trying to do?

Could be a case of:
http://mywiki.wooledge.org/XyProblem

The ray cast gives you all the triangles that are colliding with the ray, which might not be what you’re looking for. Getting the closest geometry is much easier in comparison.

1 Like

Is there any solution in JME to find the closest geometry faster?

If there isn’t a good solution in JME, will JME provide the solution in the future?

Thank you very much!

Depends on your definition of “closest geometry”.

Consider reading the link posted by @pspeed above

There is a lot of triangles in my scene, because it’s too much for the GPU to render so I want to reduce the triangles that rendered by the GPU, and I prepare to only render the geometry that I can see, if I could find the closest geometry quickly, my trouble will be solved, so hope the JME can provide the solution to find the closest geometry quickly.

I’m doing like this:

node.collideWith(ray, results);//It’s too slow for me to find the closest.getGeometry().CollisionResult closest = results.getClosestCollision();closest.getGeometry().setCullHint(Spatial.CullHint.Never);

I put it in a new thread and the fps is high enough but the loading speed is too slow.

Thank you very much!

JME is already doing frustum culling for you. The number of triangles you see in the stats are already the number of triangles on screen.

Man, I’m so glad we asked the question.

1 Like

This was worthy of its own response. You CANNOT access the scene graph from a separate thread. You CAN"T. Don’t do it.

The scene graph is not thread safe at all. Not ever not at all… don’t do it. One thread at a time, that’s it.

1 Like

Ok, I won’t do it again. Because it’s too slow, the idea came in. If it’s fast enough, it’s no need to use another thread.

I need the solution to have a further culling, because only the frustum culling is not enough for me.
@pspeed @Momoko_Fan so do you have a good solution?
Thank you very much!

Organize your scene better.

It’s kind of odd that you run into a problem that almost no one with a proper scene runs into… so look for other solutions. (by odd, I mean not really odd… just likely your scene is bad.)

Edit: and by the way, the frustum culling is going to be WAAAAY more efficient than anything you are trying so I’m not sure how your approach is going to be any better. I think we should probably not offer any more advice until you show us a screen shot with the stats up and describe how your scene is constructed.

There are many techniques besides frustum culling to improve performance - but to know which one would be appropriate we would have to know what kind of scene is being rendered. So yeah, just posting a screenshot will probably go a long way…

@pspeed @Momoko_Fan
Ok, I will show you my screenshot and the relevant source code about my scene’s organization. Please be patient to read the following contents, thank you very much!

That is my screenshot in my scene. I know the objects are too much and I want to have a further culling in the scene to reduce the objects and the triangles because the frustum culling is not enough for me.

I know my scene is very big, I am trying my best to make my app’s performance well, so I want to only render the geometry that I can see, because there is many geometry is no need to be rendered every frame in the frustum, so I want to have a further culling, and I organized my scene in a binary tree, the relevant source code as follows:

//0, I organized the scene just like a binary tree
//1, tmpList has all the geometry.
for (int i=0;i<tmpList.size();i++){
node.attachChild(tmpList.get(i));
}
//2, I organize the scene in the “initNode()” method.
initNode(node,0);

//3, initNode() method is recursive call.
private void initNode(Node node,int layer) {

    if(node.getChildren().size()==1){
        return;
    }
    int nodeXYZ;
    if (((BoundingBox)node.getWorldBound()).getXExtent() >= ((BoundingBox)node.getWorldBound()).getYExtent() && ((BoundingBox)node.getWorldBound()).getXExtent() >= ((BoundingBox)node.getWorldBound()).getZExtent()) {
        nodeXYZ = 1;
    } else if (((BoundingBox)node.getWorldBound()).getYExtent() >= ((BoundingBox)node.getWorldBound()).getXExtent() && ((BoundingBox)node.getWorldBound()).getYExtent() >= ((BoundingBox)node.getWorldBound()).getZExtent()) {
        nodeXYZ = 2;
    } else {
        nodeXYZ = 3;
    }

    Node leftNode = new Node();
    Node rightNode = new Node();
    tmpList = node.getChildren();//the tmpList has all the children.
    float f1=0;
    float nodeCenterXYZ = 0;
    if(nodeXYZ==1){
        nodeCenterXYZ = node.getWorldBound().getCenter().getX();
        for (int i = 0; i < tmpList.size(); i++) {
            f1 =((Geometry)(tmpList.get(i))).getMesh().getBound().getCenter().getX()-nodeCenterXYZ;
            if(lengthToNodeCenter>Math.abs(f1)){//lengthToNodeCenter==2.
            }else if(f1>0){
                rightNode.attachChild(tmpList.get(i));
            }else if(f1<0){
                leftNode.attachChild(tmpList.get(i));
            }
        }
    }else if (nodeXYZ==2){
        nodeCenterXYZ = node.getWorldBound().getCenter().getY();
        for (int i = 0; i < tmpList.size(); i++) {
            f1 =((Geometry)(tmpList.get(i))).getMesh().getBound().getCenter().getY()-nodeCenterXYZ;
            if(lengthToNodeCenter>Math.abs(f1)){
            }else if(f1>0){
                rightNode.attachChild(tmpList.get(i));
            }else if(f1<0){
                leftNode.attachChild(tmpList.get(i));
            }
        }
    }else if(nodeXYZ==3) {
        nodeCenterXYZ = node.getWorldBound().getCenter().getZ();
        for (int i = 0; i < tmpList.size(); i++) {
            f1 =((Geometry)(tmpList.get(i))).getMesh().getBound().getCenter().getZ()-nodeCenterXYZ;
            if(lengthToNodeCenter>Math.abs(f1)){
            }else if(f1>0){
                rightNode.attachChild(tmpList.get(i));
            }else if(f1<0){
                leftNode.attachChild(tmpList.get(i));
            }
        }
    }

    if(leftNode.getVertexCount()!=0){
        node.attachChild(leftNode);
        initNode(leftNode,layer+1);
    }
    if(rightNode.getVertexCount()!=0){
        node.attachChild(rightNode);
        initNode(rightNode,layer+1);
    }

}

And to be honest, my scene in unity performs well through only show the geometry that I can see.
Please tell me what are you thinking about? Thank you very much!

Yes, you have 2000 objects in view on a mobile device. Already this is too many. Culling what’s “not in the view” won’t help… because there are 2000 objects in the view.

You are already pretty much only rendering the geometry you can see. The stuff behind you and off to the sides is not being rendered.

A binary tree is not at all an efficient spatial organization.

You need to organize your scene spatially (in a grid maybe) and then batch batch batch batch batch to get the object count down.

Edit: note that 2000 objects in view is bordering on too many objects even for desktop.

5 more cents: I’m not sure where do you generate your objects, and i’m not sure about Blender, but in 3ds max there’s a nice Optimize modifier that allows you to dramatically reduce triangle count of created objects without significant or even at all visible distortions. However, it should be applied after the object is done as geometry but before UVW Map generation. Also, before that certain intersecting objects can be combined to one, then optimize can subtract all inner invisible faces as well.

@pspeed @Momoko_Fan

Yes, the objects is too many, but what I show you is only a part of my biggest scene, and if I don’t render all the objects in the scene is a good idea, so I want to do a further culling in manual control. And you must had noticed that

We use the method to load our biggest scene about close to 3 million triangles, and most of the time the draw call is about 300, and only a few time the draw call is about 500, and the triangles maximum close to 200k.

No, it’s really not enough for me, so I want to do a further culling, but I feel the JME haven’t provide a good solution to get the closest geometry, so maybe I should write it by myself, and it must be a hard work for me. :scream:

Batch can reduce the objects but if I batch too much the OOM will appear. I have tried to use batch and instancing but the performance is not very well, so I want to do a further culling to make the performance well.

And I think use the JME can do it just like the unity. :smile:

Well, I suspect if you rendered your bounding boxes they might be pretty ridiculous. It’s also possible Unity has done something to optimize your scene for you. Maybe you should use Unity.

At any rate, ray casts are probably the worst way I could think of to try to figure out if something is on screen or not. Just a horrible horrible slow absolutely wrong way to do it. The slowest possible way I could think of short of rendering it and querying pixels.

And a binary tree is a pretty horrible data structure too if it isn’t spatially organized. Even less efficient than a straight array, really.

Spatial organization will be the key whatever you do.

But there is something very strange about your scene when the first pic has 2000 objects in it but it only looks like it should be at most 10-20. Maybe Unity is batching on load. I know nothing about Unity.

Yeah, in my test I know I shouldn’t use ray-cast to got the closest geometry in my scene, because it’s truly slow for me.

The first pic and the other two pics are in one scene, and in the third pic you should have seen many small objects and each one is a objects. I had said that the scene is part of my biggest scene, and if I batch all the objects in the scene, it performs well. But if I batch the biggest scene the OOM must be appear. And if use batch when I use ray-cast to get the closest collision and change the color of it I will got the whole batchNode rather than a geometry.

Have you see the source code I posted just now?

I think my scene is spatially organized, isn’t it?

Looks like you are spatially organizing based on the bounding box… which is exactly what frustum culling uses. I’d be very surprised if you get different results.

You need to batch. Batching the whole scene would be super bad. Batch it spatially.

There is no different…

But batch will use a lot of memory, and if my scene is big enough the OOM appear. If I batch it spatially, would the OOM disappear?

If I use batch, could I only change a geometry’s color?(the geometry is in the batchNode)