ThreeBSP wrong result - javascript

I'm having some troubles with a tube in Three.JS. I have to cut it at 45 degrees and then connect this tube with another one (a connection with "L" form).
My idea is this:
- I create a cube
- I change the position of the cube
- I use a substration between the tube and the cube to get the result
I found that the "subtract" function gives to me a strange result.
Here there is the simplified code (here the cube is not rotated but I will need to rotate it to get my result) and the image the with the undesired result (inside the yellow rectangle).
var cube = new THREE.CubeGeometry(25, 25, 25);
var cMesh = new THREE.Mesh(cube);
cMesh.position.y=100;
cMesh.updateMatrix();
var path = new THREE.LineCurve3(new THREE.Vector3(0, 100, 0), new THREE.Vector3(0,-100, 0));
var geometry = new THREE.TubeGeometry(path, 20, 2, 18, false);
material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
mesh = new THREE.Mesh(geometry, material);
var geom1 = new ThreeBSP(mesh);
var geom2=new ThreeBSP(cMesh);
var geomF=geom1.subtract(geom2);
mesh = geomF.toMesh();
problem detail

Related

Three.js - PlaneGeometry from Math.Plane

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.

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 - Things disappear when zooming out

In my three.js project I use a high z position for my camera.
When the z position is too high my scene becomes black.
So, when I zoom out it becomes black. But I don't want that to happen.
This is how it is with camera.position.z = 3000;
And when I zoom out, just one zoom, it is like this:
For the controls I use OrbitControls, My camera is like:
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 3000);
camera.position.z = 3000;
And here the code for the planet and some planets' orbits:
var scene = new THREE.Scene();
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture("assets/img/sun.jpg")
});
var sun = new THREE.Mesh(new THREE.SphereGeometry(200, 50, 50), material);
scene.add(sun);
var orbitLine = function(radius,y)
{
var segments = 64,
line_material = new THREE.LineBasicMaterial( { color: 0xffffff } ),
geometry = new THREE.CircleGeometry( radius, segments );
geometry.vertices.shift();
var orbit = new THREE.Line( geometry, line_material );
if(y)
orbit.position.y=y;
else if(!y)
orbit.position.y=0;
scene.add(orbit);
};
var Mercury_orbit = orbitLine(400,-70);
var Venus_orbit = orbitLine(700,70);
var Earth_orbit = orbitLine(900,70);
var Mars_orbit = orbitLine(1250,70);
var Jupiter_orbit = orbitLine(3000,70);
Couldn't provide a fiddle as for some reason it didn't work.
If you need more code tell me in the comments and I will add it.
Any ideas?
thanks.
Your camera's far plane is at 3000 which means everything that is 3000 units away will be clipped and not drawn.
At the same time you have placed your camera at (0,0,3000) so you are right on the position where things will start to disappear.

babylonjs: multi-shadows for multi-elements not working

Im trying to get the shadows right using Babylonjs. Without any joy :p
Here is the resources on shadows I have found
Babylonjs wiki: Shadows
framework for building 3D games with HTML5 and WebGL
but I can't find anything on "element on element" shadows. :(
here is my attempt at it:
my sources loosely based on Babylonjs wiki: 17-Shadows
I have 2 lights and 3 objects
I get a shadow behind the sphere but then I also get an artefact on the front face of the sphere.
► Live code:
jsfiddle.net/codemeasandwich/z64Ba
I appreciate your help as I've been struggling with this for a while.
function createSceneTuto(engine) {
var scene = new BABYLON.Scene(engine);
//freeCamera is a FPS like camera where you control the camera with the cursors keys and the mouse
//touchCamera is a camera controlled with touch events (it requireshand.jsto work)
//arcRotateCamera is a camera that rotates around a given pivot. It can be controlled with the mouse or touch events (and it also requires hand.js to work)
// ArcRotateCamera >> Camera turning around a 3D point (here Vector zero)
// Parameters : name, alpha, beta, radius, target, scene
var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 90, BABYLON.Vector3.Zero(), scene);
camera.setPosition(new BABYLON.Vector3(30, 30, 30));
// pointLight (like the sun for instance) which emits lights in every direction from a specific position
// directionalLight which emits lights from the infinite towards a specific direction
var light = new BABYLON.DirectionalLight("Dir0", new BABYLON.Vector3( -1,0, 0), scene);
var light0 = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(1, 10, 100), scene);
light0.diffuse = new BABYLON.Color3( 0,1, 0);
light0.specular = new BABYLON.Color3(1, 1, 1);
var box = BABYLON.Mesh.CreateBox("Box", 3, scene);
var torus = BABYLON.Mesh.CreateTorus("torus", 5, 1, 20, scene);
// var plan = BABYLON.Mesh.CreatePlane("Plane", 50.0, scene);
// plan.position.z = -40
var sphere = BABYLON.Mesh.CreateSphere("Sphere", 15, 20, scene);
// Shadows
var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
var shadowGenerator0 = new BABYLON.ShadowGenerator(1024, light0);
shadowGenerator.getShadowMap().renderList.push(box);
shadowGenerator.getShadowMap().renderList.push(torus);
shadowGenerator.getShadowMap().renderList.push(sphere);
shadowGenerator0.getShadowMap().renderList.push(box);
shadowGenerator0.getShadowMap().renderList.push(torus);
shadowGenerator0.getShadowMap().renderList.push(sphere);
box.receiveShadows = true;
torus.receiveShadows = true;
sphere.receiveShadows = true;
var alphaTorus = 0, alphaBox =0;
scene.registerBeforeRender(function () {
torus.rotation.x += 0.02;
torus.position = new BABYLON.Vector3(Math.cos(alphaTorus) * 15, 0, Math.sin(alphaTorus) * 15);
alphaTorus += 0.003;
box.position = new BABYLON.Vector3(Math.cos(alphaBox) * 15, 0, Math.sin(alphaBox) * 15);
alphaBox += 0.01;
});
return scene;
}
► The above lights as directional lights
var light = new BABYLON.DirectionalLight("Dir0", new BABYLON.Vector3( -1,0, 0), scene);
light.position = new BABYLON.Vector3(0, 0, 20);
light.intensity = 0.5;
var light0 = new BABYLON.DirectionalLight("Omni0", new BABYLON.Vector3(0,0,-1), scene);
light0.position = new BABYLON.Vector3(25, 0, 0);
light.intensity = 0.5;
Only directional lights can cast shadows and they also need a position to define from where the shadows come
I update the wiki to add this IMPORTANT information :)
Only directional ligths can cast shadows:
var light = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(-1, -2, -1), scene);
You must also define a position for your light (because Babylon.js must define a point of view to > create the shadow map):
light.position = new BABYLON.Vector3(20, 40, 20);
Please note that you should have to move the position to define the area where the shadows are seen.

