Three.js: Rotate Cylinder into Vector3 direction - javascript

I've already searched, but didn't find anything that helps:
I got an vector and a CylinderGeometry Mesh. I want to acchieve, that the cylinder is facing the point where the vector is showing. As input I got a position (c) and a direction (m) (like a line equation: y = mx + c):
function draw (m,c, _color) {
//... create the geometry and mesh
// set the position
line.position.x = c.x;
line.position.y = c.y;
line.position.z = c.z;
// i've tried something like this:
line.lookAt(c.add(m));
//.. and add to scene
}
But it looks like the direction is the direct opposite of what I want to acchieve.
I've also tried stuff like translation:
geometry.applyMatrix( new THREE.Matrix4().makeTranslation(0, length/2, 0));
and tried to get the rotation manually like line.rotation.x = direction.angleTo(vec3(1,0,0))* 180 / Math.PI;. But none of them worked like I needed.

This works for me:
// Make the geometry (of "distance" length)
var geometry = new THREE.CylinderGeometry( 0.6, 0.6, distance, 8, 1, true );
// shift it so one end rests on the origin
geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, distance / 2, 0 ) );
// rotate it the right way for lookAt to work
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( THREE.Math.degToRad( 90 ) ) );
// Make a mesh with the geometry
var mesh = new THREE.Mesh( geometry, material );
// Position it where we want
mesh.position.copy( from.sceneObject.position );
// And make it point to where we want
mesh.lookAt( to.sceneObject.position );

Related

Three.js - Strange lines on custom mesh

I'm trying to make a custom mesh in order to have a lot of customizable planes in the scene.
Here is some code:
geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertexPositions, 3 ).setDynamic( true ) );
geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).setDynamic( true ) );
geometry.addAttribute( 'opacity', new THREE.BufferAttribute( opacity, 1 ).setDynamic( true ) );
// Initialize material
var material = new THREE.ShaderMaterial( { vertexColors: THREE.VertexColors, transparent: true, vertexShader: vertexShader, fragmentShader: fragmentShader } );
// Create something like a Wireframe of the planes
var Pgeometry = new THREE.BufferGeometry();
Pgeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( ApointsPositions ), 3 ).setDynamic( true ) );
var points = new THREE.LineSegments( Pgeometry, new THREE.PointsMaterial( { color: 0x353535 } ) );
scene.add( points );
// Create planes and add to scene
planeMeshes = new THREE.Mesh( geometry, material );
planeMeshes.setDrawMode( THREE.TriangleStripDrawMode );
scene.add( planeMeshes );
My custom material is working fine and let me to use opacity on every vertex. Every plane is created and everything works fine.
The problem is that, when I render the scene, there are some strange lines on every planes row, here's a full working Codepen: Codepen link
Do you see those diagonal lines there? Are you able to tell me what's happening? I didn't find their origin.
Thank you in advance!
The reason you're seeing diagonals is because you're using THREE.TriangleStripDrawMode, so the rightmost triangles share vertices with the leftmost triangles of the next row. You're seeing a really stretched out triangle cut across.
To solve this, get rid of the line where you're assigning TriangleStripDrawMode, which will go back to the default of three vertices per triangle (no sharing of vertices).
Problem 2:
The first triangle on each iteration is being drawn in a clockwise order, but the second triangle on each iteration is being drawn in a counter-clockwise order, so you will not see the second one unless you change the vertex order to be clockwise.
Here's how you have it in your Codepen:
// Second tri is drawn counter-clockwise
AvertexPositions.push( x, y + 60, 0 ); //
AvertexPositions.push( x + 80, y + 60, 0 ); // Second triangle of a plane
AvertexPositions.push( x + 80, y, 0 );
This is how it should be:
// Now, it is clockwise, matching first tri
AvertexPositions.push( x, y + 60, 0 ); //
AvertexPositions.push( x + 80, y, 0 ); //
AvertexPositions.push( x + 80, y + 60, 0 ); // Second triangle of a plane
It is important to draw all your triangles in the same winding order. Otherwise, some will be facing forward, and some will be facing backward. You can choose which side gets rendered, or render both sides with Materials.Side

How to make a object follow the direction of the PointerLockControls in Three.js?

I am using Three.js and PointerLockControls to create simple FPS game. What I am trying to do is to attach a weapon to the camera/controls.
I was able to position the gun in front of the camera and move it along on the x/y axis, but it does not move along the z axis (up/down).
function updateGun() {
if (weapon) {
const yaw = controls.getObject();
weapon.position.set(
yaw.position.x - Math.sin(yaw.rotation.y) * 3,
yaw.position.y - 1,
yaw.position.z - Math.cos(yaw.rotation.y) * 3);
weapon.rotation.set(
yaw.rotation.x,
(yaw.rotation.y - Math.PI),
yaw.rotation.z);
}
}
If you are using PointerLockControls and want to add an object that remains in front of the camera, you can use this pattern:
var mesh = new THREE.Mesh( new THREE.SphereGeometry( 5, 16, 8 ), new THREE.MeshNormalMaterial() );
mesh.position.z = - 100; // some negative number
camera.add( mesh );
If you are not using PointerLockControls, you can still use the same technique, you just have to be sure to add the camera as a child of the scene.
scene.add( camera );
camera.add( mesh );
three.js r.84

