Нelo! I need to find the intersection point of two ellipses in webgl (three js). Not found in documentation as can be to apply Raycaster.
I draw ellipse as:
var curve = new THREE.EllipseCurve(
x, // X
y, // Y
xRadius, // xRadius
yRadius, // yRadius
0, // aStartAngle
Math.PI*2, // aEndAngle
false, // aClockwise
0 // aRotation
);
var points = curve.getPoints( 100 );
var geometry = new THREE.BufferGeometry().setFromPoints( points );
var item = new THREE.Line( geometry, material );
scene.add( item = );
Related
I trying to get position of hole in extruded geometry. I created plane and made hole in her geometry. I want get x,y,z coordinates in center of hole. Is there some methods to get it?
Here demo: https://codepen.io/DYDOI-NSK/pen/XWqJzXG?editors=0011
Here code:
I created shape of plane
let shape = new THREE.Shape();
let width = 30;
let height = 30;
shape.moveTo(-width, height);
shape.lineTo(-width, -height);
shape.lineTo(width, -height);
shape.lineTo(width, height);
shape.lineTo(-width, height);
I created hole path and add it to shape
let hole = new THREE.Path();
hole.absarc(20, 10, 10, 0, Math.PI * 2, false) //first two argumets is x,y coord of hole
shape.holes.push(hole)
I created plane add add extruded geometry
let geometry = new THREE.PlaneGeometry( 30, 30);
let material = new THREE.MeshBasicMaterial( {color: new THREE.Color('#cea6a6'), side: THREE.DoubleSide} );
let mesh = new THREE.Mesh( geometry, material );
let newGeometry = new THREE.ExtrudeGeometry(shape, settings);
mesh.geometry.dispose()
mesh.geometry = newGeometry;
After 4 days I understand how can do it. I simple created line from mesh center to hole config position. Applied quaternion to line and got x,y,z cords of hole.
Maybe there are more optimized solutions, but it only that I could create. I will be glad if someone share more optimized solution :D
Here codepen: https://codepen.io/DYDOI-NSK/pen/XWqJzXG?editors=0011
Here code:
/*
* findCoords - function to find hole coords in 3d space
* data - parameter that require x,y of hole
*/
let findCoords = function (data) {
let vertexes = [];
//Set coords where you was created hole
let hole = new THREE.Vector3(
data.x,
data.y,
0
);
vertexes.push( new THREE.Vector3() );
vertexes.push(hole)
//Create line
const material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
const geometry = new THREE.BufferGeometry().setFromPoints( vertexes );
const line = new THREE.Line( geometry, material );
scene.add(line)
//Set line to center of mesh
line.position.copy(mesh.position)
//Rotate line like rotated mesh
line.applyQuaternion(mesh.quaternion)
//Extract hole coords from second vertex of line
let holeCoord = new THREE.Vector3()
const positionAttribute = line.geometry.getAttribute( 'position' );
holeCoord.fromBufferAttribute( positionAttribute, 1);
return holeCoord;
}
I want to find point of intersection curve and line. Created raycast, but it doesn't work well. The point of the ray is far from the actual intersection.
Webgl 1, threejs 0.109
var sartPoint = new THREE.Vector3( -30, -50, 0 );
var endPoint = new THREE.Vector3( 50, 80, 0 );
var geometry = new THREE.Geometry();
geometry.vertices.push(sartPoint);
geometry.vertices.push(endPoint);
var materialTmp = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 5 } );
var itemTmp = new THREE.Line( geometry, materialTmp );
_this.add( itemTmp, 'lines' );
scene.updateMatrixWorld()
var curve = new THREE.EllipseCurve(
0, 0, // ax, aY
10, 10, // xRadius, yRadius
0, 2 * Math.PI, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
);
var points = curve.getPoints( 10 );
var geometry = new THREE.BufferGeometry().setFromPoints( points );
var material = new THREE.LineBasicMaterial( { color : 0xff00ff } );
var ellipse = new THREE.Line( geometry, material );
scene.add( ellipse );
var raycaster = new THREE.Raycaster(sartPoint, endPoint.clone().normalize());
var intersects = raycaster.intersectObject( ellipse );
console.log(intersects);
if(intersects.length > 0){
// FIRST dot of intersect
var dotGeometry2 = new THREE.Geometry();
dotGeometry2.vertices.push(intersects[0].point);
var dotMaterial2 = new THREE.PointsMaterial( { size: 5, color: 0x00ff00 } );
var dot2 = new THREE.Points( dotGeometry2, dotMaterial2 );
_this.add( dot2, 'points' );
}
The second argument to the Raycaster constructor is a direction vector. Instead of:
endPoint.clone().normalize()
I think you want:
endPoint.clone().sub(startPoint).normalize()
It is work if
curve.getPoints( 10 );
When
curve.getPoints( 100 );
That doesn't work.
Does changing the value of an object's rotation property rotate the object about the world axes or the object's axes? For eg
object.rotation.x += 2
Will this rotate the object about the world X axis or the object's X axis?
I tried the following example :
var materials = [];
materials.push( [ new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ] );
materials.push( [ new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ] );
materials.push( [ new THREE.MeshBasicMaterial( { color: 0x00ff00 } ) ] );
materials.push( [ new THREE.MeshBasicMaterial( { color: 0x00ff00 } ) ] );
materials.push( [ new THREE.MeshBasicMaterial( { color: 0x0000ff } ) ] );
materials.push( [ new THREE.MeshBasicMaterial( { color: 0x0000ff } ) ] );
object = new THREE.Mesh( new THREE.CubeGeometry( 20, 20, 20, 1, 1, 1, materials ), new THREE.MeshFaceMaterial() );
object.position.x = 0;
object.position.y = 0;
object.position.z = 0;
object.rotation.x = 0;
object.rotation.y = 0;
object.rotation.z = 0;
object.scale.x = 1;
object.scale.y = 1;
object.scale.z = 1;
scene.add( object );
After i have added the object to the scene i tried the following -
object.rotation.x += Math.PI/4;
object.rotation.y += Math.PI/4;
object.rotation.z += Math.PI/4;
Until now the object rotates with respect to its own X,Y and Z axes.
but doing:
object.rotation.x += Math.Pi/4;
now rotates the object 45 degrees about the World X axis instead of the object's X axis.
The rotations are in local space. However, they are evaluated in a specific order which you can set yourself. The object.rotation property is an Euler, and as you can read in the description of the order-property:
The order in which to apply rotations. Default is 'XYZ', which means
that the object will first be rotated around its X axis, then its Y
axis and finally its Z axis. Other possibilities are: 'YZX', 'ZXY',
'XZY', 'YXZ' and 'ZYX'. These must be in upper case.
Three.js uses intrinsic Tait-Bryan angles. This means that rotations
are performed with respect to the local coordinate system. That is,
for order 'XYZ', the rotation is first around the local-X axis (which
is the same as the world-X axis), then around local-Y (which may now
be different from the world Y-axis), then local-Z (which may be
different from the world Z-axis).
(Emphasis added by me).
Consider the following example, every cube is updated with the same y-axis rotation. In every case the rotation is happening around the y-axis in local space, but:
The first cube has not been rotated in any other axis, making its
local space axis the same as the world space axis.
The second cube has been rotated around its x-axis, which means that
the y-axis is also rotated.
The third cube has also been rotated, but the order of rotation is
changed so that the y-axis rotation happens first, while it is still the same as the world y-axis, and the rotation around x happens afterward.
const canvas = document.getElementById("canvas");
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(10, 2, 20, 40);
const renderer = new THREE.WebGLRenderer({ canvas });
const light = new THREE.PointLight();
light.position.set(0, 5, 10)
scene.add(light);
camera.position.set(0, 0, 25);
const material = new THREE.MeshLambertMaterial();
const geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
const cube1 = new THREE.Mesh(geometry, material);
const cube2 = new THREE.Mesh(geometry, material);
const cube3 = new THREE.Mesh(geometry, material);
cube1.position.set(-2, 0, 0);
cube2.position.set( 0, 0, 0);
cube3.position.set( 2, 0, 0);
scene.add(cube1);
scene.add(cube2);
scene.add(cube3);
//The first cube is not rotated
cube1.rotation.set(0, 0, 0);
//The second cube is rotated pi/4 rad around X
cube2.rotation.set(Math.PI/4, 0, 0);
//The third cube is rotated pi/4 rad around X
//AND the rotation order is set to YXZ to make the y-rotation happen first
cube3.rotation.set(Math.PI/4, 0, 0);
cube3.rotation.order = "YXZ";
let t0 = performance.now();
function update(){
const t1 = performance.now();
const rotation = 0.001 * (t1 - t0);
cube1.rotation.y += rotation;
cube2.rotation.y += rotation;
cube3.rotation.y += rotation;
renderer.render(scene, camera);
t0 = t1;
requestAnimationFrame(update);
}
update();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>
<canvas id="canvas" width="400" height="200"></canvas>
I want to create a "U" shaped magnet in three.js. So can I use TubeGeometry for that?
So if this is the code for creating a 3D sin curve. How can I make it as "U" shaped Magnet?
var CustomSinCurve = THREE.Curve.create(
function ( scale ) { //custom curve constructor
this.scale = ( scale === undefined ) ? 1 : scale;
},
function ( t ) { //getPoint: t is between 0-1
var tx = t * 3 - 1.5;
var ty = Math.sin( 2 * Math.PI * t );
var tz = 0;
return new THREE.Vector3( tx, ty, tz ).multiplyScalar(this.scale);
}
);
var path = new CustomSinCurve( 10 );
var geometry = new THREE.TubeGeometry( path, 20, 2, 8, false );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
If the shape of the magnet's profile is not critical (rectangle instead of circle), then you can use THREE.ExtrudeGeometry():
var path = new THREE.Shape(); // create a U-shape with its parts
path.moveTo(-1, 1);
path.absarc(0, 0, 1, Math.PI, Math.PI * 2);
path.lineTo(1, 1);
path.lineTo(.8, 1);
path.absarc(0, 0, .8, Math.PI * 2, Math.PI, true);
path.lineTo(-.8,1);
path.lineTo(-1, 1);
var extOpt = { // options of extrusion
curveSegments: 15,
steps: 1,
amount: .2,
bevelEnabled: false
}
var uGeom = new THREE.ExtrudeGeometry(path, extOpt); // create a geometry
uGeom.center(); // center the geometry
var average = new THREE.Vector3(); // this variable for re-use
uGeom.faces.forEach(function(face){
average.addVectors(uGeom.vertices[face.a], uGeom.vertices[face.b]).add(uGeom.vertices[face.c]).divideScalar(3); // find the average vector of a face
face.color.setHex(average.x > 0 ? 0xFF0000 : 0x0000FF); // set color of faces, depends on x-coortinate of the average vector
});
var uMat = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors }); // we'll use face colors
var u = new THREE.Mesh(uGeom, uMat);
scene.add(u);
jsfiddle example
I need to apply a texture on a ExtrudeGeometry object.
The shape is a circle and the extrude path is composed of 2 vectors :
One for the top.
One for the bottom.
I didn't choose cylinderGeometry because I need to place top/bottom sections of my geometry at precise positions and because the geometry created will not be always purely vertical (like a oblique cylinder for example).
Here is a picture of a section (one top vector, one bottom vector and a shape extruded between these 2 vectors).
and a picture of the texture I'm trying to apply.
All I want to do is to wrap this picture on the vertical sides of my object just one time.
Here is my code :
var biVectors = [ new THREE.Vector3( this.startVector.x, this.startVector.y, this.startVector.z ) , new THREE.Vector3( this.endVector.x, this.endVector.y, this.endVector.z ) ];
var wellSpline = new THREE.SplineCurve3(biVectors);
var extrudeSettings = {
steps : 1,
material: 0,
extrudeMaterial: 1,
extrudePath : wellSpline
};
var pts = [];
for (var i = 0; i <= this.segments; i++) {
var theta = (i / this.segments) * Math.PI * 2;
pts.push( new THREE.Vector3(Math.cos(theta) * this.diameter , Math.sin(theta) * this.diameter, 0) );
}
var shape = new THREE.Shape( pts );
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var texture = THREE.ImageUtils.loadTexture( 'textures/sampleTexture2.jpg' );
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.flipY = false;
var material = new THREE.MeshBasicMaterial( { map: texture } );
var slice = new THREE.Mesh( geometry, material );
var faceNormals = new THREE.FaceNormalsHelper( slice );
console.log("face normals: ", faceNormals);
myCanvas.scene.add( faceNormals );
slice.parentObject = this;
myCanvas.scene.add( slice );
this.object3D = slice;
}
Now, as you can see, the mapping is not correct at all.
I've read a lot of information about this problem the last 3 days. But I'm running out of options as I'm new to THREE.JS.
I think I have to redefine the UV coordinates but I have no clue how to do this.
It seems that wrapping a texture on a cylinder like object is anything but easy in THREE.JS.
Can someone please help me on this issue ?