Cannot get object to change position using tween - three.js

Apologies for asking this, but I am losing my mind.
In the context of a three.js scene I have built a cube with the following bit of code.
var gcap = new THREE.BoxGeometry( 10, 10, 1, 2, 2, 2 );
mcap = new THREE.MeshBasicMaterial( { color: 0x3182bd, wireframe: false, transparent: true, opacity: 0.5} );
cap = new THREE.Mesh( gcap, mcap );
cap.position.set( - 12, 19, 0 );
gcap.center();
cap.rotation.z = (28 * Math.PI)/180; //convert to radians
app.scene.add(cap);
So why does this tween not work (and by not working I mean there is not noticeable change in the scene):
new TWEEN.Tween(cap.position)
.to(-12, 19, 100 ).start();
but this one does:
new TWEEN.Tween(app.controls.target).to({
x: 31/2,
y: 29/2,
z: 11/2
}).start();
I realize this is probably a super-dumb question, but I'm new to tween (and really three.js in general).

In .to() you have to pass an object of the same structure that you pass in .Tween(), fully or partially. It depends on what values of the object you want to change.
And the second paremeter in .to() is duration.
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();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var box1 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({
color: "red",
wireframe: true
}));
box1.position.set(-3, 0, 0);
scene.add(box1);
var box2 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({
color: "blue",
wireframe: true
}));
box2.position.set(3, 0, 0);
scene.add(box2);
var tween1 = new TWEEN.Tween(box1.position) // here you pass the position {x, y, z}
.to({ // here you pass an object with properties you want to change (now you want to change all of them)
x: 1,
y: 3,
z: -2
}, 2000).delay(500).repeat(Infinity).yoyo(true).start();
var tween2 = new TWEEN.Tween(box2.position) // the same, position {x, y, z}
.to({ // but you want to change only y-coordinate, so you pass an object of {y}
y: 3
}, 1000).delay(500).repeat(Infinity).yoyo(true).start();
render();
function render() {
requestAnimationFrame(render);
TWEEN.update();
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/90/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>

Related

Three.js assign array of materials to an indexed BufferGeometry

I have a BufferGeometry triangular prism; where I have specified the 6 vertices and then added indexes to create the 8 faces (2 triangle faces per square plane).
I have then setup 5 groups, so that each side of the prism is a group.
And it works here when I have a single material assigned to the whole object: https://jsfiddle.net/30ez17dw/1/
However I want to be able to assign an array of materials, so that each side (group) has it's own materials. But when I do this the object disappears:
https://jsfiddle.net/30ez17dw/2/
How can I fix my code to make the array of materials work?
You have not specified your groups correctly. Try it like so:
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 5;
camera.position.y = 2;
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
var geometry = new THREE.BufferGeometry();
const y = 0.866025404;
const y2 = 0.5;
const h = 1;
const vertices = new Float32Array([
-y2, 0, 0,
y2, 0, 0,
0, 0, y,
-y2, h, 0,
y2, h, 0,
0, h, y,
]);
const indices = [
0, 1, 2, // Top
5, 4, 3, // Bottom
3, 1, 0, // Back
1, 3, 4, // Back
0, 2, 3, // Left
5, 3, 2, // Left
4, 2, 1, // Right
2, 4, 5, // Right
];
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(indices);
geometry.computeVertexNormals();
geometry.clearGroups();
geometry.addGroup(0, 3, 0);
geometry.addGroup(3, 6, 1);
geometry.addGroup(6, 12, 2);
geometry.addGroup(12, 18, 3);
geometry.addGroup(18, 24, 4);
var material = [
new THREE.MeshBasicMaterial({
color: 0x00ff00
}),
new THREE.MeshBasicMaterial({
color: 0xff0000
}),
new THREE.MeshBasicMaterial({
color: 0x0000ff,
}),
new THREE.MeshBasicMaterial({
color: 0xffff00
}),
new THREE.MeshBasicMaterial({
color: 0x00ffff
})
];
var mesh = new THREE.Mesh(geometry, material); // , side: THREE.DoubleSide
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);
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.132.0/build/three.min.js"></script>
The indices you pass to addGroup() are meant to be consecutive.

Make parallel the crossing edges of opposite faces with three.js

