Verifying if a point is inside a cube in three.js - three.js

I have created a cube as:
var cubeGeometry = new THREE.BoxGeometry( 1, 1, 1 );
var cubeMaterial = new THREE.MeshLambertMaterial( { color:
0xffff00,wireframe: true } );
var cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.position.x = p.x;
cube.position.y = p.y;
cube.position.z = p.z;
scene.add(cube);
p is a input point to my function. So this code creates a cube at position p and adds it to the scene.
How can I check that some point,say A, lies inside this cube? I couldn't find any helper function like containsPoint etc for Three.Mesh. I may do some additional checks to verify, but I am looking for a Three.js function.

You can create THREE.Box3() instance, using its .setFromObject() the cube as the parameter, then call .containsPoint(), passing the point you want to check as the parameter to this method:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var cube = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
cube.position.set(0, 1, 0);
scene.add(cube);
var pointA = new THREE.Vector3(0, 1, 0);
var pointB = new THREE.Vector3(2, 1, 0);
point(pointA, 0x00ff00);
point(pointB, "yellow");
function point(point, color) {
p = new THREE.Mesh(new THREE.SphereGeometry(0.25, 4, 2), new THREE.MeshBasicMaterial({
color: color
}));
p.position.copy(point);
scene.add(p);
}
var bb = new THREE.Box3(); // for re-use
bb.setFromObject(cube);
console.log(bb);
console.log(bb.containsPoint(pointA), bb.containsPoint(pointB));
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

cube.updateMatrixWorld(); //Make sure the object matrix is current with the position/rotation/scaling of the object...
var localPt = cube.worldToLocal(yourPoint.clone()); //Transform the point from world space into the objects space
if(Math.abs(localPt.x)<=0.5&&Math.abs(localPt.y)<=0.5&&Math.abs(localPt.z)<=0.5)
console.log("Point is inside!"); //Check if all the axis are within the size of the cube.. if your cube sizes arent 1,1,1, you'll have to adjust these checks to be half of width/height/depth..
Something like that?

