Leveraging three.js and tween.js to spin an object in 90-degree increments for a seamless 360-degree rotation loop

I've managed to get my animation working, but not in the exact way I had envisioned.

What I'm trying to achieve is to have an object rotate 90 degrees with a delay (which currently works), and then continue rotating another 90 degrees, repeating indefinitely. However, no matter what I try, the rotation always resets back to its original position. Even when I set up multiple tweens to take me to 360 degrees, the last tween that resets back to zero causes the entire object to spin in the opposite direction.

Thank you

var width = 1000;
var height = 600;
var scene = new THREE.Scene();
var group = new THREE.Object3D(); //create an empty container

var camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, -500, 1000);
camera.position.x = 180;
camera.position.y = 180;
camera.position.z = 200;

var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.setClearColor(0xf0f0f0);
document.body.appendChild(renderer.domElement);

var geometry = new THREE.BoxGeometry(300, 300, 300);
var material = new THREE.MeshLambertMaterial({
    color: 0xffffff,
    shading: THREE.SmoothShading,
    overdraw: 0.5
});
var cube = new THREE.Mesh(geometry, material);
group.add(cube);

var canvas1 = document.createElement('canvas');
canvas1.width = 1000;
canvas1.height = 1000;
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Helvetica";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Text bit', 500, 500);

// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;

var material1 = new THREE.MeshBasicMaterial({
    map: texture1,
    side: THREE.DoubleSide
});
material1.transparent = true;

var mesh1 = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(2000, 2000),
    material1
);
mesh1.position.set(-150, 150, 151);
group.add(mesh1);

directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 0, 0)
scene.add(directionalLight);

directionalLight = new THREE.DirectionalLight(0x888888);
directionalLight.position.set(0, 1, 0)
scene.add(directionalLight);

directionalLight = new THREE.DirectionalLight(0xcccccc);
directionalLight.position.set(0, 0, 1)
scene.add(directionalLight);

scene.add(group)

// with help from https://github.com/tweenjs/tween.js/issues/14
var tween = new TWEEN.Tween(group.rotation).to({ y: -(90 * Math.PI / 180)}, 1000).delay(1000);
tween.onComplete(function() {
    group.rotation.y = 0;
});
tween.chain(tween);

tween.start();

camera.lookAt(scene.position);

var render = function() {
    requestAnimationFrame(render);
    TWEEN.update();
    renderer.render(scene, camera);
};

render();

=====EDIT=====

I was able to make it work, although I am unsure if this is the most efficient method, but I am content with the result:

var start = {}
start.y = 0;
var targ = {};
targ.y = 90*Math.PI/180

function rot(s,t) {
  start["y"] = s;
  targ["y"] = t;
}

var cnt1 = 1;
var cnt2 = 2;

rot(0,90*Math.PI/180);

var tween = new TWEEN.Tween(start).to(targ, 1000).delay(1000);
tween.onUpdate(function() {
   group.rotation.y = start.y;
})
tween.onComplete(function() {
  _c = cnt1++;
  _d = cnt2++;
  rot((_c*90)*Math.PI/180,(_d*90)*Math.PI/180)
});

tween.chain(tween);

tween.start();

Answer №1

