I'm working on a project in which I create 3d Widget to rotate, scale and translate a mesh.
I'm currently having some trouble with positioning the cone that I use for scaling the parent mesh.
This is my code:
function createScaleWidget(mesh, constScale){
var bbox = new THREE.Box3().setFromObject(mesh);
var material = new THREE.MeshBasicMaterial({
color: 0x0000ff
});
var coneGeom = new THREE.CylinderGeometry(0, constScale, 10, 50, 20, false);
var cone = new THREE.Mesh(coneGeom,material);
cone.position.y = bbox.max.y/2; //assuming all the objects are laid on the ground
cone.position.z = bbox.max.z+10;
cone.position.x = bbox.max.x+10;
mesh.add(cone);
}
mesh is the mesh I'm creating the widget for,
cone is the widget.
I would like to have the cone in the middle of the mesh (with respect to y)
and in an angle with respect to the bounding box (the ideal would be to have it on the right of the face bounding box that is facing the camera).
Probably my problem is due to the fact that the cone is child of the mesh therefore the final position do not only depends on the bbox but also on the position of the mesh itself.
I guess you want something like that:
You are right you have to locate the cone relatively to its parent position, in this case - the mesh:
function createScaleWidget(mesh, constScale){
var bbox = new THREE.Box3().setFromObject(mesh);
var material = new THREE.MeshBasicMaterial({
color: 0x0000ff
});
var coneGeom = new THREE.CylinderGeometry(0, constScale, 10, 50, 20, false);
var cone = new THREE.Mesh(coneGeom,material);
cone.position.y = bbox.size().y / 2;
mesh.add(cone);
}
this worked for me while i did something similar. the cone should be placed next to one of the faces. to try another face you can then try:
cone.position.z = bbox.size().z / 2;
instead.
Related
I make a game where you can add objects to a world without using a grid. Now I want to make a footpath. When you click on "Create footpath", then you can add a point to on the world at the raycaster position. After you add a first point you can add a second point to the world. When these 2 objects where placed. A line/footpath is visible from the first point to the second one.
I can do this really simple with THREE.Line. See the code:
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push( new THREE.Vector3(x1,0,z1), new THREE.Vector3(x2,0,z2) );
lineGeometry.computeLineDistances();
var lineMaterial = new THREE.LineBasicMaterial( { color: 0xFF0000 } );
var line = new THREE.Line( lineGeometry, lineMaterial );
scene.add(line);
But I can't add a texture on a simple line. Now I want to do something the same with a Mesh. I have the position of the first point and the raycaster position of the second point. I also have the lenght between the two objects for the lenght of the footpath. But I don't know how I can get the rotation what is needed.
Note. I saw something about LookAt, is this maybe a good idea, how can I use this with a mesh?
Can anyone help me to get the correct rotation for the footpath object?
I use this code for the foodpath mesh:
var loader = new THREE.TextureLoader();
loader.load('images/floor.jpg', function ( texture ) {
var geometry = new THREE.BoxGeometry(10, 0, 2);
var material = new THREE.MeshBasicMaterial({ map: texture, overdraw: 0.5 });
var footpath = new THREE.Mesh(geometry, material);
footpath.position.copy(point2);
var direction = // What can I do here?
footpath.rotation.y = direction;
scene.add(footpath);
});
I want to get the correct rotation for direction.
[UPDATE]
The code of WestLangley helps a lot. But it works not in all directions. I used this code for the lenght:
var lenght = footpaths[i].position.z - point2.position.z;
What can I do that the lenght works in all directions?
You want to align a box between two 3D points. You can do that like so:
var geometry = new THREE.BoxGeometry( width, height, length ); // align length with z-axis
geometry.translate( 0, 0, length / 2 ); // so one end is at the origin
...
var footpath = new THREE.Mesh( geometry, material );
footpath.position.copy( point1 );
footpath.lookAt( point2 );
three.js r.84
Refer https://jsfiddle.net/pmankar/svt0nhuv/
Main large red icosahedron geometry keeps rotating about the y axis. I added a small red sphere geometry and merged it to the main large red icosahedron geometry. Until here it works fine. For this I used, THREE.GeometryUtils.merge(point_sphere_iso_geom, sphere);
However, when I try to add spheres dynamically with a mouse click, they are added (yellow spheres), but they do not rotate with the main large red icosahedron geometry.
Can anyone explain why does it works in the initial case, but not when added dynamically and how to achieve it dynamically as well.
I hope I understood you correctly. Every mouse click you have to create a new geometry based on the previous one (mesh geometry and mesh matrix), merging it with the geometry of a new sphere, and apply it to a new mesh, then remove the old mesh and add the new one.
some changes in vars
var geometry, material, point_sphere_iso_geom, mesh;
in creation of the start merged mesh
point_sphere_iso_geom = new THREE.IcosahedronGeometry(100, 4);
cygeo = new THREE.SphereGeometry(5, 10, 10);
cygeo.translate(0,0,120);
point_sphere_iso_geom.merge( cygeo );
mesh = new THREE.Mesh(point_sphere_iso_geom, material);
and in the function of addYellowPoint
function addYellowPoint(valX, valY) {
var sgeometry = new THREE.SphereGeometry(2.5, 10, 10);
var range = 150;
var x = Math.random() * range - range / 2;
var y = Math.random() * range - range / 2;
var z = Math.random() * range - range / 2;
sgeometry.translate(x,y,z);
point_sphere_iso_geom = mesh.geometry.clone();
point_sphere_iso_geom.applyMatrix(mesh.matrix);
point_sphere_iso_geom.merge(sgeometry);
scene.remove(mesh);
mesh.geometry.dispose();
mesh.material.dispose();
mesh = new THREE.Mesh(point_sphere_iso_geom, material);
scene.add(mesh);
}
I am trying to draw a least squares plane through a set of points in Three.js. I have a plane defined as follows:
var plane = new THREE.Plane();
plane.setFromNormalAndCoplanarPoint(normal, point).normalize();
My understanding is that I need to take that plane and use it to come up with a Geometry in order to create a mesh to add to the scene for display:
var dispPlane = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(dispPlane);
I've been trying to apply this answer to get the geometry. This is what I came up with:
plane.setFromNormalAndCoplanarPoint(dir, centroid).normalize();
planeGeometry.vertices.push(plane.normal);
planeGeometry.vertices.push(plane.orthoPoint(plane.normal));
planeGeometry.vertices.push(plane.orthoPoint(planeGeometry.vertices[1]));
planeGeometry.faces.push(new THREE.Face3(0, 1, 2));
planeGeometry.computeFaceNormals();
planeGeometry.computeVertexNormals();
But the plane is not displayed at all, and there are no errors to indicate where I may have gone wrong.
So my question is, how can I take my Math.Plane object and use that as a geometry for a mesh?
This approach should create a mesh visualization of the plane. I'm not sure how applicable this would be towards the least-squares fitting however.
// Create plane
var dir = new THREE.Vector3(0,1,0);
var centroid = new THREE.Vector3(0,200,0);
var plane = new THREE.Plane();
plane.setFromNormalAndCoplanarPoint(dir, centroid).normalize();
// Create a basic rectangle geometry
var planeGeometry = new THREE.PlaneGeometry(100, 100);
// Align the geometry to the plane
var coplanarPoint = plane.coplanarPoint();
var focalPoint = new THREE.Vector3().copy(coplanarPoint).add(plane.normal);
planeGeometry.lookAt(focalPoint);
planeGeometry.translate(coplanarPoint.x, coplanarPoint.y, coplanarPoint.z);
// Create mesh with the geometry
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffff00, side: THREE.DoubleSide});
var dispPlane = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(dispPlane);
var material = ...;
var plane = new THREE.Plane(...);
// Align to plane
var geometry = new THREE.PlaneGeometry(100, 100);
var mesh = new THREE.Mesh(geometry, material);
mesh.translate(plane.coplanarPoint());
mesh.quaternion.setFromUnitVectors(new THREE.Vector3(0,0,1), plane.normal);
Note that Plane.coplanarPoint() simply returns -normal*constant, so it might be a better option to use Plane.projectPoint() to determine a center that is "close to" an arbitrary point.
im stuck with a work that i need to do, basicly first i needed to create a pendulum that basicly is 2 spheres and 1 cylinder the 2 spheres are in the up and down a bigger 1 and a smaller 1, what i need to do is the pendulum should move not around his own center but about a center that is 0.85 the height of my cylinder, my idea was to create a pivot point, but since i dont know very good how the pivot point work i tryed a lot of things, i tryed first to add the cylinder to the scene and the spheres to the cylinder, then i created the pivot point and add the pivot point to the cylinder, in the animate function i just tried to rotate the pivot point in the x axis but nothing happens :/
Here is my code guys hope someone can give me a hand
var scene, camera, renderer;
var caixaGrande, caixaPequena1, caixaPequena2,cylinder,Cylinder2,esferaGrande;
var pivotPoint1, pivotPoint2;
const RAIOCILINDRO = 2.5;
const ALTURACILINDRO = 100;
const RAIOESFERAGRANDE = 15;
const RAIOESFERAPEQUENA = 5;
var rotacao = Math.PI/180;
window.onload = function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.up=new THREE.Vector3(0,1,0);
camera.position.set(150,50,50);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// Add a directional light to show off the object
var light = new THREE.DirectionalLight( 0xffffff, 1.5);
// Position the light out from the scene, pointing at the origin
light.position.set(1.5, 1.5, 1);
scene.add( light );
var textureCylindro = new THREE.TextureLoader().load("CylinderTexture.png");
var textureSphere = new THREE.TextureLoader().load("SphereTexture.png");
geometry = new THREE.CylinderGeometry(RAIOCILINDRO,RAIOCILINDRO,ALTURACILINDRO);
material = new THREE.MeshPhongMaterial( {color: 0xffffff , map:textureCylindro} );
cylinder = new THREE.Mesh(geometry,material);
scene.add(cylinder);
pivotPoint1 = new THREE.Object3D();
pivotPoint1.position.y=ALTURACILINDRO*0.15;
cylinder.add(pivotPoint1);
var geometry = new THREE.SphereGeometry(RAIOESFERAGRANDE);
var material = new THREE.MeshPhongMaterial( {color: 0xffffff,map:textureSphere} );
esferaGrande = new THREE.Mesh( geometry, material );
esferaGrande.position.y = -ALTURACILINDRO/2;
cylinder.add( esferaGrande );
var geometry = new THREE.SphereGeometry(RAIOESFERAPEQUENA);
var material = new THREE.MeshPhongMaterial( {color: 0xffffff,map:textureSphere} );
var esferaPequena = new THREE.Mesh( geometry, material );
esferaPequena.position.y = ALTURACILINDRO/2;
cylinder.add( esferaPequena );
Cylinder2 = cylinder.clone();
Cylinder2.position.z = 3 * RAIOESFERAGRANDE;
scene.add(Cylinder2);
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
animate();
}
function animate() {
pivotPoint1.rotation.x += 10;
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
What you should do is create an Object3D that you add the other 3 elements to, then you add that Object3D to the scene. Then when you want to rotate the whole thing, you rotate your Object3D.
So for example:
var axis = new Object3D();
sphere1.position.y = -.15 * pendulumLength;
sphere2.position.y = .85 * pendulumLength;
cylinder.position.y = .35 * pendulumLength;
//assuming the cylinder is pendulumLength long, this^ puts it right between the two balls
axis.add(sphere1);
axis.add(sphere2);
axis.add(cylinder);
scene.add(axis);
then in your animate() function, simply rotate your Axis:
axis.rotation.z += .01;
EDIT:
So, here is my bad drawing of what happens. If you look here, the circle when positioned at 0,0 when rotated, rotates around the axis. Again when you move it up to 1,1 it rotates around its center point, because rotation is relative to the center point of the circle.
Again the same is true of the cylinder. At 0,0 it rotates around its center. At .5,.5 it also rotates around its center. It doesn't care where it is, it will rotate around its position point.
So if we want to rotate these two as a group relative to some other point, we need to make them the children of another object, because when we move the parent, the children maintain their relationship to the parent, even though their positions are still 1,1 and .5,.5 respectively.
The reason that they get rotated in the manner on the right is because their relationship to the parent object is 1,1 and .5,.5 relative to a parent object with a rotation of 0 radians. When we rotate the parent object by some number of radians, they need to move in order to maintain their original relationship.
Another way to think of it: You have a wooden board with a nail perfectly through the center and you have a shoe. You set the shoe in the upper right hand corner of the board with the toe pointing away from you. If you rotate the wooden board Math.PI/2 radians, the shoe will not stay in the upper right hand corner (relative to you), even though that's where you put it, because the shoe has been added to the board, and you have moved the board. Now, the shoe should be in the bottom right, and will be facing to your right. Object3D.add() is like the process of putting the shoe on the board.
I want to keep the position of an object in scene and want to change the parent of that object from scene to any other mesh.here is a sample code
http://plnkr.co/edit/fpjsUkOA0rH6FvG4DL6Z?p=preview
in this example when am trying to add the sphere to box it's position is changing.i want to keep the original position .try to remove comment in line 35 ,the spehere is moving towards box.i want to keep its position and make sphere box's child
http://plnkr.co/edit/fpjsUkOA0rH6FvG4DL6Z?p=preview
If question relies only to position then the answer of Brakebein may be correct. But if you need also to revert scale and rotation, then you should make something like this, I think:
var inversionMatrix = new THREE.Matrix4();
inversionMatrix.getInverse( parentObject.matrix );
childObject.applyMatrix(inversionMatrix);
If you add the sphere to the group, you just need to substract the group's position from the sphere's position to keep it in its original world position.
var material = new THREE.MeshLambertMaterial({color: 0x00ff00});
var boxGeometry = new THREE.BoxGeometry(5, 15, 5);
var box = new THREE.Mesh(boxGeometry, material);
var sphereGeometry = new THREE.SphereGeometry( 5, 32, 32 );
var sphere = new THREE.Mesh(sphereGeometry, material);
sphere.position.set(0, 10, 0);
sphere.updateMatrix();
var group = new THREE.Object3D();
group.translateX(6);
group.updateMatrix();
// if you add sphere to group object
group.add(box);
group.add(sphere);
scene.add(group);
var m = new THREE.Matrix4().getInverse(group.matrixWorld);
sphere.applyMatrix(m);
// if you add sphere to box
group.add(box);
box.add(sphere);
scene.add(group);
var m = new THREE.Matrix4().getInverse(box.matrixWorld);
sphere.applyMatrix(m);
console.log(group.position, sphere.position);