Three.js - PlaneGeometry from Math.Plane - javascript

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.

Related

Align BoxGeometry between two 3D Points

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

Three.js Mesh position not changing on set

I am trying to map lat/long data to a sphere. I am able to get vectors with different positions and set the position of the cube mesh to those. After I merge and display it appears that there is only one cube. I am assuming that all the cubes are in the same position. Wondering where I am going wrong here. (latLongToSphere returns a vector);
// simple function that converts the data to the markers on screen
function renderData() {
// the geometry that will contain all the cubes
var geom = new THREE.Geometry();
// add non reflective material to cube
var cubeMat = new THREE.MeshLambertMaterial({color: 0xffffff,opacity:0.6, emissive:0xffffff});
for (var i = quakes.length - 1; i >= 0; i--) {
var objectCache = quakes[i]["geometry"]["coordinates"];
// calculate the position where we need to start the cube
var position = latLongToSphere(objectCache[0], objectCache[1], 600);
// create the cube
var cubeGeom = new THREE.BoxGeometry(2,2,2000,1,1,1),
cube = new THREE.Mesh(cubeGeom, cubeMat);
// position the cube correctly
cube.position.set(position.x, position.y, position.z);
cube.lookAt( new THREE.Vector3(0,0,0) );
// merge with main model
geom.merge(cube.geometry, cube.matrix);
}
// create a new mesh, containing all the other meshes.
var combined = new THREE.Mesh(geom, cubeMat);
// and add the total mesh to the scene
scene.add(combined);
}
You have to update the mesh matrix before merging its geometry:
cube.updateMatrix();
geom.merge(cube.geometry, cube.matrix);
jsfiddle: http://jsfiddle.net/L0rdzbej/222/

how to add a object in scene to a mesh without changing its position in three.js

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);

THREE.js: Adding a line over extruded text

I want to add a horizontal line over text which is then extruded:
var geo = new THREE.TextGeometry("x", geometry_options);
var mat = new THREE.MeshBasicMaterial({color: 0, side:THREE.DoubleSide});
geo.computeBoundingBox ();
var vec = new THREE.Shape();
vec.moveTo(geo.boundingBox.min.x, geo.boundingBox.max.y);
vec.lineTo(geo.boundingBox.max.x, geo.boundingBox.max.y);
geo.addShape(vec);
var mesh = new THREE.Mesh(geo, mat);
A Javascript error occurs on calling geo.addShape(vec). I guess I have some misconception. I am not yet very familiar with THREE.js. Any help or an alternative way to accomplish that would be much appreciated.
instead of geo.addShape(vec); try
geo.merge(vec.makeGeometry());
but your geometry is just a line -- it has no polygons -- so it probably won'ty look right.
an alternative might be to have two objects grouped together, one a mesh and the other a line, e.g.:
var all = new THREE.Obejct3D();
var geo = new THREE.TextGeometry("x", geometry_options);
var mat = new THREE.MeshBasicMaterial({color: 0, side:THREE.DoubleSide});
geo.computeBoundingBox ();
var mesh = new THREE.Mesh(geo, mat);
all.add(mesh);
var vecg = new THREE.Geometry();
vecg.vertices.push(
new THREE.Vector3(geo.boundingBox.min.x, geo.boundingBox.max.y,0),
new THREE.Vector3(geo.boundingBox.max.x, geo.boundingBox.max.y,0));
var line = new THREE.Line(vecg, new THREE.LineBasicMaterial());
all.add(line);
then scene.add(all); etc as needed

Threejs BufferGeometry - Render some faces with other Texture

i have an output date like this:
geom[0] = {
texturesindexT: new Int16Array([0,1,2,3]),
texturesindexS: new Int16Array([-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,...]),
materialsindexT: new Int16Array([-1,-1,-1,-1]),
materialsindexS: new Int16Array([-1,0,1,2,3,4,5,0,6,2,7,8,-1,0,...]),
startIndicesT: new Uint32Array([0,288,606,897,1380]),
startIndicesS: new Uint32Array([1380,1431,1479,1485,1497,1515,1659,...]),
m_indices: new Uint16Array([0,1,2,3,0,2,4,2,5,4,6,2,7,3,2,8,9,10,...]),
m_vertices: new Float32Array([-81.93996,25.7185,-85.53822,-81.93996,...]),
m_normals: new Float32Array([-0.004215205,0.9999894,-0.001817489,-0.004215205,...]),
m_texCoords: new Float32Array([0,0.04391319,0,0.2671326,0.009521127,0.03514284,...]),
}
var textures = new Array("-1_-1/t0.jpg","-1_-1/t1.jpg","-1_-1/t2.jpg",...);
The Data is in order for an Index, Vertex and Normal-Buffer but sections have to be rendered with other Textures and Maretials.
I have tried to make a THREE.Geometry out of the indices, vertices and texCoords/UVCoords but that didn't work.
Now i am trying use a THREE.BufferGeometry() and this work BUT i need to render index 0 to 287 with Texture "textures[0]" and index 288 to 605 with "textures[1]" and so on.
My first attempt was to make a BufferGeometry for each part with index 288 to 605 , but since the Indices are in order for the hole model, i have to put the complete vertices, normales and UVCoords in the Buffer for just a couple of faces.
Is there a way to render sections of the BufferGeometry with other Textures or to set the Texture Index for each Face?
Or is it possible to create a Material, that renders the first X faces with Texture A and the next with Texture B???
If you want to use two different textures with a single BufferGeometry, you can use this pattern, which sets drawcalls:
var geometry1 = new THREE.BufferGeometry();
// ...and set the data...
var geometry2 = geometry1.clone();
// set drawcalls
geometry1.offsets = geometry1.drawcalls = []; // currently required
geometry1.addDrawCall( start1, count1, 0 );
geometry2.offsets = geometry2.drawcalls = []; // currently required
geometry2.addDrawCall( start2, count2, 0 );
var material1 = new THREE.MeshPhongMaterial( { map: map1 } );
var material2 = new THREE.MeshPhongMaterial( { map: map2 } );
var mesh1 = new THREE.Mesh( geometry1, material1 );
var mesh2 = new THREE.Mesh( geometry2, material2 );
three.js r.70
You can create two geometries with same vertex buffers and different indexes:
var position = new THREE.BufferAttribute(positionArray, 3);
var normal = new THREE.BufferAttribute(normalArray, 3);
var uv = new THREE.BufferAttribute(uvArray, 2);
var indices1 = new THREE.BufferAttribute(indexArray1, 1);
var geometry1 = new THREE.BufferGeometry();
geometry1.addAttribute('position', position);
geometry1.addAttribute('normal', normal);
geometry1.addAttribute('uv', uv);
geometry1.addAttribute('index', indices1);
var indices2 = new THREE.BufferAttribute(indexArray2, 1);
var geometry2 = new THREE.BufferGeometry();
geometry2.addAttribute('position', position);
geometry2.addAttribute('normal', normal);
geometry2.addAttribute('uv', uv);
geometry2.addAttribute('index', indices2);
and then create 2 meshes with different materials as you normally would. As far as I understand, this will re-use same data in both meshes.

Categories