RingGeometry rotate in three.js - three.js

I followed a example to create a planet ring with the following code.
createRing(){
const TEXTURE_PATH = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/123879/';
let loader = new THREE.TextureLoader();
loader.setCrossOrigin( 'https://s.codepen.io' );
var ringTexture = loader.load( TEXTURE_PATH + 'saturnrings.png' );
let saturnRadius = 0.98;
var ringGeometry = new THREE.RingGeometry(1.4 * saturnRadius, 2.5 * saturnRadius, 2 * 32, 5, 0, Math.PI * 2);
var ringMaterial = new THREE.MeshBasicMaterial({
map: ringTexture,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.7,
});
var ring = new THREE.Mesh( ringGeometry, ringMaterial );
scene.add(ring);
}
the code works to show a planet and planet ring as shown in the image below.
then I tried to rotate the ring with the code,
ring.rotation.set(new THREE.Vector3( Math.PI / 2, 0, 0 ));
however the ring just disappear with only the planet left.
what goes wrong with it

Related

Connecting two components in Three.js

I would like to build something that allows the connection of two components, kind of like a guitar cable will plug into an amp from a guitar. So I want to connect to one point, and then drag the connection to a second point and have there be some natural hang in the rope. I made this example from a previous SO question (Three.js rope / cable effect - animating thick lines), but I can't seem to get the calculation right. So the question would be, how would I be able to make a function with this signature:
function drawSpline(startPoint, endPoint, ropeLength) {
// returns a new THREE.Line object with a natural curvature for "slack" in the rope between the two points
}
This is what I have so far:
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
scene.add(camera);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
const RADIUS = 1;
const SEGMENTS = 16;
const RINGS = 16;
const sphereMaterial =
new THREE.MeshLambertMaterial(
{
color: 0xCC0000
});
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(
RADIUS,
SEGMENTS,
RINGS),
sphereMaterial);
sphere.position.z = 0;
const pointLight =
new THREE.PointLight(0xFFFFFF);
// set its position
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// add to the scene
scene.add(pointLight);
const shiftRatio = 7.5;
scene.add(drawSpline({x: 0, y: -3, z: 0}, {x: 6, y: 1, z: 0}, 'blue'));
function drawSpline(beginning, end, clr){
let ySign = Math.sign((end.y + beginning.y) / 2)
let appliedRatio = shiftRatio;
let midVector = new THREE.Vector3( (end.x + beginning.x) / 8, (end.y+beginning.y)/2, (end.z+beginning.z)/ 2 )
let positionVector = new THREE.Vector3(0,end.y-beginning.y,end.z-beginning.z)
let orthogVector = new THREE.Vector3(0,positionVector.z,-positionVector.y).normalize()
var curve = new THREE.CatmullRomCurve3( [
new THREE.Vector3( beginning.x, beginning.y, beginning.z ),
midVector.clone().addScaledVector(orthogVector,ySign*appliedRatio),
new THREE.Vector3( end.x, end.y, end.z ),
]);
var points = curve.getPoints( 20 );
console.log(points);
var geometry = (new THREE.BufferGeometry()).setFromPoints( points );
var material = new THREE.LineBasicMaterial( { color : clr } );
// Create the final object to add to the scene
var curveObject = new THREE.Line( geometry, material );
return curveObject;
}

Ray does not accurately determine the intersection

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.

U-shaped magnet geometry in three.js

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

ThreeJS raycasting is different in R81 than R71

I have a plane with a mesh on it. My code draws a ball when the user double clicks on the mesh. This works just fine in R71 but as soon as I switched to R81 raycaster doesn't return an intersect. Here's the code:
In init():
// Plane
plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry( 1000, 1000, 3, 3 ),
new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: .5, transparent: true } )
);
plane.visible = false;
scene.add( plane );
planes.push(plane);
In doubleClickEvent():
event.preventDefault();
var mouse = new THREE.Vector2((event.clientX / window.innerWidth ) * 2 - 1, -(((event.clientY / window.innerHeight ) * 2 - 1)));
var directionVector = new THREE.Vector3();
directionVector.set(mouse.x, mouse.y, 0.1);
directionVector.unproject(camera);
directionVector.sub(camera.position);
directionVector.normalize();
raycaster.set(camera.position, directionVector);
intersects = raycaster.intersectObjects(planes);
if (intersects.length) {
var sphereParent = new THREE.Object3D();
var sphereGeometry = new THREE.SphereGeometry(.1, 16, 8);
var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphereParent.add(sphere);
sphereParent.position.set(intersects[0].point.x, intersects[0].point.y, 0.0);
scene.add(sphereParent);
objects.push(sphereParent);
}
If I change
intersects = raycaster.intersectObjects(planes);
to
intersects = raycaster.intersectObjects(scene.children);
the ball gets drawn but it gets drawn on the wrong position.
Any ideas?
I found the answer. The reason why the raycast isn't working is because the plane's visibility is false. The solution is to change the visibility of the material visibility rather the plane.

Three.js - Cube and sphere clipping strangely with plane

I'm having an issue where it looks like the cube and sphere are clipping with the plane. It seems to happen when I move the cube (using the keyboard) toward the back of the scene. It also happens when I use the trackball controls to move around the scene. Sometimes the cube and sphere are visible even when I turn the camera so I am looking at the bottom of the plane.
Some code that might be of use, contains camera variables, creation of plane, sphere, and cube. I have images too: http://imgur.com/0VlZLmP
//CAMERA
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45;
var ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT;
var NEAR = 0.1;
var FAR = 20000;
//Renderer
ShapeShifter.renderer = new THREE.CanvasRenderer();
//Sphere
var sphereGeometry = new THREE.SphereGeometry( 50, 32, 16 );
var sphereMaterial = new THREE.MeshLambertMaterial( { color: 0x8888FF, overdraw: true } );
ShapeShifter.sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
ShapeShifter.sphere.position.set( 100, 50, -10 );
ShapeShifter.scene.add( ShapeShifter.sphere );
//Cube
var cubeGeometry = new THREE.CubeGeometry( 50, 50, 50 );
var cubeMaterial = new THREE.MeshBasicMaterial( { color: 0xFF4422 } );
ShapeShifter.cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
ShapeShifter.scene.add( ShapeShifter.cube );
ShapeShifter.cube.position.set( -40, 50, 200 );
//Floor
var floorGeometry = new THREE.PlaneGeometry( 1000, 1000 );
var floorMaterial = new THREE.MeshBasicMaterial( { color: 0x4DBD33, overdraw: true } );
ShapeShifter.floor = new THREE.Mesh( floorGeometry, floorMaterial );
ShapeShifter.floor.material.side = THREE.DoubleSide;
ShapeShifter.floor.position.y = 0;
ShapeShifter.floor.rotation.x = Math.PI / 2;
ShapeShifter.scene.add( ShapeShifter.floor );
This is a known limitation of CanvasRenderer.
You can reduce these artifacts by increasing the tessellation of your geometry -- particularly the plane.
var floorGeometry = new THREE.PlaneGeometry( 1000, 1000, 10, 10 ); // will help
var cubeGeometry = new THREE.CubeGeometry( 50, 50, 50, 2, 2, 2 ); // may help

Resources