Just use setTimeout after tween completion ( http://jsfiddle.net/bhpf4zvy/ ):

function rotateObject( obj, angles, delay, pause ) {
    new TWEEN.Tween(group.rotation)
        .delay(pause)
        .to( {
                x: obj.rotation._x + angles.x,            
                y: obj.rotation._y + angles.y,
                z: obj.rotation._z + angles.z            
            }, delay )
        .onComplete(function() {
                setTimeout( rotateObject, pause, obj, angles, delay, pause );
            })
        .start();
}
rotateObject(group, {x:0,y:-Math.PI/2,z:0}, 1000, 500 );

Update: Oh wow, what was I thinking??? Just use relative animation (http://jsfiddle.net/vv06u6rs/7/):

var tween = new TWEEN.Tween(group.rotation)
        .to({ y: "-" + Math.PI/2}, 1000) // relative animation
        .delay(1000)
        .onComplete(function() {
            // Ensure the rotation stays within 360 degrees by calculating the remainder.
            if (Math.abs(group.rotation.y)>=2*Math.PI) {
                group.rotation.y = group.rotation.y % (2*Math.PI);
            }
        })
        .start();
tween.repeat(Infinity)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular failing to update $scope variable within controller

I need to implement a directive that allows file uploading directly to the browser angular.module('angularPrototypeApp') .directive('upload', ['$parse', function ($parse) { return { restrict: 'A', scope: fal ...

Utilizing the click event with a Bootstrap modal: A guide

I have a PHP script that generates multiple Bootstrap modals, and I want to be able to modify some input fields when the "save changes" button is clicked. The ModalIDs generated are in the format "ModalID0000". However, nothing happens when I click on the ...

Autofill class names in VS Code for Next.js using Emmet

How can I modify Emmet autocomplete to change from className="" to className={styles.}? If it is possible, could you please guide me on how to achieve this? Alternatively, if modifying the autocomplete feature is not an option, is there a way to create a ...

When using a function linked to an API request, an uncaught TypeError is thrown: Unable to access the 'includes' property of an undefined value

Utilizing the movie DB API (), I am displaying the results of my call on my page using Vue. The API supplies all the necessary data for me to achieve my objective, as demonstrated in this image https://i.stack.imgur.com/vP4I2.jpg Beneath each show's ...

How can I use JavaScript api calls to retrieve an image url and insert it into an image tag in an

I have a JSON object that I need to use to retrieve images from a remote URL and display them in the img tag using API calls. The API link can be found at <div class="emoji"> <ul id="emojiz"></ul> <span style= ...

Trigger a function in jQuery when the DOM undergoes changes

Up until now, I have been utilizing livequery which has served its purpose. However, it tends to slow down the page browsing experience, so I am in search of an alternative solution. I have a function that performs ajax on elements with a specific class l ...

Retrieving values from a multidimensional array in JavaScript

I need some help with my code. I am struggling to pass an array (larray3) containing elements from two other arrays (larray1 and larray2) from data.js to model.js and view.js. Despite correctly building the multidimensional array in data.js, when I receive ...

"Exploring the concept of Undefined in Javascript Arrays

I keep encountering the issue links[i] is undefined. Even after explicitly defining it, the error persists. Any thoughts on why this might be happening? I am attempting to implement unobtrusive image rollovers for 5 links that I currently have. function ...

I'm having trouble getting the second controller to function properly in my AngularJS application

I've been looking everywhere for a solution on how to implement two controllers, but I can't seem to get it working. Could there be something wrong with my HTML or could the issue lie in my script? Here is the JavaScript code: <script> v ...

Issues with retrieving the scope attribute within a directive

I am currently facing an issue where I am unable to access the values stored in $scope.photoRes within my directive. When I use console.log(scope.photoRes) in the directive, it only displays an empty object. Here is the output from the console: Object {fi ...

How can I trigger the offcanvas opening in Bootstrap 5 through code?

I am having an issue with a bottom offcanvas on my webpage. I want to open it when a card is clicked, but despite trying to set the necessary attributes and using code from the documentation, it only shows the backdrop briefly before immediately dismissing ...

"Steady layout of grid for the navigation bar and

Currently, I am in the process of developing a control panel with the use of HTML and CSS. To structure the page, I opted for a grid layout. However, I encountered an issue where the navbar and sidebar do not stay fixed on the screen despite trying various ...

The properties are not appearing on the screen nor in the React Development Tools

Having difficulties grasping React props and mapping data from an array? Struggling to get the props to show up on your Card component, or display in React dev tools? It's unclear where the mistake lies. Seeking assistance to pinpoint the issue. Also ...

Concerns with textbox placement while scrolling with an absolute position style

I have an ASP:textbox on a page with various controls and divs, where I am setting the style to position:absolute on the "onkeyup" event. The height of the textbox increases dynamically based on the characters entered, but the issue is that the textbox alw ...

What is the process for creating interconnected mutations in GraphQL?

Exploring GraphQL: Implementing Associated Mutations To deepen my understanding of GraphQL and expand my technical skills, I decided to create a portfolio for myself. However, as I delved into this project, I encountered a challenge when trying to add an ...

Even with minify and uglify plugins implemented, the React App remains unminified

I am facing a major issue with my reactjs app in production, as it exceeds 1.8 MB. I urgently need to reduce the size of the app. Below is the analysis from webpack: https://i.sstatic.net/skVfV.png Here is my webpack.config.js: const path = require( ...

Looking for a straightforward way to incorporate a "Read more" and "Show Less" functionality into a Wordpress site using Javascript?

As a last resort, I am seeking a quick and simple fix. I have been experimenting with Javascript to implement a 'Read more...' & '... Read Less' feature on six different sections of a single page. The goal is to display only the fi ...

Angular is showing an error indicating that the property "name" is not found on an empty object

After thorough checking, I have confirmed that the property does exist with the correct key. However, it is returning an error message stating name is not a property of {}. I attempted to assign this object to an interface along with its properties but enc ...

Is there a way to always keep an element positioned directly above a fluid image that is perfectly centered?

My current project involves creating an overlay to display a fluid image of any size. The challenge I'm facing is how to consistently position the close button 30px above the image and flush with its right edge. The catch is that the container doesn&a ...

Creating TypeScript declaration file for exporting JavaScript function

I'm a beginner with TypeScript and I want to learn how to create a declaration file for a custom JavaScript function. I attempted to do this, however, I encountered an error stating "Could not find a declaration file for module './main'." Ad ...