I need to project a 3D point on a given plane - as of right now I am relying on scene.multiPickWithRay - however, I am under the impression that there has to be a better way. Anybody can point me to the right method implementation in Babylon?
getRayHitPointOnPlane(point) {
const length = 10;
let origin = camera.position;
let direction = point.subtract(origin).normalize();
let ray = new BABYLON.Ray(origin, direction, length);
var hits = scene.multiPickWithRay(ray);
let pc = new BABYLON.Vector3(0, 0, 0);
if (hits) {
for (var i = 0; i < hits.length; i++) {
let hit = hits[i];
if (hit.pickedMesh.name == "apf-" + label.name) {
pc = hit.pickedPoint;
}
}
} else {
console.log("No hits");
}
return pc;
}
I donât follow. I am not sure what you mean by âusing bounding info of your planâ - while I see your fastCheck flag and onlyBoundingInfo, I donât really follow how to translate this to the code snippet above.
@Deltakosh: The link you provided for mathematical projection provides an orthogonal projection - we are interested here in mathematically projecting along a given ray - i.e. the mathematical (and faster) way of getting the intersection point between a given ray (line) and plane. I have a simple solution that yields 20x improvements for me. Maybe the supporters on the forum can include it in the framework eventually.
For others that may have this issue:
If you have a mesh plane, make sure you use a source plane when creating it:
// apf position is the position of the plane
// The plane normal is the camera's forward ray normalized and negated
var sourcePlane = BABYLON.Plane.FromPositionAndNormal(apfPosition, camera.getForwardRay().direction.normalize().negate());
var plane = BABYLON.MeshBuilder.CreatePlane("apf-" + label.name, { width: this._width, height: this._height, sourcePlane: sourcePlane}, scene);
/**
* Projects a point to a plane along a ray starting from the camera origin and directed towards the point.
* @param {BABYLON.Vector3} point
* @param {BABYLON.Plane} plane
* @return {BABYLON.Vector3} The projection of the point p on the plane
*/
projectOnPlane(point, plane) {
let n = plane.normal;
let d = plane.d;
// ray origin
let p0 = camera.position;
// ray direction
let V = point.subtract(p0).normalize();
let denom = BABYLON.Vector3.Dot(V, n);
let t = -(BABYLON.Vector3.Dot(p0, n) + d)/denom;
// P = P0 + t*V
return p0.add(V.scale(t));
}
here is what you will have in the new nightly (it will be even faster as I will remove all GC call):
/**
* Projects a point to a plane along a ray starting from a specified origin and directed towards the point.
* @param origin defines the origin of the projection ray
* @param plane defines the plane to project to
* @param result defines the Vector3 where to store the result
*/
public projectOnPlaneToRef(plane: Plane, origin: Vector3, result: Vector3): void {
I think you are correct about the bug fix. I think that âstrutcodeâ was confused about the intention of the method. Whilst this topic make the intention clear the comments in the code do not.
/**
* Projects the current vector3 to a plane along a ray starting from a specified origin and directed towards the point.
* @param plane defines the plane to project to
* @param origin defines the origin of the projection ray
* @param result defines the Vector3 where to store the result
*/
It is not clear what is meant by the point. This would make it clearer.
/**
* Projects the current point Vector3 to a plane along a ray starting from a specified origin and passing through the current point Vector3.
* @param plane defines the plane to project to
* @param origin defines the origin of the projection ray
* @param result defines the Vector3 where to store the result
*/
The original intention was from an observational origin (camera.position) draw a line through the point vector the method is applied to and and see where it hits the plane.
Diagram below when plane passes through world origin.
1158 // ray direction
1159 this.subtractToRef(origin, V);
set the direction of the intersecting line; i.e. vector from origin to vector
In the updated version the vector the method is applied to is taken as a direction vector and forms the line through the origin that hits the plane as in the diagram below.
Looking at these lines it is the vector (this) used for the line direction.
1162 const { x, y, z } = this;
1188 result.set(origin.x + x * hitDistance, origin.y + y * hitDistance, origin.z + z * hitDistance);
I think the original code needs to be re-instated. However there are still somethings to be considered. The function projectOnPlane given in the post is based on the origin being the camera viewing the point vector and plane and hence it is unlikely that the ray is parallel to the plane. The change in BJS to a general origin could mean that the ray might be parallel to the plane or could be pointing away from the plane. I need to investigate further and see what changes need to be made to the original function for it to work with all origins and vector points.
I have amended the original code to take care of the ray being close to parallel to the plane. The original code already took into account the direction the ray was pointing.
Here is a Javascript version of the function.
Now I will see if I can do a PR to re-instate the original code with these ammendments.