#prisoner849
Your solution doesn't work if the box is rotated.
Here's an illustration of the problem. I render both solutions and you can see where the Box3 version breaks with the rotated cube, whereas the analytical once works.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var boxDimensions = new THREE.Vector3(2,2,2);
var cube = new THREE.Mesh(new THREE.BoxGeometry(boxDimensions.x,boxDimensions.y,boxDimensions.z), new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
cube.position.set(0, 1, 0);
cube.rotation.y = Math.PI*0.25;
scene.add(cube);
var pointA = new THREE.Vector3(0.95, 0.95, 0.95);
var pointC = new THREE.Vector3(-0.65, 0.65, -0.65);
var pa = point(pointA, 0x00ff00);
var pc = point(pointC, 0x00ff00);
function point(point, color) {
p = new THREE.Mesh(new THREE.SphereGeometry(0.25, 4, 2), new THREE.MeshBasicMaterial({
color: color
}));
p.position.copy(point);
scene.add(p);
return p;
}
var bb = new THREE.Box3(); // for re-use
bb.setFromObject(cube);
console.log(bb);
function correctPointInBox(pt,cube,boxDim){
cube.updateMatrixWorld(); //Make sure the object matrix is current with the position/rotation/scaling of the object...
var localPt = cube.worldToLocal(pt.clone()); //Transform the point from world space into the objects space
if(Math.abs(localPt.x)<=boxDim.x*0.5&&Math.abs(localPt.y)<=boxDim.y*0.5&&Math.abs(localPt.z)<=boxDim.z*0.5)
return true;
else
return false;
}
render();
function render() {
pa.position.x = Math.sin(performance.now()*0.001)*2;
pc.position.z = Math.cos(performance.now()*0.001)*2;
if(bb.containsPoint(pa.position))
pa.material.color.set("red")
else
pa.material.color.set("green")
if(correctPointInBox(pc.position,cube,boxDimensions))
pc.material.color.set("red")
else
pc.material.color.set("green")
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Related

I need to use the data from first picture to draw cylinder,put two cylinders point B is not coincide(like second picture)

**I need to use the data from first picture to draw cylinder,put two cylinders point B is not coincide(like second picture) **
var geometry = new THREE.CylinderGeometry(10, 10,151.02648774304458, 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(1,75.5,1);
scene.add(mesh);
var material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var geometry1 = new THREE.CylinderGeometry(10, 10,158.8741640418605, 20, 1, false);
var mesh1 = new THREE.Mesh(geometry1, material1);
mesh1.position.set(-30,217,32.5);
mesh1.rotation.set(2,151,2);
scene.add(mesh1);
You have to add the red cylinder to a Group. Set the position in that way, that the bottom of the cylinder is at (0, 0, 0). Set the position of the group in that way, that it's origin is at the top of the black cylinder.
Finally you have to rotate the group:
let height = 151.02648774304458;
let height1 = 158.8741640418605;
var geometry = new THREE.CylinderGeometry(10, 10, height, 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(1, 75.5, 1);
scene.add(mesh);
var material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var geometry1 = new THREE.CylinderGeometry(10, 10, height1, 20, 1, false);
var mesh1 = new THREE.Mesh(geometry1, material1);
mesh1.position.set(0, height1/2, 0);
group = new THREE.Group();
group.position.set(mesh.position.x, mesh.position.y + height/2, mesh.position.z);
group.add(mesh1);
group.rotation.set(...);
scene.add(group);
(function onLoad() {
var container, camera, scene, renderer, orbitControls;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
canvas: my_canvas,
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
//container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 200, -400);
camera.lookAt( 0, 0, 0 );
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
orbitControls = new THREE.OrbitControls(camera, container);
createModel();
}
var group;
function createModel() {
var material = new THREE.MeshPhongMaterial({color:'#ff0000'});
var material1 = new THREE.MeshPhongMaterial({color:'#000000'});
let height = 151.02648774304458;
let height1 = 158.8741640418605;
var geometry = new THREE.CylinderGeometry(10, 10, height, 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(1, 75.5, 1);
scene.add(mesh);
var material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var geometry1 = new THREE.CylinderGeometry(10, 10, height1, 20, 1, false);
var mesh1 = new THREE.Mesh(geometry1, material1);
mesh1.position.set(0, height1/2, 0);
group = new THREE.Group();
group.position.set(mesh.position.x, mesh.position.y + height/2, mesh.position.z);
group.add(mesh1);
//group.rotation.set(2, 151, 2);
scene.add(group);
}
var rotate = 0.0;
function animate() {
group.rotation.set(0, 0, rotate);
rotate += 0.01;
requestAnimationFrame(animate);
orbitControls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<script src="https://cdn.jsdelivr.net/npm/three#0.115/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.115/examples/js/controls/OrbitControls.js"></script>
<div id="container"><canvas id="my_canvas"> </canvas></div>
To set a specific rotation by a specific vector, I recommend to set the rotation by a .setRotationFromQuaternion.
The Quaternion defines how to rotate from the upwards direction (0, 1, 0) to the target direction. The Target direction is the vector form the joint to the endpoint of the upper cylinder (-62-1, 283-151, 61-1):
For instance:
let upVector = new THREE.Vector3(0, 1, 0);
let targetVector = new THREE.Vector3(-62 - 1, 283 - height, 61 - 1);
let quaternion = new THREE.Quaternion().setFromUnitVectors(
upVector, targetVector.normalize());
group.setRotationFromQuaternion(quaternion)

Rotating a cube about an axis

In my program, I have done as:
var object = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial( 0xff0000 ) );
object.rotation.x = Math.PI / 2;
var box = new THREE.BoxHelper( object, 0xffff00 );
scene.add(box);
Here,I first try to create a wireframe box and then rotate it by 90 degrees about x axis(line 2). But I don't see any change in box's orientation.
What is correct way of doing it?
Just set rotation of the cube at 90 degrees (here it's 45) and you'll have the same cube:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var cube = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
cube.position.set(0, 1, 0);
cube.rotation.x = Math.PI * 0.25;
scene.add(cube);
var box = new THREE.BoxHelper(cube, 0xff9900);
scene.add(box);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

How to join two individual vertices each belonging to two different geometries?

At the same position?
Here is my code:
var cubeGeometry1 = new THREE.BoxGeometry(20,20,20);
var cubeMesh1 = new THREE.Mesh(cubeGeometry1, material1);
var cubeGeometry2 = new THREE.BoxGeometry(20, 20, 20);
var cubeMesh2 = new THREE.Mesh(cubeGeometry2, material1);
scene.add(cubeMesh1);
scene.add(cubeMesh2);
Here are the two vertices I need to join together. I need to find the middle world coordinates in between them, once this is done, I need to translate them twoards eachother (practically merging them into the same spot)
var myPoint1 = cubeGeometry1.vertices[0];
var myPoint2 = cubeGeometry2.vertices[5];
Here is what I have so far - Although this did not work and I do not fully understand the code.
function getPointInBetweenByPerc(pointA, pointB, percentage)
{
var dir = pointB.clone().sub(pointA);
var len = dir.length();
dir = dir.normalize().multiplyScalar(len*percentage);
return pointA.clone().add(dir);
}
var pointToTransform = getPointInBetweenByPerc(myPoint1, myPoint2, 0.5);
console.log(pointToTransform);
cubeGeometry1.vertices[0].x = pointToTransform.x; //only applies to local matrix?
cubeGeometry2.vertices[5].x = pointToTransform.x;
I simply just want to merge vertex A from Geometry A with Vertex B from Geometry B.
If I got you correctly, you can use .localToWorld(), .worldToLocal() methods:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-2, 3, 5);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var box1 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({
color: "red",
wireframe: true
}));
box1.position.set(0, 0, 0);
scene.add(box1);
var box2 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({
color: "blue",
wireframe: true
}));
box2.position.set(1, 2, 3);
scene.add(box2);
btnMerge.addEventListener("click", function() {
let vertex1 = box1.localToWorld(box1.geometry.vertices[0].clone());
let vertex2 = box2.localToWorld(box2.geometry.vertices[3].clone());
let midPoint = vertex1.add(vertex2).multiplyScalar(0.5);
box1.geometry.vertices[0].copy(box1.worldToLocal(vertex1.copy(midPoint)));
box2.geometry.vertices[3].copy(box2.worldToLocal(vertex2.copy(midPoint)));
box1.geometry.verticesNeedUpdate = true;
box2.geometry.verticesNeedUpdate = true;
}, false);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<button id="btnMerge" style="position: absolute;">Merge</button>

Assigning displacement/normal map to a single side of a cylinder

I have a cylinder created like this:
var geometry = new THREE.CylinderGeometry( 50, 50, 2, 128 );
It is a flat cylinder, like a coin. When I ad a displacementMap & normalMap, I end up with textures on both side of the cylinder, but I only want the maps to be on one side.
How can I do this?
For a THREE.CylinderGeometry a separated material for the shaft, the top plane and the bottom plane can be set:
var material1 = new THREE.MeshBasicMaterial({color:'#ff0000'});
var material2 = new THREE.MeshBasicMaterial({color:'#00ff00'});
var material3 = new THREE.MeshBasicMaterial({color:'#0000ff'});
var materialList = [material1, material2, material3];
var geometry = new THREE.CylinderGeometry( 50, 50, 2, 128 );
var mesh = new THREE.Mesh(geometry, materialList);
See the code snippet:
(function onLoad() {
var container, loader, camera, scene, renderer, controls, mesh;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, -100, -100);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
window.onresize = resize;
scene.add(camera);
window.onresize = resize;
var material1 = new THREE.MeshBasicMaterial({color:'#ff0000'});
var material2 = new THREE.MeshBasicMaterial({color:'#00ff00'});
var material3 = new THREE.MeshBasicMaterial({color:'#0000ff'});
var materialList = [material1, material2, material3];
var geometry = new THREE.CylinderGeometry( 50, 50, 2, 128 );
mesh = new THREE.Mesh(geometry, materialList);
scene.add(mesh);
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function resize() {
var aspect = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = aspect;
camera.updateProjectionMatrix();
}
function animate() {
mesh.rotation.x += 0.01;
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<script src="https://threejs.org/build/three.min.js"></script>
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script-->
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
Use the thetaLength option of CylinderGeometry to separate it into two pieces.
// Create two half-cylinders.
var part1 = new THREE.CylinderGeometry( 50, 50, 2, 128, 1, false, 0, Math.PI );
var part2 = new THREE.CylinderGeometry( 50, 50, 2, 128, 1, false, Math.PI, Math.PI );
// Add the half-cylinders to a group, with different materials on each.
var group = new THREE.Group();
group.add( new THREE.Mesh( part1, material1 ) );
group.add( new THREE.Mesh( part2, material2 );
If you need more custom control than this, you probably want to use a modeling program like Blender to set up UVs and texture the cylinder.

Three js - moving rotation axis

Using threejs I created a simple cylinder object and rotating it in z-axis. The object rotates around the center axis, both the ends of the cylinder rotate around the axis which is at the center of the cylinder.
How can I make it rotate in a different axis? I would like the cylinder to rotate by having one end in a fixed point while the other end goes around in circles. My code is below.
init();
function init() {
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('myCanvas'), antialias: true });
renderer.setClearColor(0xeaebed);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(5, window.innerWidth / window.innerHeight, 0.1, 4000);
scene = new THREE.Scene();
//LIGHTS
var light = new THREE.AmbientLight(0xffffff, 1);
scene.add(light);
var light1 = new THREE.PointLight(0xffffff, 0.3);
scene.add(light1);
//Gun holder
var gunHolder = new THREE.Object3D();
var gunHolderColour = 0x0f4207;
var gunHolderBaseCylinderGeometry = new THREE.CylinderGeometry(10, 10, 50, 32);
var gunHolderBaseCylinderMaterial = new THREE.MeshStandardMaterial({
color: gunHolderColour,
metalness: 0.5,
roughness: 0.5
});
var gunHolderBaseCylinderMesh = new THREE.Mesh(gunHolderBaseCylinderGeometry, gunHolderBaseCylinderMaterial);
gunHolderBaseCylinderMesh.position.set(0, -8, -3000);
scene.add(gunHolderBaseCylinderMesh);
requestAnimationFrame(render);
function render() {
gunHolderBaseCylinderMesh.rotation.z += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
}
You can use .translate() method of your geometry:
var gunHolderBaseCylinderGeometry = new THREE.CylinderGeometry(10, 10, 50, 32); // height is 50
gunHolderBaseCylinderGeometry.translate(0, 25, 0); // move upwards at half of height, 25
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0xeaebed);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(5, window.innerWidth / window.innerHeight, 0.1, 4000);
scene = new THREE.Scene();
//LIGHTS
var light = new THREE.AmbientLight(0xffffff, 1);
scene.add(light);
var light1 = new THREE.PointLight(0xffffff, 0.3);
scene.add(light1);
//Gun holder
var gunHolder = new THREE.Object3D();
var gunHolderColour = 0x0f4207;
var gunHolderBaseCylinderGeometry = new THREE.CylinderGeometry(10, 10, 50, 32);
gunHolderBaseCylinderGeometry.translate(0, 25, 0);
var gunHolderBaseCylinderMaterial = new THREE.MeshStandardMaterial({
color: gunHolderColour,
metalness: 0.5,
roughness: 0.5
});
var gunHolderBaseCylinderMesh = new THREE.Mesh(gunHolderBaseCylinderGeometry, gunHolderBaseCylinderMaterial);
gunHolderBaseCylinderMesh.position.set(0, -8, -3000);
scene.add(gunHolderBaseCylinderMesh);
requestAnimationFrame(render);
function render() {
requestAnimationFrame(render);
gunHolderBaseCylinderMesh.rotation.z += 0.01;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.js"></script>

Resources