Jump to content

Dragndrop on a back side orientation mesh


yuccai
 Share

Recommended Posts

Hi,

I would like to pick a mesh and moving it around a room which is a simple cube with backside orientation.

Basically, it consists on 3 functions called on 3 distinct events

  1. onPointerDown : I select the mesh I want to move (main mesh) when I click on the mouse
  2. onPointerMove : I select a different mesh in order to move the main mesh when I drag the mouse
  3. onPointerUp : I deselect the main mesh when I release the click of the mouse

The behavior I want to produce is to dragndrop the main mesh on visible faces only and keeping each face belonging to the same mesh (I don't want to create as many meshes as faces).

For instance, when my camera is above the room, the ceiling is transparent and we can see the floor due to the backside orientation of the room. But on step 2, I can't figure out how to pick the face which corresponds to the floor. I only succeed to pick the ceiling. I tried to build a predicate (pickInfo = scene.pick(x,y,predicate)) based on faces normales but once a mesh has been evicted from the predicate, it is not recalled, even if more than one face which is intersected.

So I would like to know if there is a way to do what I'm expecting to do. When a mesh has succeed the predicate, how the returned pickInfo is built ? The selected face (pickInfo.pickedPoint) is always the nearest from the camera ? Is is possible the return an array of valid meshes with an another array containing its corresponding faces intersected ?

Here is a PG relating my issue : http://www.babylonjs-playground.com/#1V3CAT#185

 

Thanks

  

Link to comment
Share on other sites

Hiya @yuccai, good to see you again.  Sorry it has taken so long to get a reply.

http://www.babylonjs-playground.com/#1DE6PV#1

Above, I am just screwing around.  Got some crappy box-dragging happening... without being blocked by room.  Changed isPicked to pickedMesh... just some assorted testing crap.  For accurate drag'n'drop, it might be wise to start with the Drag'n'Drop Playground Demo and make the ground (which is REQUIRED in that demo)... be invisible.  (place its invisible ground behind/beneath your room).  Dragging mesh in a 3D world... using a 2d pointer... is a challenge.

As far as using picking (or using the new multi-pick)... to pick multiple faces (and possibly store all hit faces in an array)... using a backside box such as room... that might be impossible (so far).  I have never heard of anyone doing it before.  The picked face will always be the one closest to camera (unless the ray is fired from the far side of the room). 

I think most people would make the room... from 6 separate planes.

But I DO see your hope.  If room picking (floor, walls) would ALWAYS ignore the face that is closest to the camera (such as a room ceiling)... then you could get proper and correct face clicking (click upon inside walls and floor, and get the correct pickingInfo.faceID's).  This is a cool challenge.

Once upon a time, I was asked to remove the top... from a BJS box.

http://www.babylonjs-playground.com/#1KH9RY#8

I just used my trusty "indices chainsaw", and hacked some indices.  The top of the box disappeared.  I don't think this method will work for you, but i thought I would show you.

 

Fellow forum users... Yuccai is needing a picker... which IGNORES pickingInfo.faceID that are not rendered.  In other words... if you can see-thru the face, don't allow picking of IT.  Only pick the first RENDERED faceID that the ray hits.  Pick PAST see-thru faces, and only hit the first (and maybe collect ALL...) faces that ARE rendered and can be seen.

What a stalwart challenge!  This might require coding a custom picker (a modification of the default BJS picking system).  This custom picker would test HIT face-normals... checking if the face is see-thru (back-sided).  If it IS a hit on a backfaced face, ignore this pickedPoint/faceID and continue the ray further... until it hits a non-backfaced face.  :)  (what a sentence!)

I will keep thinking and perhaps try a custom picker (scary, I'm not a very good coder).  Hopefully, others will comment and have more wisdom.

Link to comment
Share on other sites

In fact it was not as difficult as I thought, I just added my predicate (which consists in checking the sign of the face normal with the intersecting ray) for each faces intersected. I had to patch the following function of Babylon.js : 

SubMesh.prototype.intersects = function (ray, positions, indices, fastCheck) {
    var intersectInfo = null;
    // LineMesh first as it's also a Mesh...
    if (this._mesh instanceof BABYLON.LinesMesh) {
        var lineMesh = this._mesh;
        // Line test
        for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 2) {
            var p0 = positions[indices[index]];
            var p1 = positions[indices[index + 1]];
            var length = ray.intersectionSegment(p0, p1, lineMesh.intersectionThreshold);
            if (length < 0) {
                continue;
            }
            if (fastCheck || !intersectInfo || length < intersectInfo.distance) {
                intersectInfo = new BABYLON.IntersectionInfo(null, null, length);
                if (fastCheck) {
                    break;
                }
            }
        }
    }
    else {
        // Triangles test
        for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
            var p0 = positions[indices[index]];
            var p1 = positions[indices[index + 1]];
            var p2 = positions[indices[index + 2]];
            var p0p1 = p0.subtract(p1);
            var p2p1 = p2.subtract(p1);
            var normal = BABYLON.Vector3.Cross(p0p1, p2p1);
            if(BABYLON.Vector3.Dot(ray.direction, normal) < 0 ) {
                var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
                if (currentIntersectInfo) {
                    if (currentIntersectInfo.distance < 0) {
                        continue;
                    }
                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
                        intersectInfo = currentIntersectInfo;
                        intersectInfo.faceId = index / 3;
                        if (fastCheck) {
                            break;
                        }
                    }
                }
            }
        }
    }
    return intersectInfo;
};
 

The changes are effected on triangles test side. From the 3 vertices of the face, I calculate the normal and then I check the dot sign of this normal with the ray direction. If it is positive (the ray and the face are oriented in the same way), it means that the face is back to camera, thus invisible in a back face culling mesh. So I keep only negative dot product.   

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...