I'm trying to raycast to TextGeometry's boundingBox. Currently, raycasting works for textGeometry when click is on the letters not around or inbetween letters. If the click is inbetween the text letters/aphabets, no object is intersected with intersectObjects(). I need the raycast to intersect the textGeo object when click is inbetween the letters as well.
I'm defining TextGeometry as:
var textGeo = new THREE.TextGeometry( text, {
size: size,
height: 1,
font: 'helvetica'
});
textGeo.computeBoundingBox();
var textMaterial = new THREE.MeshBasicMaterial({ color: fontColor });
var textMesh = new THREE.Mesh(textGeo, textMaterial);
After searching for solutions, going with the boundingBox seemed the best approach. Please advice or point to how this can be achieved. Any ideas or tips on how to do this? Or if there is any currently available approach.
How would I make the raycast intersect the bounding box?
I found a solution in the Three.js lib itself. They have an optimization piece in the raycast function for a Mesh that looks at the BoundingBox and BoundingSphere to figure if the ray falls outside to skip checking for intersection. I flipped it around for my case:
var inverseMatrix = new THREE.Matrix4(), ray = new THREE.Ray();
//for example textGeo is the textGeometry
inverseMatrix.getInverse(textGeo.matrixWorld);
ray.copy(raycaster.ray).applyMatrix4(inverseMatrix);
if(textGeo.geometry.boundingBox !== null){
if(ray.isIntersectionBox(textGeo.geometry.boundingBox) === true){
//intersected
}
}
Create the bounding box of your geometry and create geometry for the bbox.
Create a THREE.Object3D and add the bounding as its child (name it obbox)
Add obbox to the scene.
Now if you intersect the scene you will get the obbox object first because it will always be closer to the origin of the ray.
Related
i have a short question:
I know how to calculate the boxes of my (imported) 3dobjects f.e.
var box = new THREE.Box3().setFromObject(obj);
With this i can compute boxes for my objects and i can merge them together if i want.
The problem is, now i have these 2 objects https://imgur.com/gallery/NbPwcmB
The solution seems quite simple: i need to compute the left and right spherebox and put them together, but both of these 2 objects are imported with stlloader. I'm not sure how stlloader exactly works, (it seems for me like its all 1 huge mesh) so i'm not even sure if this is possible.
so my questions:
1. how can i compute a box with the shape of a sphere of my sphere object.
2. Is this even possible for my stl object? (I will try when i get the answer for question 1)
Edit: Question 1 should somehow be working with .computeBoundingSphere..
is there a way to make this visible?
how can i compute a box with the shape of a sphere of my sphere object.
Well, in three.js you have the choice between two bounding volumes. THREE.Box3 represents an axis-aligned bounding box (AABB) whereas THREE.Sphere represents a bounding sphere. If you need a box with the shape of a sphere, use THREE.Sphere.
Is this even possible for my stl object?
The method setFromObject() does only exist for THREE.Box3. However, you can compute the bounding sphere via THREE.BufferGeometry.computeBoundingSphere(). This sphere is defined in local space, however. You can use THREE.Sphere.applyMatrix4() to transform it into world space by passing in the world matrix of the 3D object.
is there a way to make this visible?
There is no helper class for bounding spheres. But you can easily create a helper mesh based on THREE.SphereBufferGeometry. Something like:
const geometry = new THREE.SphereBufferGeometry( boundingSphere.radius );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
const mesh = new THREE.Mesh( geometry, material );
mesh.position.copy( boundingSphere.center );
scene.add( mesh );
three.js R109
I have been creating a simple Three.js application and so far I have a centered text in the scene that shows "Hello World". I have been copying the code examples to try and understand what is happening and so far Ihave it working but I am failing to completely understand why.
My confusion comes from reading all the Three.js tutorials describing that a Geometry object is responsible for creating the shape of the object in the scene. Therefore I did not think it would not make sense to have a position on something that is describing the shape of the mesh.
/* Create the scene Text */
let loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function (font) {
/* Create the geometry */
let geometry_text = new THREE.TextGeometry( "Hello World", {
font: font,
size: 5,
height: 1,
});
/* Create a bounding box in order to calculate the center position of the created text */
geometry_text.computeBoundingBox();
let x_mid = geometry_text.boundingBox.max.x - geometry_text.boundingBox.min.x;
geometry_text.translate(-0.5 * x_mid, 0, 0); // Center the text by offsetting half the width
/* Currently using basic material because I do not have a light, Phong will be black */
let material_text = new THREE.MeshBasicMaterial({
color: new THREE.Color( 0x006699 )
});
let textMesh = new THREE.Mesh(geometry_text, material_text);
textMesh.position.set(0, 0, -20);
//debugger;
scene.add(textMesh);
console.log('added mesh')
} );
Here is the code that I use to add to shape and my confusion comes from the following steps.
/* Create a bounding box in order to calculate the center position of the created text */
geometry_text.computeBoundingBox();
let x_mid = geometry_text.boundingBox.max.x - geometry_text.boundingBox.min.x;
geometry_text.translate(-0.5 * x_mid, 0, 0); // Center the text by offsetting half the width
First, we translate the geometry to the left to center the text inside the scene.
let textMesh = new THREE.Mesh(geometry_text, material_text);
textMesh.position.set(0, 0, -20);
Secondly, we set the position of the mesh.
My confusion comes from the fact that we need both of these operations to occur to move the mesh backwards and become centered.
However I do not understand why these operations should be done of the geometry, infact what confuses me more is that why does textMesh.position.set(0, 0, -20); not override my previously performed translation and simply move the mesh to (0,0,-20). removing my previous translation. It seems that both are required.
AFAIK it is recommended (in scenegraph) to transform (translate, rotate, scale) the whole mesh (with simple) rather than prepare transformed geometry and use it to create "untransformed" mesh, since the mesh in second case is not transform-friendly. Basically "cumulative" transform will be just illegal, giving wrong, unexpected results. Even simple movement.
But sometimes it is useful to create transformed geometry and use it for some algos/computations or in meshes.
You are getting somehow "expected" results in your "combined transform" case because it is just particular case (for example it can work only if object position is (0, 0, 0) etc)
mesh.position.set doesn't modify geometry: it is only a property of mesh and it is used to compute final mesh triangles. This computation involves geometry and object matrix which is composed from object position, object quaternion (3D-rotation) and object scale. Object's geometry can be modified by "matrix" operations but none of such operations are performed dynamically by mesh.
I'm trying to make a linear regression plane visualization tool for a math project. Currently I have the math parts completed, but I am not sure how to graph the plane. I have a equation in the form of z=C+xD+yE, where C, D, and E are known constants. How do I graph the plane using these information? Thanks.
github page: https://saxocellphone.github.io/LAProject/
z=C+xD+yE
This equation gives full information about the plane. What else you need to graph (plot, draw?) it? Probably it depends on your graphic software possibilities.
Canonical form of given equation:
xD + yE - z + C = 0
Normal to the plane is (D, E, -1). Distance to the coordinate origin Abs(C)/Sqrt(D^2+E^2+1).
Plane intersects coordinate axes at values (-C/D), (-C/E), (C)
I see your problem is not with math, but with three,
as WestLangley pointed out in his comment you can play with rotations etc. or create a simple triangle which is the easiest way
since you have your equation for the plane create 3 points to form a triangle
// z=C+xD+yE
// i assume here that the plane is not aligned with any axis
// and does not pass through the origin, otherwise choose the points in another way
var point1 = new THREE.Vector3(-C/D,0,0);//x axis intersection
var point2 = new THREE.Vector3(0,-C/E,0);//y axis intersection
var point3 = new THREE.Vector3(0,0,C);//z axis intersection
now form a new geometry as in How to make a custom triangle in three.js
var geom = new THREE.Geometry();
geom.vertices.push(point1);// adding vertices to geometry
geom.vertices.push(point2);
geom.vertices.push(point3);
// telling geometry that vertices 0,1,2 form a face = triangle
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
create a simple material and add it to a scene
var material = new THREE.MeshBasicMaterial({
color: 0xff0000, // RGB hex color for material
side: THREE.DoubleSide // do not hide object when viewing from back
});
scene.add(new THREE.Mesh(geometry,material));
that should get you going, you can add another triangles, or make it larger with choosing points that are further apart
For each mesh (THREE.Object3D) Three.js provide a very handy properties - boundingSphere and boundingSphere that have intersectsSphere and isIntersectionBox methods.
With all this I thought I can use it for simple collision detection but when I try it appears that collision happens all the time because (I tried boundingSphere) boundingSphere.center is always in (0, 0, 0); So If I want to check collisions between 2 meshes I should for each object - clone boundingSphere object and then get it world coordinates and only then to use intersectsSphere.
something like this:
var bs = component.object.geometry.boundingSphere.clone();
bs.center.setFromMatrixPosition(component.object.matrixWorld);
...
if (_bs.intersectsSphere(bs)){
is this how it suppose to be used or am I missing something and there are more convenient way of doing collisions detection based on boundingBox/boundingSphere?
If you want to do collision detection with bounding boxes you need the boxes in the world coordinate system. The bounding volumes in the intersectsSphere and isIntersectionBox properties of the mesh are in the local coordinate system of the object.
You can do like you did: clone the volumes and move them to the correct position in the world coordinate system, that is a good solution.
Otherwise you can also set a new box from your meshes and do collision using those boxes. Let's say you have a THREE.Mesh called mesh then you can do:
sphere = new THREE.Sphere.setFromPoints( mesh.vertices );
box = new THREE.Box3.setFromObject( mesh );
A little tip. During development it can be nice to see the bounding boxes in your scene, for this you can use the THREE.BoundingBoxHelper:
var helper = new THREE.BoundingBoxHelper( mesh );
scene.add( helper );
I am currently working on a small project using the new Babylon.js framework. One of the issues I have run into is that I basically have two meshes. One of the meshes is supposed to be the background, and the other is supposed to follow the cursor to mark where on the other mesh you are targeting. The problem is that when I move the targeting mesh to the position of the cursor, it blocks the background mesh when I use scene.pick, resulting in the other mesh having its position set on its self.
Is there any way to ignore the targeting mesh when using scene.pick so that I only pick the background mesh or is there some other method I could use? If not, what would be the steps to implement this sort of feature to essentially raycast only through certain meshes?
If you need code samples or any other forms of description, let me know. Thanks!
Ok, it's easy.
So, we have two meshes. One is called "ground", the second "cursor". If you want to pick only on the ground you have two solutions :
First:
var ground = new BABYLON.Mesh("ground",scene);
ground.isPickable = true ;
var cursor = new BABYLON.Mesh("cursor", scene);
cursor.isPickable = false;
...
var p = scene.pick(event.clientX, event.clientY); // it return only "isPickable" meshes
...
Second:
var ground = new BABYLON.Mesh("ground",scene);
var cursor = new BABYLON.Mesh("cursor", scene);
...
var p = scene.pick(event.clientX, event.clientY, function(mesh) {
return mesh.name == "ground"; // so only ground will be pickable
});
...
regards.