How to create tubes efficiently in three.js - three.js

I'm struggling to make tubes in THREE.js and there are very few tutorials on them so I decided to ask here. How can I create a tube without using this difficult piece of code taken from the official docs?
class CustomSinCurve extends THREE.Curve {
constructor( scale = 1 ) {
super();
this.scale = scale;
}
getPoint( t, optionalTarget = new THREE.Vector3() ) {
const tx = t * 3 - 1.5;
const ty = Math.sin( 2 * Math.PI * t );
const tz = 0;
return optionalTarget.set( tx, ty, tz ).multiplyScalar( this.scale );
}
}
Preferably with the use of bezier curves or something intuitive.
(To be clear, I'm using React-three-fiber to create these models but I know how to convert vanilla THREE.js to it.)

Try it like so:
let mesh;
let camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 4;
scene = new THREE.Scene();
const curve = new THREE.QuadraticBezierCurve3(new THREE.Vector3(-1, -1, 0), new THREE.Vector3(-1, 1, 0), new THREE.Vector3(1, 1, 0))
const geometry = new THREE.TubeGeometry(curve);
const material = new THREE.MeshNormalMaterial({
side: THREE.DoubleSide
});
mesh = new THREE.Mesh(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 animate() {
requestAnimationFrame(animate);
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.133.1/build/three.min.js"></script>
The example code uses a simple quadratic bezier curve in order to generate the tube's shape.

Related

three.js Rotate 3d model left and right slowly

i'm trying to learn threejs but i've some difficult to understand how to rotate my 3d model.
now i'm able to rotate my model in a loop...but this is not what i want
i want to rotate my model a little bit to the right and then again a little bit to the left (in loop)..not at 360°.
or better ROTATE with mouse movement!
my code so far:
let container;
let camera;
let renderer;
let scene;
let computer;
function init(){
container = document.querySelector('.scene');
//creazione scena
scene = new THREE.Scene();
const fov = 35;
const aspect = container.clientWidth / container.clientHeight;
const near = 0.1;
const far = 1000;
// setup camera
camera = new THREE.PerspectiveCamera(fov,aspect,near,far);
camera.position.set(0,2.8, 11);
// luci ambiente
const ambient = new THREE.AmbientLight(0x404040,3);
scene.add(ambient);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1,1,0);
scene.add(light)
// renderer
renderer = new THREE.WebGLRenderer({antialias:true, alpha:true});
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(renderer.domElement);
// caricamento modello 3d
let loader = new THREE.GLTFLoader();
loader.load('./3d/scene.gltf', function (gltf){
scene.add(gltf.scene);
computer = gltf.scene.children[0];
animate()
})
}
function animate(){
requestAnimationFrame(animate);
computer.rotation.z += 0.003;
computer.rotation.x = -1.2;
computer.position.y = -10
renderer.render(scene,camera);
}
init()
function onWindowResize(){
camera.aspect = container.clientWidth / container.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
}
window.addEventListener("resize", onWindowResize);
As an option, use mouse position in NDC to slightly rotate your model:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.135.0";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
let g = new THREE.CylinderGeometry(1, 2, 3, 4);
let m = new THREE.MeshNormalMaterial();
let o = new THREE.Mesh(g, m); // let's suppose it's your model
scene.add(o);
window.addEventListener("pointermove", event => {
let xMove = ( event.clientX / window.innerWidth ) * 2 - 1; // from the docs of Raycaster
if (o) { // in case you load a model, you need to check if it's not null or undefined
o.rotation.y = xMove * Math.PI * 0.1;
}
});
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
</script>

Create cone geometry with flat base in three.js?

Trying to figure out how to create something that looks like the image below... Tried searching around but couldn't really figure it out...
Try it with CylinderGeometry. This class allows to define different radii for the top and bottom.
let mesh;
let camera, scene, renderer;
init();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 2;
scene = new THREE.Scene();
const geometry = new THREE.CylinderGeometry(0.2, 0.5, 1, 16);
const material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animation);
document.body.appendChild(renderer.domElement);
}
function animation(time) {
mesh.rotation.x = time / 2000;
mesh.rotation.y = time / 1000;
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.133.1/build/three.min.js"></script>

looking to rotate a object by using the pivot point of another object

I have a 2 objects(A and B) which respectively have 2 positions.
I am trying to revolve the object B around the object A.
so my idea is to take the center of object A and Make object B to rotate around it in a circular direction and would like to know the position of B while it is revolving around
here is a graphical representation
I suggest you use an instance of THREE.Group as a pivot object. You can add object B to this object and transform it like demonstrated in the following live example.
The position of the object B in world space can be extracted from the world matrix via Vector3.setFromMatrixPosition().
let camera, scene, renderer;
let objectB, pivot;
const worldPosition = new THREE.Vector3();
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 2;
scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshNormalMaterial();
const objectA = new THREE.Mesh(geometry, material);
scene.add(objectA);
pivot = new THREE.Group();
scene.add(pivot);
objectB = new THREE.Mesh(geometry, material);
objectB.scale.setScalar(0.5);
objectB.position.x = 1;
pivot.add(objectB);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
pivot.rotation.y += 0.01;
// pivot.updateMatrixWorld(); // ensure world matrix is up to date
// console.log( worldPosition.setFromMatrixPosition( objectB.matrixWorld ) );
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.124/build/three.js"></script>

3D Objects appearing as flat in three.js

I just setup a very basic "hello world" for three.js…
But apparently my 3d cube is appearing as a 2d square…
The code to the js file is here
const t = THREE;
const scene = new t.Scene();
const camera = new t.PerspectiveCamera(75, window.innerWidth, window.innerHeight, 0.1, 1000);
const renderer = new t.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// create a shape
const geometry = new t.BoxGeometry(1, 1, 1);
// create a material
const material = new t.MeshBasicMaterial({color: 0xFFFFFF, wireframe: true});
const cube = new t.Mesh(geometry, material);
// cube.position.y = 1;
scene.add(cube);
// camera.position.x = 300;
camera.position.z = 5;
// logic
const update = function () {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
};
// draw scene
const render = function () {
renderer.render(scene, camera);
};
// run render loop (update-render-repeat)
const RenderLoop = function () {
window.requestAnimationFrame(RenderLoop);
update();
render();
};
RenderLoop();
And the result of the code is here
Any help is appreciated!
EDIT:
Sorry for not including the code
You're building your PerspectiveCamera wrong:
Your way:
PerspectiveCamera(75, window.innerWidth, window.innerHeight, 0.1, 1000);
Correct way:
PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
You need to pass the ratio w/h, not two separate w, h arguments.

Basic THREE.js scene setup

my question is simple but for the life of me i cannot figure out what is going on. I am trying to set up a basic three.js scene and add a simple cube with a BaiscMaterial however the cube is not showing up in my scene.
"use strict";
var renderer, scene, camera;
var light;
function init() {
var canvasWidth = 850;
var canvasHeight = 450;
var canvasRatio = canvasWidth / canvasHeight;
camera = new THREE.PerspectiveCamera(45, canvasRatio, 0.9, 1000);
camera.position.set(0, 200, -550);
camera.lookAt(0, 0, 0);
light = new THREE.AmbientLight(0xFFFFFF, 1);
light.position.set(-800, 900, 300);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(canvasWidth, canvasHeight);
renderer.setClearColorHex(0x000000, 1.0); //canvas color
renderer.gammaInput = true;
renderer.gammaOutput = true;
}
function cube() {
var cubeGeo = new THREE.CubeGeometry(1000, 1000, 1000);
var cubeMaterial = new THREE.MeshBasicMaterial();
var cube1 = new THREE.Mesh(cubeGeo, cubeMaterial);
cube1.position.set(0, 0, 0);
return cube1;
}
function fillScene() {
scene = new THREE.Scene();
scene.add(light);
var cube = cube();
scene.add(cube);
}
function addToDOM() {
var container = document.getElementById('container');
var canvas = container.getElementsByTagName('canvas');
if (canvas.length > 0) {
container.removeChild(canvas[0]);
}
container.appendChild(renderer.domElement);
}
function render() {
fillScene();
renderer.render(scene, camera);
}
try {
init();
fillScene();
addToDOM();
render();
} catch (e) {
var errorReport = "Your Program encountered an ERROR, cannot draw on canvas. Error was:<br/><br/>";
$('#container').append(errorReport + e);
}
First of all, Cube is updated to BoxGeometry now. And I see lots of problem on your code and improper function definition and usage.
Here's a very simple example from mr.doob's Github.
var scene, camera, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
geometry = new THREE.BoxGeometry( 200, 200, 200 );
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render( scene, camera );
}
See the demo here
P.S Three.js Docs is the best place for resources, it makes work alot easier with tons of example code.

Resources