Related
I'm having a problem merging multiple lines into one geometry. Line geometry was built using the CubicBezierCurve3:
const curve = new CubicBezierCurve3(
point1,
point2,
point3,
point4
);
const geometry = new BufferGeometry();
const points = curve.getPoints(16);
geometry.setFromPoints(points);
Then these two geometries were merged using BufferGeometryUtils:
const line = new Line(BufferGeometryUtils.mergeBufferGeometries([line1Geometry, line2Geometry], false), new LineBasicMaterial())
As a result, the desired figure turned out, but an extra line came from somewhere that connects them.
line
If I change the order when merging, then I get a different line. I don't understand how to solve this problem.
line2
You can't use THREE.Line for this use case since it represents a continuous line. So if you merge two separate lines into one, there will be no gap that separates both.
You have to use THREE.LineSegments however that means you have to pre-process your curve geometries. Try it like in the following live example:
let camera, scene, renderer;
init();
render();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.set(0, 0.5, 2);
scene = new THREE.Scene();
const curve1 = new THREE.CubicBezierCurve3(
new THREE.Vector3(1, 0, 0),
new THREE.Vector3(2, 0, 0),
new THREE.Vector3(1, 1, 0),
new THREE.Vector3(2, 1, 0)
);
const geometry1 = createGeometry(curve1.getPoints(32));
const curve2 = new THREE.CubicBezierCurve3(
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(-2, 0, 0),
new THREE.Vector3(-1, 1, 0),
new THREE.Vector3(-2, 1, 0)
);
const geometry2 = createGeometry(curve2.getPoints(32));
const geometry = THREE.BufferGeometryUtils.mergeBufferGeometries([geometry1, geometry2]);
const material = new THREE.LineBasicMaterial();
mesh = new THREE.LineSegments(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function render() {
renderer.render(scene, camera);
}
function createGeometry(points) {
const vertices = [];
const segments = points.length - 1;
for (let i = 0; i < segments; i++) {
const point1 = points[i];
const point2 = points[i + 1];
vertices.push(point1.x, point1.y, point1.z);
vertices.push(point2.x, point2.y, point2.z);
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
return geometry;
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.145/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.145/examples/js/utils/BufferGeometryUtils.js"></script>
I created kind of mannequin with three.js.
I want to make it possible to:
link all objects with connection child-parent
move objects relatively (if hand moved, than elbow whould be moved, but if wrist moved, than other parts should not be moved)
I wrote code below and made jsfiddle example. Not sure whether it is correct way.
var scene, camera, renderer, pivot;
//main
init();
animate();
//init
function init() {
//scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);
//camera
camera = new THREE.PerspectiveCamera(140, window.innerWidth / window.innerHeight, 0.1, 10000);
//neck
var geometry = new THREE.BoxBufferGeometry(2, 3, 1);
var material = new THREE.MeshNormalMaterial({
transparent: true,
opacity: 0.5
});
var figure = new THREE.Mesh(geometry, material);
figure.position.set(0, 1.5, 0);
//body
var geometry2 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
/* geometry2.rotateZ(THREE.Math.degToRad(90)); // ROTATE GEOMETRY SO IT'S IN THE CORRECT ORIENTATION */
var figure2 = new THREE.Mesh(geometry2, material);
figure2.position.set(0, 1.5, 0); // MOVE THE GEOMOETRY UP BY HALF SO PIVOT IS AT THE BOTTOM OF THE GEO
/* figure2.rotation.set(0, 0, Math.PI / 2); */
figure.add(figure2);
//head
var geometry3 = new THREE.SphereGeometry(0.75, 32, 32);
var material3 = new THREE.MeshBasicMaterial({
color: 0xffff00
});
var sphere3 = new THREE.Mesh(geometry3, material3);
sphere3.position.set(0, 2.5, 0);
figure.add(sphere3)
//right shoulder
var geometry4 = new THREE.SphereGeometry(0.25, 32, 32);
var material4 = new THREE.MeshBasicMaterial({
color: 0xffff00
});
var sphere4 = new THREE.Mesh(geometry4, material4);
sphere4.position.set(1.25, 1.25, 0);
figure.add(sphere4)
//right hand top
var geometry5 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure5 = new THREE.Mesh(geometry5, material);
figure5.position.set(1.25, 0.25, 0);
figure.add(figure5);
//right elbow
var geometry6 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere6 = new THREE.Mesh(geometry6, material3);
sphere6.position.set(1.25, -0.75, 0);
figure.add(sphere6)
//right hand bottom
var geometry7 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure7 = new THREE.Mesh(geometry7, material);
figure7.position.set(1.25, -1.75, 0);
figure.add(figure7);
//right hand bottom sphere
var geometry8 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere8 = new THREE.Mesh(geometry8, material3);
sphere8.position.set(1.25, -2.75, 0);
figure.add(sphere8);
//right wrist
var geometry9 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
var figure9 = new THREE.Mesh(geometry9, material);
figure9.position.set(1.25, -3.25, 0);
figure.add(figure9);
//left shoulder
var geometry10 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere10 = new THREE.Mesh(geometry10, material4);
sphere10.position.set(-1.25, 1.25, 0);
figure.add(sphere10)
//left hand top
var geometry11 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure11 = new THREE.Mesh(geometry11, material);
figure11.position.set(-1.25, 0.25, 0);
figure.add(figure11);
//left elbow
var geometry12 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere12 = new THREE.Mesh(geometry12, material3);
sphere12.position.set(-1.25, -0.75, 0);
figure.add(sphere12)
//left hand bottom
var geometry13 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure13 = new THREE.Mesh(geometry13, material);
figure13.position.set(-1.25, -1.75, 0);
figure.add(figure13);
//left hand bottom sphere
var geometry14 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere14 = new THREE.Mesh(geometry14, material3);
sphere14.position.set(-1.25, -2.75, 0);
figure.add(sphere14);
//left wrist
var geometry15 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
var figure15 = new THREE.Mesh(geometry15, material);
figure15.position.set(-1.25, -3.25, 0);
figure.add(figure15);
//left hip
var geometry16 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere16 = new THREE.Mesh(geometry16, material3);
sphere16.position.set(-0.5, -2.25, 0);
figure.add(sphere16);
//left haunch
var geometry17 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure17 = new THREE.Mesh(geometry17, material);
figure17.position.set(-0.5, -3.65, 0);
figure.add(figure17);
//left knee
var geometry18 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere18 = new THREE.Mesh(geometry18, material3);
sphere18.position.set(-0.5, -5, 0);
figure.add(sphere18);
//left shin
var geometry19 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure19 = new THREE.Mesh(geometry19, material);
figure19.position.set(-0.5, -6.35, 0);
figure.add(figure19);
//left ankle
var geometry20 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere20 = new THREE.Mesh(geometry20, material3);
sphere20.position.set(-0.5, -7.5, 0);
figure.add(sphere20);
//left foot
var geometry21 = new THREE.BoxBufferGeometry(1, 0.25, 1.5);
var figure21 = new THREE.Mesh(geometry21, material);
figure21.position.set(-0.5, -7.85, 0.25);
figure.add(figure21);
//right hip
var geometry22 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere22 = new THREE.Mesh(geometry22, material3);
sphere22.position.set(0.5, -2.25, 0);
figure.add(sphere22);
//right haunch
var geometry23 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure23 = new THREE.Mesh(geometry23, material);
figure23.position.set(0.5, -3.65, 0);
figure.add(figure23);
//right knee
var geometry24 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere24 = new THREE.Mesh(geometry24, material3);
sphere24.position.set(0.5, -5, 0);
figure.add(sphere24);
//right shin
var geometry25 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure25 = new THREE.Mesh(geometry25, material);
figure25.position.set(0.5, -6.35, 0);
figure.add(figure25);
//right ankle
var geometry26 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere26 = new THREE.Mesh(geometry26, material3);
sphere26.position.set(0.5, -7.5, 0);
figure.add(sphere26);
//right foot
var geometry27 = new THREE.BoxBufferGeometry(1, 0.25, 1.5);
var figure27 = new THREE.Mesh(geometry27, material);
figure27.position.set(0.5, -7.85, 0.25);
figure.add(figure27);
//add figure
scene.add(figure);
scene.add(new THREE.AxesHelper());
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//add grid
/* scene.add(new THREE.GridHelper(10, 20)) */
camera.position.z = 5;
//top view on object
/* camera.position.set(0, 10, 0);
camera.up.set(0, 0, -1);
camera.lookAt(0, 0, 0); */
//controls to rotate camera
controls2 = new THREE.OrbitControls(camera, renderer.domElement);
controls2.minPolarAngle = Math.PI/2;
controls2.maxPolarAngle = Math.PI/2;
//controls to drag object in 3d
/* var cubePoints = [];
cubePoints.push(figure2);
var controls = new THREE.DragControls(cubePoints, camera, renderer.domElement); */
}
//animate
function animate() {
requestAnimationFrame(animate);
render();
};
//render
function render() {
renderer.render(scene, camera);
};
To link meshes in Three.js I usually use groups (see https://threejs.org/docs/#api/en/objects/Group), I also use them to change the pivot point of a mesh by placing the mesh in a group with the wanted pivot point in the center coordinates of the group.
Of course you can nest groups for your case, like a group with the hand mesh which can be inside another group with the forearm mesh and so on.
In order to move the elbow position according to the hand position (if I get what you say right), you should use Inverse Kinematics, there are implementations for Three.js like https://github.com/jsantell/THREE.IK but I never used it so I can't tell you more about it.
Hope you solve your problem.
I'm having a problem trying to write a unit test to check collision detection. I simplify code as only this possible - I have a plane in (0, 0, 0) and I do raycasting from above this plane (from (0, 100, 0)) to bottom (0, -1, 0) and I suppose to find intersections with that plane but no luck.
console.clear();
var intersections,
from = new THREE.Vector3(0, 100, 0);
direction = new THREE.Vector3(0, -1, 0),
raycaster = new THREE.Raycaster();
var geometry = new THREE.PlaneGeometry(10, 10, 1, 1);
var ground = new THREE.Mesh(geometry);
ground.position.set(0, 0, 0);
ground.rotation.x = THREE.Math.degToRad(-90);
raycaster.set(from, direction);
intersections = raycaster.intersectObjects([ground]);
console.log(intersections);
What is wrong here? Why this simple code does not show any intersections? (r73).
jsfiddle example
You need to update the world transform of the ground mesh prior to raycasting. (Normally, the renderer does this for your in the render() call.)
console.clear();
var intersections,
from = new THREE.Vector3(0, 100, 0);
direction = new THREE.Vector3(0, -1, 0),
raycaster = new THREE.Raycaster();
var geometry = new THREE.PlaneGeometry(10, 10, 1, 1);
var ground = new THREE.Mesh(geometry);
ground.position.set(0, 0, 0);
ground.rotation.x = THREE.Math.degToRad(-90);
ground.updateMatrixWorld(); // add this
raycaster.set(from, direction);
intersections = raycaster.intersectObjects([ground]);
console.log(intersections);
three.js r.73
I want to draw a ring with the help of ExtrudeGeometry.
Ring3D = function(innerRadius, outerRadius, heigth, Segments) {
var extrudeSettings = {
amount: heigth,
bevelEnabled: false,
curveSegments: Segments
};
var arcShape = new THREE.Shape();
arcShape.moveTo(outerRadius, 0);
arcShape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);
var holePath = new THREE.Path();
holePath.moveTo(innerRadius, 0);
holePath.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);
arcShape.holes.push(holePath);
var geometry = new THREE.ExtrudeGeometry(arcShape, extrudeSettings);
var material = new THREE.MeshPhongMaterial({
color: 0x00ffff
});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = Math.PI / 2;
mesh.position.y = heigth / 2;
var object = new THREE.Object3D;
object.add(mesh);
return object;
}
The resulting figure has visible scars. And the cylinder and torus such scars not. How to get rid of them? Example here.
with geometry.computeVertexNormals();
var shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(0, 10);
shape.quadraticCurveTo(35, 30, 0, 50);
shape.lineTo(0, 60);
shape.quadraticCurveTo(48, 30, 0, 0);
var extrudeSettings = {
amount : 20,
steps : 10,
bevelEnabled: false,
curveSegments: 8
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { color: '0x804000' ,transparent: true,opacity: 0.2} ) );
scene.add( mesh );
You need to .computeVertexNormals() from your geometry. But it seems there is some issue (with a solution) explained here: https://github.com/mrdoob/three.js/issues/323. I am not sure if it will work in your case.
I have found a comment in the code of ExtrudeGeometry:
this.computeFaceNormals();
// can't really use automatic vertex normals
// as then front and back sides get smoothed too
// should do separate smoothing just for sides
//this.computeVertexNormals();
So it seems it is not supported now :(
I'm trying to make a double-sided mesh with THREE.MeshLambertMaterial, but only the front side is shaded. It works fine when I use THREE.MeshBasicMaterial. I am using the THREE.WebGLRenderer, version 57.
Here's a simplified example with a rectangle:
var rectWidth = 100, rectLength = 100;
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, rectWidth, 0));
geometry.vertices.push(new THREE.Vector3(rectLength, rectWidth, 0));
geometry.vertices.push(new THREE.Vector3(rectLength, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 0, 0));
geometry.faces.push(new THREE.Face4(0, 1, 2, 3));
// MeshBasicMaterial works
var material = new THREE.MeshLambertMaterial({
color: 0xCC0000,
side: THREE.DoubleSide,
});
geometry.computeFaceNormals();
geometry.computeVertexNormals();
var rect = new THREE.Mesh(geometry, material);
scene.add(rect);
What am I doing wrong? I found http://mrdoob.github.com/three.js/examples/webgl_performance_doublesided.html, which shows that THREE.DoubleSide works with THREE.MeshPhongMaterial (which also didn't work in my case). The example uses a built-in geometry though, whereas I am building a custom one, so I suppose I am missing something there.