Three.js - How to scale a circle without scaling it's stroke? - javascript

I'm using a THREE.Path to create a Circular path and then using a TubeGeometry to use that Path to basically create a circle with transparent fill and a stroke whose thickness I can control. My question is, how can I scale up the Circular path at runtime?
Accessing the vertices through mesh.vertices results in a very weird result, because I'm accessing the Tube's Geometry, not the Path. If I change the path, then I have to create a brand new TubeGeometry and update the Tube with the new geometry by doing mesh.geometry = newTubeGeometry, and that just doesn't work at all. Scaling the Tube itself increases it's radius as well, so that's not the right solution either.
Any ideas?
Thanks

Just changing the geometry property does not work, you have to create a new instance of THREE.Mesh. You should also call geometry.dispose() on your old geometry because the renderer internally caches the corresponding WebGLBuffer objects. More information here:
https://discourse.threejs.org/t/changing-the-geometry-of-a-mesh/306

Just an example of how you can do that trick with THREE.TorusGeometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var geometry = new THREE.TorusGeometry(5, 0.5, 8, 32);
geometry.rotateX(Math.PI * -0.5);
geometry.vertices.forEach(v => {
v.initPosition = new THREE.Vector3().copy(v);
});
var mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
color: "red",
wireframe: true
}));
scene.add(mesh);
var clock = new THREE.Clock();
var time = 0;
render();
function render() {
requestAnimationFrame(render);
time += clock.getDelta();
geometry.vertices.forEach(v => {
v // take a vertex
.setY(0) // make it scalable in two dimensions (x, z)
.normalize() // make a normal from it
.multiplyScalar(Math.sin(time) * 2) // set the distance
.add(v.initPosition); // add the initial position of the vertex
});
geometry.verticesNeedUpdate = true;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Related

Creating a cylinder with slanted bottom

I want to create a cylinder with slanted bottom shape in three.js.
I don't see any direct way to create such geometry in three.js. I tried to see if I can cut the cylinder by a slanted plane, but could not find such operation in the documentation. Can anybody suggest a way to create this?
You can operate with vertices as you want.
Just a simple concept:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var cylGeom = new THREE.CylinderBufferGeometry(1, 1, 5, 16);
var vertices = cylGeom.attributes.position;
// change upper vertices
var v3 = new THREE.Vector3(); // temp vector
for (let i = 0; i < vertices.count; i++) {
v3.fromBufferAttribute(vertices, i); // set the temp vector
v3.y = v3.y > 0 ? (v3.x * 0.5) + 2.5 : v3.y; // change position by condition and equation
vertices.setY(i, v3.y); // set Y-component of a vertex
}
var cylMat = new THREE.MeshLambertMaterial({
color: "aqua"
});
var cyl = new THREE.Mesh(cylGeom, cylMat);
scene.add(cyl);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera)
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Three.js move camera distance to object by z

I'm rotating a PerspectiveCamera with orbitControls around an object. Now I want to move the camera closer to the object but keep the actual rotation.
My coordinate to set the distance to the objects are output as [0,0,100].
But my CameraPosition is [-500, 96, 1772]. How can I keep the "rotation" but move the camera closer to the object to a distance of 100.
Do I need to use getAzimuthalAngle() or getPolarAngle()?
For example, like this, if you object is not in the center of a scene:
camera.position.sub(obj.position).setLength(100).add(obj.position);
If the object is in the center:
camera.position.setLength(100);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(25, 0, 100);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(100, 100));
var obj = new THREE.Mesh(new THREE.CubeGeometry(10, 10, 10), new THREE.MeshBasicMaterial({
color: "red",
wireframe: true
}));
obj.position.set(25, 0, 0);
scene.add(obj);
controls.target.copy(obj.position);
controls.update();
stepCloser.addEventListener("click", onClick, false);
function onClick() {
camera.position.sub(obj.position).setLength(100).add(obj.position);
}
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<button id="stepCloser" style="position: absolute;">
100 units to the object
</button>
this will work. I was trying to load the GLTF model through this code snippet.
loader.load('./demo-models/model-1/scene.gltf', function (gltf) {
gltf.position.x -= 60
scene.add(gltf.scene);
});
But that didn't work out. So after debugging for a while, I realized I could play around with some parameters of the Perspective Camera. Well initially the first argument was 75 units which made my object way too far from the screen, I had to zoom in until I could get a clear view. Some code tweaks, it works the best when I set it to 1.
var camera = new THREE.PerspectiveCamera(1, window.innerWidth / window.innerHeight, 0.1, 1000);

Adding diagonal lines to a GridHelper object in Three.js?