Circular radius intersection (like a circular cursor brush) - Three js

I'd like to be able to catch the faces of an object in the radius of a circular cursor (like in painting/photoshop).
I'll show you what is it for https://jsfiddle.net/Shaggisu/w7ufmutr/9/
I'd want be able to selct not only the single face that in the moment intersects with the mouse point but all faces that might be in the circular radius, I tried to uplod some image for that cursor but cant really make it work with external files in jsfiddle.
My question is, if is there some standard method of achieving multiple selection/intersection in a specified radius or should I devised some code that would for example reiterate on suroundin faces around the mouse point in specific moment.
I'm still quite new to three.js so I would ask for some directions to go with it, and especialy if there are some solid ways to achieve, any tip would be helpful too.
var brushTexture = THREE.ImageUtils.loadTexture( '/cur_circle.png' );
var brushMaterial = new THREE.SpriteMaterial( { map: brushTexture, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.center } );
brushSprite = new THREE.Sprite( brushMaterial );
brushSprite.scale.set( 32, 32, 1.0 );
brushSprite.position.set( 50, 50, 0 );
scene.add( brushSprite );
//////////////////////////////////////////////////////////////////////
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// when the mouse moves, call the given function
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}
function onDocumentMouseDown( event )
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
console.log("Click.");
// update the mouse variable
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// find intersections
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( targetList );
// if there is one (or more) intersections
if ( intersects.length > 0 )
{
controls.enabled = false; // stops camera rotation
console.log("Hit # " + toString( intersects[0].point ) );
// change the color of the closest face.
intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 );
intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
}
}
function onDocumentMouseMove( event){
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
brushSprite.position.set( event.clientX, event.clientY, 0);
// find intersections
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( targetList );
// if there is one (or more) intersections
if ( intersects.length > 0 )
{
console.log("Hit # " + toString( intersects[0].point ) );
// change the color of the closest face.
intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 );
intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
}
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
}
function onDocumentMouseUp( event){
event.preventDefault();
document.removeEventListener( "mousemove", onDocumentMouseMove);
controls.enabled = true;
}
The code is modified version of the stemkoskis github that I used for practice.
I have already extended it somewhat for camera management in intersection events and continous selection, but the selection of multiple faces in a radius is what interests me now the most.
You can do this in javascript, modifying vertex color, like you do it in your sample but you will be quickly limited by the number of polygon.
That said, consider your brush like a cone, which start from the Ray.origin and extend in Ray.direction. The radius of the cone is driven by the radius of your brush.
Iterate over each vertices.
For each, get the minimum distance between the vertex to the Ray line.
Get the radius of the brush/cone based on the distance between this vertex and the Ray.origin
If the minimum distance is inferior to the cone radius, your vertex is "in". You can also handle the distance to create a smooth brush.
It should looks like this, it kind of pseudo code, you may need to adapt to ThreeJs Math lib:
// Important, Ray origin and direction must be defined in the same space a vertices positions
// You may need to transform ray origin and direction in object local space.
// get the length of Ray.direction
// may be useless if 'direction' is normalized
var rayDirLenSq = ray.direction.length();
rayDirLenSq *= rayDirLenSq;
var brushRadius = 10.0;
for( var i=0;i< vertices.length;i++){
// get the vertex
var v = vertices[i];
var vdir = v.sub( ray.origin );
var dot = vdir.dot( ray.direction ) / rayDirLenSq;
if( dot < 0 ){
// handle vertices behind the camera if needed
}
// v2 : projection of the vertex onto ray line
var v2 = ray.direction.clone().multiplyScalar( dot );
// v3 : projection -> vertex
var v3 = vdir.subtract( v2 )
// dist is the distance between the vertex and the ray line
var dist = v3.length()
// 0 when vertex is at the brush border
// 1 when vertex is in the brush center
var paintingFactor = Math.max(0.0, 1.0 - dist/brushRadius )
}
Depending of what you want, you can store the painting factor of each vertices to get a mean factor per faces. Or you can modify vertex color of each vertices independantly to get gradients on your faces...
I didn't test the code, it may contain some mistakes :)
A more advanced method
You could also use a texture to paint on. You will get rid of vertex (and javascript) limitations. You will be able to paint with textured brushes, and have detail inside a triangle (no more vertex color).
The principle :
You need UVs datas and a texture + FBO for each of your meshes.
In a prepass, for each mesh, render it to it's Fbo in it's uvs coords
gl_Position = vec4( UVs*2.0-1.0, 0.0, 1.0 );
Provide the worldSpace vertex position to fragment shader, so you can access the world space position of each pixel of the object texture.
vVertexPosition = modelMatrix * aPosition;
With vVertexPosition in your fragment shader, you can then use the same method as the javascript one to get the brushFactor of each pixels of your mesh.
You can even project this world space pixel position in a custom projection matrix based on the Ray to get the uvs coordinate of the pixel in a brush texture, and paint with textured brush.