As you can see in the example below, an edge crossing a face is never parallel to this of the opposite face. How can I get this done ?
"use strict";
const renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});
const camera = new THREE.PerspectiveCamera(70, 1, 1, 1000);
camera.position.z = 400;
// Make a scene
const scene = new THREE.Scene();
// Make a cube.
const geometry = new THREE.BoxGeometry(200, 200, 200);
// Make a material
const material = new THREE.MeshBasicMaterial({
color: 0x00FF00,
wireframe: true,
});
// Create a mesh based on the geometry and material
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
function resize() {
var width = renderer.domElement.clientWidth;
var height = renderer.domElement.clientHeight;
if (renderer.domElement.width !== width || renderer.domElement.height !== height) {
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function animate(time) {
time *= 0.001; // seconds
resize();
mesh.rotation.x = time * 0.5;
mesh.rotation.y = time * 1;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
That's the way the BoxGeometry algorithm works in Three.js. If you want to override the way in which the vertices are connected, you're going to have to manually build your THREE.Geometry as outlined in the docs. The idea is as follows:
Init a Geometry object.
Add vertices to the geometry with Vector3
Define how the vertices will be connected with Face3
I got things started with 2 sides of the box in the demo below, but I'll leave the remaining 4 sides for you to figure out (it might help to draw it out with pen and paper to figure out how to connect the remaining Face3s).
"use strict";
const renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});
const camera = new THREE.PerspectiveCamera(70, 1, 1, 1000);
camera.position.z = 400;
// Make a scene
const scene = new THREE.Scene();
// 1. Start with empty geometry
const geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3( -100, 100, 100 ),
new THREE.Vector3( -100, -100, 100 ),
new THREE.Vector3( 100, -100, 100 ),
new THREE.Vector3( 100, 100, 100 ),
// verts [4-7] in -z
new THREE.Vector3( -100, 100, -100 ),
new THREE.Vector3( -100, -100, -100 ),
new THREE.Vector3( 100, -100, -100 ),
new THREE.Vector3( 100, 100, -100 ),
);
// 3. Connect vertices in desired order to make faces
geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
geometry.faces.push( new THREE.Face3( 0, 2, 3 ) );
geometry.faces.push( new THREE.Face3( 4, 5, 6 ) );
geometry.faces.push( new THREE.Face3( 4, 6, 7 ) );
// Make a material
const material = new THREE.MeshBasicMaterial({
color: 0x00FF00,
wireframe: true,
});
// Create a mesh based on the geometry and material
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
function resize() {
var width = renderer.domElement.clientWidth;
var height = renderer.domElement.clientHeight;
if (renderer.domElement.width !== width || renderer.domElement.height !== height) {
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function animate(time) {
time *= 0.001; // seconds
resize();
mesh.rotation.x = time * 0.5;
mesh.rotation.y = time * 1;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>

Increase thickness of cylinder in three js

I am trying to increase thickness of cylinder using ThreeBSP. Using this http://jsfiddle.net/gerdonabbink/tephoLr1/133/ fiddle but it gives me an constructor error.
Type Error: ThreeBSP is not a constructor
currently i am using <script type="module"> to load all JS file using 'import' keyword. so is there need to alter library? because i haven't seen any export statement in library so, or is there any other way is available to increase thickness of cylinder?
My Code Sample 'Instead of 'THREE' i used 'Mine' as module'
You can form such cylinder, using the approach with THREE.Shape and THREE.ExtrudeBufferGeometry():
body {
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(3, 5, 8);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var arcShape = new THREE.Shape();
arcShape.absarc( 0, 0, 2, 0, Math.PI * 2, false );
var holePath = new THREE.Path();
holePath.absarc( 0, 0, 1, 0, Math.PI * 2, true );
arcShape.holes.push( holePath );
var extrudeGeom = new THREE.ExtrudeBufferGeometry(arcShape, {depth: 6, curveSegments: 36, bevelEnabled: false});
extrudeGeom.translate(0, 0, -3);
extrudeGeom.rotateX(-Math.PI * 0.5);
var cylinder = new THREE.Mesh(extrudeGeom, new THREE.MeshNormalMaterial());
scene.add(cylinder);
renderer.setAnimationLoop(() => { renderer.render(scene, camera); });
</script>

three.js 2d and 3d vertices interconversion

see this jsfiddle;
init();
var camera, scene, renderer;
function init() {
container = document.createElement('div');
document.body.appendChild(container);
var camera_cylinder_setting = '[0.9985033869743347, 0.02076610177755356, 0.05059404298663139, 0, 0.0047478810884058475, 0.8886997103691101, -0.4584651291370392, 0, -0.05448344349861145, 0.4580191969871521, 0.8872711062431335, 0, -0.5448344349861145, 4.5801920890808105, 8.872710227966309, 1]';
camera = new THREE.OrthographicCamera(512 / -2, 512 / 2, 512 / 2, 512 / -2, -512, 512);
camera.matrix.fromArray(JSON.parse(camera_cylinder_setting));
camera.matrix.decompose(camera.position, camera.quaternion, camera.scale);
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xf0f0f0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(512, 512);
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
var geometry = new THREE.CylinderGeometry(118, 158, 383, 30, 30, true, 3.3, 6.3);
var loader = new THREE.TextureLoader();
object = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
color: Math.random() * 0xffffff,
opacity: 0.5
}));
object = new THREE.Mesh(geometry);
loader.load('https://farm9.staticflickr.com/8829/28748679526_16d6e56b84_b.jpg', function(texture) {
texture.offset = new THREE.Vector2(0.3, 0.1);
var material = new THREE.MeshBasicMaterial({
overdraw: 1,
map: texture
});
object.material = material;
scene.add(object);
renderer.render(scene, camera);
});
}
what i want to know hwo to get the greed rectangle accordding to the raw image's red rectangle?
oppositely,how to get the red rectangel according to the green rectangle?
thank you very much!

Three JS how to render the xyz axis over all the models inside a scene?

Currently I want to render the axis over the cube (rather than through it). But I can't figure out a way to do that. Does any one know how to render the axis lines over the cube module? Thanks.
Have provided the JS code below.
The cube will be rendered in scene and axis lines will be rendered in fscene. (The axis lines rendered in fscene is supposed to cover the cube which rendered in scene)
var container, stats;
var camera, scene, fscene, renderer;
var cube, plane;
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.01, 999999 );
camera.position.y = 5;
camera.position.z = 5;
camera.position.x = 4;
camera.lookAt(new THREE.Vector3());
scene = new THREE.Scene();
fscene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 1, 1, 1 );
for ( var i = 0; i < geometry.faces.length; i ++ ) {
geometry.faces[ i ].color.setHex( 0xcccccc * i );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors } );
cube = new THREE.Mesh( geometry, material );
scene.add(cube);
addAxis();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.autoClear = false;
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
animate();
}
function animate() {
requestAnimationFrame(animate);
renderer.clear();
renderer.render(scene, camera);
renderer.render(fscene, camera);
}
function addAxis() {
var sceneSize = 9000;
line({ begin: [0, 0, 0], end: [sceneSize, 0, 0], color: 0xff0000, scene: scene });
line({ begin: [0, 0, 0], end: [-sceneSize, 0, 0], color: 0xff0000, dashed: true, scene: scene });
line({ begin: [0, 0, 0], end: [0, sceneSize, 0], color: 0x00ff00, scene: scene });
line({ begin: [0, 0, 0], end: [0, -sceneSize, 0], color: 0x00ff00, dashed: true, scene: scene });
line({ begin: [0, 0, 0], end: [0, 0, sceneSize], color: 0x0000ff, scene: scene });
line({ begin: [0, 0, 0], end: [0, 0, -sceneSize], color: 0x0000ff, dashed: true, scene: scene });
}
function line(cfg){
var p = cfg.begin;
var q = cfg.end;
if (cfg.color) {
cfg.colorb = cfg.colorb || cfg.color;
cfg.colore = cfg.colore || cfg.color;
}
var geometry = new THREE.Geometry();
var material = cfg.dashed ? new THREE.LineDashedMaterial({ linewidth: 1, color: cfg.color, dashSize: 1, gapSize: 1, depthWrite:false }) : new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors, depthWrite:false });
var cp = new THREE.Color(cfg.colorb);
var cq = new THREE.Color(cfg.colore);
geometry.vertices.push(new THREE.Vector3(p[0], p[1], p[2]));
geometry.vertices.push(new THREE.Vector3(q[0], q[1], q[2]));
geometry.colors.push(cp,cq);
geometry.computeLineDistances();
var line = new THREE.Line(geometry, material, THREE.LinePieces);
fscene.add(line);
}
TransformControls.js contains the code that might help you.
depthTest should be set to false and transparent should be set to true.

Resources