First image is what I want. (I even want the opposite diagonal too, but I will derive that accordingly.) Second image is a normal GridHelper.
Would this be possible by adding another grid helper but rotated along the y-axis by 45 degrees?
I cannot seem to find anything in the official docs, so I am assuming that there is an alternate approach. Any pointers on how this could be done?
My code for the GridHelper:
grid = new THREE.GridHelper(80, 15, 0x000000, 0x000000);
grid.position.y = -0.2;
scene.add(grid);
I am thinking that a possible solution may lie in EdgesGeometry. I am still unsure about how to proceed with this, since:
EdgesGeometry( geometry, thresholdAngle )
Where geometry is any geometry object.
Does the GridHelper count as a geometry object? Here are the official docs.
EDIT:
Here is a visual example of my current situation: codepen example.
Using of THREE.PlaneBufferGeometry() and a material with wireframe: true will give you the desired result.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 50, 25);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var gridGeometry = new THREE.PlaneBufferGeometry(80, 80, 15, 15);
gridGeometry.rotateY(Math.PI);
gridGeometry.rotateX(-Math.PI * .5);
var gridMaterial = new THREE.MeshBasicMaterial({
color: "black",
wireframe: true
});
var gridWithDiagonals = new THREE.Mesh(gridGeometry, gridMaterial);
scene.add(gridWithDiagonals);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Three.js cant get the map and color property's to work with Canvas renderer

I have been trying to use the map and color property's simultaneously with the canvas renderer but only one or the other will work. Also when using the canvas renderer the image being displayed becomes distorted when the cube it is applied to rotates. This distortion does not occur with webGL. I have set up a jsfiddle to demonstrate my issue. This is my first time using a jsfiddle and I can't get the webGL renderer to display correctly either but the webGL renderer does work when I test it locally. I am using build 62dev.
// revolutions per second
var angularSpeed = 0.2;
var lastTime = 0;
// this function is executed on each animation frame
function animate(){
// update
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;
cube.rotation.y += angleChange;
lastTime = time;
// render
renderer.render(scene, camera);
// request new frame
requestAnimationFrame(function(){
animate();
});
}
// renderer
//var renderer = new THREE.WebGLRenderer();
var renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 500;
// scene
var scene = new THREE.Scene();
// cube
var spriteImg = new THREE.ImageUtils.loadTexture( 'http://unrestrictedstock.com/wp-content/uploads/lugano-switzerland-villa-ciani.jpg' );
var cube = new THREE.Mesh(new THREE.CubeGeometry(200, 200, 200), new THREE.MeshBasicMaterial({
color: 'red', map: spriteImg
}));
cube.rotation.x = Math.PI * 0.1;
scene.add(cube);
// start animation
animate();
CanvasRenderer does not support the use of material.color and material.map simultaneously.
The image distortion is a well-known limitation of CanvasRenderer. You can reduce the distortion by further tessellating your geometry.
var geometry = new THREE.CubeGeometry( 200, 200, 200, 4, 4, 4 );
You can read more about this limitation in this excellent blog post.
Fiddle: http://jsfiddle.net/8ASqn/3/
three.js r.63

THREE.js Triangle is Black

So i was using THREE.JS and created a triangle. But even though i gave it color: 0xFF0000, it appears black on Screen.
Here is my Script:
var camera, scene, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
var geometry = new THREE.Geometry(200,200,200);
var v1 = new THREE.Vector3(200,0,0); // Vector3 used to specify position
var v2 = new THREE.Vector3(-100,0,0);
var v3 = new THREE.Vector3(0,50,0); // 2d = all vertices in the same plane.. z = 0
// Push vertices represented by position vectors
geometry.vertices.push(v1);
geometry.vertices.push(v2);
geometry.vertices.push(v3);
// Push face, defined with vertices in counter clock-wise order
geometry.faces.push(new THREE.Face3(0, 2, 1));
// Create a material and combine with geometry to create our mesh
var redMat = new THREE.MeshLambertMaterial({color: 0xFF0000});
var triangle = new THREE.Mesh(geometry, redMat);
scene.add(triangle);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
Hope you can find the mistake i made. I am sure it's just something really stupid.
late to the party...but for all who come after me.
The issue here is the type of material used
change
new THREE.MeshLambertMaterial({color: 0xFF0000});
to
new THREE.MeshBasicMaterial({color: 0xFF0000});
and it will show up red
Even I've struggled from this problem for sometime. The solution for me was to add an ambient light to the scene if you're using Lambert Material.
Just add:
var light = new THREE.AmbientLight(0xffffff);
scene.add(light);
Try add computeFaceNormals call upon geometry object:
geometry.computeFaceNormals();
*from https://stackoverflow.com/a/49226898/2154075

Categories