ThreeJS bufferGeometry position attribute not updating when translation applied

I used STLLoader to load an stl onto a threeJS scene returning a BufferGeometry.
I then used
myMesh.position.set( x,y,z )
myMesh.rotation.setFromQuaternion ( quaternion , 'XYZ');
to translate the geometry. This effectively changes the
myMesh.position
myMesh.quaternion
Translation is happening in the scene and all works well.
I expected that the
myMesh.geometry.attributes.position.array
would be different before and after the translation - but it remained identical. I want to extract the new veritces from the buffergeometry after translation.
I tried to call
myMesh.geometry.dynamic = true;
myMesh.geometry.attributes.position.needsUpdate = true;
in the render loop but no luck as I haven't updated the vertices explicity.
You want to get the world position of a mesh's geometry, taking into consideration the mesh's transform matrix, mesh.matrix. Also, your mesh geometry is THREE.BufferGeometry.
Here is the pattern to follow:
mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 10, 10, 10 );
mesh.rotation.set( - Math.PI / 2, 0, 0 );
mesh.scale.set( 1, 1, 1 );
scene.add( mesh );
mesh.updateMatrix(); // make sure the mesh's matrix is updated
var vec = new THREE.Vector3();
var attribute = mesh.geometry.attributes.position; // we want the position data
var index = 1; // index is zero-based, so this the the 2nd vertex
vec.fromAttribute( attribute, index ); // extract the x,y,z coordinates
vec.applyMatrix4( mesh.matrix ); // apply the mesh's matrix transform
three.js r.71

Three.js cylinder rotation in 3d plane

Ive been having the linewidth problem (something to do with ANGLE on window). I have resorted to using cylinders between 2 points (in 3D space). I have already solved the issue on getting the length of the cylinder based on the 2 points-3D distance formula.
I have been having trouble however getting the angle. I want the cylinder to rotate so that the angle found will make it so that the cylinder connects the two points.
Essensially I am trying to find a way to find the angle between (x1,y1,z1) and (x2,y2,z2). And having it modify a cylinder (cylinder.rotation.x, cylinder.rotation.y, and cylinder.rotation.z).
You can use a transformation matrix to do that. Here's some example code:
function createCylinderFromEnds( material, radiusTop, radiusBottom, top, bottom, segmentsWidth, openEnded)
{
// defaults
segmentsWidth = (segmentsWidth === undefined) ? 32 : segmentsWidth;
openEnded = (openEnded === undefined) ? false : openEnded;
// Dummy settings, replace with proper code:
var length = 100;
var cylAxis = new THREE.Vector3(100,100,-100);
var center = new THREE.Vector3(-100,100,100);
////////////////////
var cylGeom = new THREE.CylinderGeometry( radiusTop, radiusBottom, length, segmentsWidth, 1, openEnded );
var cyl = new THREE.Mesh( cylGeom, material );
// pass in the cylinder itself, its desired axis, and the place to move the center.
makeLengthAngleAxisTransform( cyl, cylAxis, center );
return cyl;
}
// Transform cylinder to align with given axis and then move to center
function makeLengthAngleAxisTransform( cyl, cylAxis, center )
{
cyl.matrixAutoUpdate = false;
// From left to right using frames: translate, then rotate; TR.
// So translate is first.
cyl.matrix.makeTranslation( center.x, center.y, center.z );
// take cross product of cylAxis and up vector to get axis of rotation
var yAxis = new THREE.Vector3(0,1,0);
// Needed later for dot product, just do it now;
// a little lazy, should really copy it to a local Vector3.
cylAxis.normalize();
var rotationAxis = new THREE.Vector3();
rotationAxis.crossVectors( cylAxis, yAxis );
if ( rotationAxis.length() < 0.000001 )
{
// Special case: if rotationAxis is just about zero, set to X axis,
// so that the angle can be given as 0 or PI. This works ONLY
// because we know one of the two axes is +Y.
rotationAxis.set( 1, 0, 0 );
}
rotationAxis.normalize();
// take dot product of cylAxis and up vector to get cosine of angle of rotation
var theta = -Math.acos( cylAxis.dot( yAxis ) );
//cyl.matrix.makeRotationAxis( rotationAxis, theta );
var rotMatrix = new THREE.Matrix4();
rotMatrix.makeRotationAxis( rotationAxis, theta );
cyl.matrix.multiply( rotMatrix );
}
I didn't write this. Find the full working sample here.
It's part of Chapter 5: Matrices from this awesome free Interactive 3D Graphics course taught using three.js.
I warmly recommend it. If you didn't have a chance to play with transformations you might want to start with Chapter 4.
As a side note. You can also cheat a bit and use Matrix4's lookAt() to solve the rotation, offset the translation so the pivot is at the tip of the cylinder, then apply the matrix to the cylinder.

Categories

Resources