How can I bind two shapes together as one in Three.js?

Can I bind two different shapes together as one shape?
For example, binding sphere and cylinder together as one?
Kind of, yes. There are multiple options:
via hierarchy you can simply add one mesh to another using the add() function
via the GeometryUtil's merge() function to merge vertices and meshes of two Geometry objects into one
using a basic 3D editor that supports Boolean operations between meshes and exporting.
Method 1 is pretty straightforward:
var sphere = new THREE.Mesh(new THREE.SphereGeometry(100, 16, 12), new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading }));
var cylinder = new THREE.Mesh(new THREE.CylinderGeometry(100, 100, 200, 16, 4, false), new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading } ));
cylinder.position.y = -100;
scene.add(sphere);
scene.add(cylinder);
Notice that 16 is repeated, so the subdivisions level in one mesh matches the other (for a decent look).
Method 2.1 - via GeometryUtils
// Make a sphere
var sg = new THREE.SphereGeometry(100, 16, 12);
// Make a cylinder - ideally the segmentation would be similar to predictable results
var cg = new THREE.CylinderGeometry(100, 100, 200, 16, 4, false);
// Move vertices down for cylinder, so it maches half the sphere - offset pivot
for(var i = 0 ; i < cg.vertices.length; i++)
cg.vertices[i].position.y -= 100;
// Merge meshes
THREE.GeometryUtils.merge(sg, cg);
var mesh = new THREE.Mesh(sg, new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading }));
scene.add(mesh);
Method 2.2 merging a Lathe half-sphere and a cylinder:
var pts = []; // Points array
var detail = .1; // Half-circle detail - how many angle increments will be used to generate points
var radius = 100; // Radius for half_sphere
var total = Math.PI * .51;
for(var angle = 0.0; angle < total ; angle+= detail) // Loop from 0.0 radians to PI (0 - 180 degrees)
pts.push(new THREE.Vector3(0,Math.cos(angle) * radius,Math.sin(angle) * radius)); // Angle/radius to x,z
var lathe = new THREE.LatheGeometry(pts, 16); // Create the lathe with 12 radial repetitions of the profile
// Rotate vertices in lathe geometry by 90 degrees
var rx90 = new THREE.Matrix4();
rx90.setRotationFromEuler(new THREE.Vector3(-Math.PI * .5, 0, 0));
lathe.applyMatrix(rx90);
// Make cylinder - ideally the segmentation would be similar for predictable results
var cg = new THREE.CylinderGeometry(100, 100, 200, 16, 4, false);
// Move vertices down for cylinder, so it maches half the sphere
for(var i = 0 ; i < cg.vertices.length; i++)
cg.vertices[i].position.y -= 100;
// Merge meshes
THREE.GeometryUtils.merge(lathe, cg);
var mesh = new THREE.Mesh(lathe, new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading}));
mesh.position.y = 150;
scene.add(mesh);
The one problem I can't address at the moment comes from the faces that are inside the mesh. Ideally, those would have normals flipped, so they wouldn't render, but I haven't found a quick solution for that.
The third is fairly straightforward. Most 3D packages allow Boolean operation on meshes (e.g., merging two meshes together with the ADD operation (meshA + meshB)). Try creating a cylinder and a sphere in Blender (free and opensource), which already has a Three.js exporter. Alternatively you can export an .obj file of the merged meshes from your 3D editor or choice and use the convert_obj_three script.
I've found yet another method, which might be easier/more intuitive. Remember the Boolean operations I've mentioned above?
It turns out there is an awesome JavaScript library just for that: Constructive Solid Geometry:
Chandler Prall wrote some handy functions to connect CSG with three.js. So with the CSG library and the Three.js wrapper for it, you can simply do this:
var cylinder = THREE.CSG.toCSG(new THREE.CylinderGeometry(100, 100, 200, 16, 4, false), new THREE.Vector3(0, -100, 0));
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(100, 16, 12));
var geometry = cylinder.union(sphere);
var mesh = new THREE.Mesh(THREE.CSG.fromCSG(geometry), new THREE.MeshNormalMaterial());
Which gives you a nice result (no problems with extra faces/flipping normals, etc.):

Categories