Three.js Line Thickness using MeshLine in 2021? - javascript

I wished to draw a curved line in Three.js with a thickness greater than one . After some digging, Three.MeshLine used to be the answer. However, I've seen a few reports (and can confirm from my own usage) that the code given on the repo example triggers a "Class constructor cannot be invoked without 'new'" error and kills the line.
Curious if anybody has found a way to make MeshLine functional with recent versions of Three. Below is the code from the current release (last commit one year ago). Unless maybe I'm missing something or if the repo has kind of gone out the window.
var scene, camera, renderer, points, line;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, 640 / 480, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setSize(640, 480);
document.body.appendChild(renderer.domElement);
camera.position.z = 9;
points = [];
for (var i = -10; i < 10.1; i += 0.1) {
points.push([i, Math.sin(i), 0]);
}
line = new MeshLine();
line.setPoints(points.flat());
var material = new MeshLineMaterial({ color: new THREE.Color(0xffff00), lineWidth: 0.1, dashArray: 0.1, dashRatio: 0.2});
material.transparent = true;
mesh = new THREE.Mesh(line, material);
scene.add(mesh);
animate();
}
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}

The project THREE.MeshLine can not support latest versions (> r127) because it derives the MeshLine class from BufferGeometry like so:
THREE.BufferGeometry.call(this)
This is no valid JS syntax anymore since BufferGeometry is now a ES6 class. That means the maintainers of THREE.MeshLine also have to move their code to ES6.

Related

Rotate a line around a circle in three.js

var lineGeometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
color: 0x000000
});
lineGeometry.vertices.push(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 10, 0),
);
var line = new THREE.Line(lineGeometry, lineMaterial);
scene.add(line);
I want to update this line's endpoint in a circular fashion. In other languages it is straightforward, I would increase some variable and update the endpoint like radius * cos(dt) and radius * sin(dt). In three.js I tried the following, but it doesn't work:
var dt = 0;
function render(){
dt += 0.01;
line.geometry.vertices[1].x = 10*Math.cos(dt);
line.geometry.vertices[1].z = 10*Math.sin(dt);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
edit: I don't want to use line.rotation.z += 0.01 method.
line.geometry.verticesNeedUpdate = true;
Add the above line before calling render. This will signal three.js that the vertex buffer has changed, so it will update it appropriately.
Since you mentioned using line.rotation, I must mention that updating the vertices is inefficient compared to rotating the line shape. When you rotate a line shape, you are simply updating the shape's transformation matrix. But when you update vertices, three.js needs to re-upload the entire set of vertices to the GPU. This may seem trivial for a single line segment, but it's a bad habit to get into if you ever intend to use larger shapes later.

How to continue to resize 3DObject on click in Three.js, is there another method for resizing other than scale.set?

My first question on StackOverflow!
I am creating a javascript interactive game and I want the mango to become bigger/smaller/different color/etc every time an event happens to it. I'm testing and I've put an event listener on the mango and it resizes, but only once, using scale.set in my callback. Is there another way to do this? I want it to continue to increase in size until a certain, yet undetermined, size. I tried using percentages which just resulted in the same thing plus my linter yelling at me. Here is my relevant code:
const Mango = function() {
this.mesh = new THREE.Object3D();
const geom = new THREE.BoxGeometry(8, 16, 5, 8, 8, 8);
// making the box round
for (let i = 0; i< geom.vertices.length; i++) {
geom.vertices[i].normalize().multiplyScalar(16);
}
for (let i = 0; i < geom.faces.length; i ++) {
let face = geom.faces[i];
face.vertexNormals[0].copy( geom.vertices[face.a] ).normalize();
face.vertexNormals[1].copy( geom.vertices[face.b] ).normalize();
face.vertexNormals[2].copy( geom.vertices[face.c] ).normalize();
}
// making it oblong
geom.applyMatrix( new THREE.Matrix4().makeScale(1.0, 1.3, 0.6));
// adding mango skin
const loader = new THREE.TextureLoader();
const mangoMap = loader.load("images/mangoMap.jpg");
const mat = new THREE.MeshPhongMaterial({
color: 0xffd507,
shininess: 40,
map: mangoMap,
});
const mango = new THREE.Mesh(geom, mat);
// adding eventlistener
const domEvents = new THREEx.DomEvents(camera, renderer.domElement);
domEvents.addEventListener(mango, 'click', function increaseMangoSize(e) {
mango.scale.set(1.2, 1.2, 1.2);
});
this.mesh.add(mango);
};
Also, if you see anything else in my code that you'd like to comment on or helpfully critique, please let me know! I've only just started working with Three.js today and have a lot to learn.
I FIGURED IT OUT!! I used
mango.scale.multiplyScalar(1.2);
instead and it works. PHEW!

Three js: Transparent object adds color to DOM underneath the canvas

I'm working on a project where i would like to have objects floating around a webpage,
you can see the progress here.
I'm now using a 2d plane to float the objects around, it's the same size as the div behind it and i've set the plane's opacity to 0.
This creates the desired effect but there is one problem occurring. The objects float around the div and become invisible when behind the plane, that's good. The renderer is transparent renderer = new THREE.WebGLRenderer({alpha: true}); so i can see the DOM underneath, that's good to. But the transparent plane that hides the floating objects adds a white color to the DOM. This only happens to DOM elements behind the plane. When dom behind the canvas is not behind the plane the proper colors are shown.
This is the code to create the plane:
var plane = new THREE.Mesh(new THREE.PlaneGeometry(160, 400), new THREE.MeshNormalMaterial());
plane.overdraw = true;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = -100;
plane.material.opacity = 0;
edit:
The problem was caused by the material type. By using a THREE.MeshBasicMaterial() instead of a THREE.MeshNormalMaterial() and adding a color to the material plane.material.color = '0xffffff' the problem got solved! The final code to create the plane looks like this:
var plane = new THREE.Mesh(new THREE.PlaneGeometry(160, 400), new THREE.MeshBasicMaterial());
plane.overdraw = true;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = -100;
plane.material.color = '0xffffff';
plane.material.opacity = 0;
Hope this helps people facing the same problem.

In three.js renderDepth of the mesh seems to be ignored

I'd like to render a mesh on top of everything else, this solution works fine:
Three.js - Geometry on top of another
I was wondering if the same could be achievable with mesh.renderDepth, but I couldn't make it work so far. Seems like renderDepth only has an effect if material.depthTest or depthWrite is set to false, but then depth ordering is of course wrong within the same object:
http://jsfiddle.net/SF9tX/22/
var cube = new THREE.Mesh(geometry, material);
cube.renderDepth = 1;
scene.add(cube);
var cube2 = new THREE.Mesh(geometry, material);
cube2.position.x = 1;
cube2.renderDepth = 2;
scene.add(cube2);
// with any one of these lines the renderDepth has an effect
// but then of course the depth test/write is wrong within the same object
// material.depthWrite = false;
// material.depthTest = false;
For r70 is renderDept function removed.
https://github.com/mrdoob/three.js/issues/5496

Three.js have one particle exactly?

I would like to add just one particle and be able to move it around. However, all I could find it how to do it with a Particle System. I tried adding a particle to the scene as one would do a mesh, but it didn't render. Only when I used a particle system did it render.
Here is what I tried:
particle_material = new THREE.ParticleBasicMaterial({ color: 0x0000ff, size: 2000 });
particle = new THREE.Particle(particle_material);
particle.position.x = 0;
particle.position.y = 0;
particle.position.z = 0;
scene.add(particle);
THREE.Particle is supported by CanvasRenderer and THREE.ParticleSystem is supported by WebGLRenderer.
You may want to consider using THREE.Sprite. See http://threejs.org/examples/webgl_sprites.html.
three.js r.60

Categories