notnuyy
notnuyy

Reputation: 121

How i can make the object steady 180 degrees?

i have clothe object where user can rotation the cloth, i am using orbit control to rotation the object here, and the interface, user can change the color of clothe, there is a button to see the back of clothe, so i want to make sure when user click it it gonna show the back on cloth

here is how i animate is with anime js

this is how i init 3D and call function doSmething for show the back of cloth object

let _scene;
let _camera;
let _control;

function init3D() {
    _scene = new THREE.Scene();
    _camera = new THREE.PerspectiveCamera(75, container.value.clientWidth / container.value.clientHeight, 0.1, 1000);
    _control = new OrbitControls(_camera, container.value);
}

init3D()

function doSometing() {
    gltfloader.load(
    url,
     (gltfModelOnLoad) => {
       _scene.add(gltfModelOnLoad.scene);
      
       anime({
          targets: _scene.rotation,
          y: _scene.rotation.y - Math.PI,
          duration: 2000,
          easing: 'easeInOutQuad',
          update: () => {
            renderSceneAndCamera();
          }
        });
   }, 
  undefined, 
  undefined

  )}
}

const renderSceneAndCamera = () => {
  _renderer.render(_scene, _camera);
}


  anime({
          targets: _scene.rotation,
          y: _scene.rotation.y - Math.PI,
          duration: 2000,
          easing: 'easeInOutQuad',
          update: () => {
            renderSceneAndCamera();
          }
        });

when i do this _scene.rotation.y - Math.PI it is not always rotation the back of clothe, also when i am on position 180 degree already, the scene becomes rotation the front of cloth ,

is that any way to make always the object rotation 180 degree what ever the rotation y changed ?

Upvotes: 2

Views: 158

Answers (2)

Łukasz Daniel Mastalerz
Łukasz Daniel Mastalerz

Reputation: 2217

In general, the solution to this problem is not as simple as it may seem... Interfering with the camera with the transformations that @rookie proposes will cause a 180 degree rotation every time, not respecting the user's input via OrbitControls. The solution below is not perfect but it may give you the direction of the output. I assume that the red face of the cube is the front of the shirt. I transformed the camera position to spherical coordinates by blocking the x-axis, because as I understood from your question and comments, you will simply rotate the shirt, something like a 3D gallery, so activating the entire transformation is probably not the best approach. As for the animation itself, always showing the front of the shirt, you can use a quaternion, which will rotate the shirt so that its front (which by default is directed towards the Z axis, example (0, 0, 1)) points towards the camera.

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/[email protected]/build/three.module.js",
      "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
    }
  }
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.2/anime.min.js" integrity="sha512-aNMyYYxdIxIaot0Y1/PLuEu3eipGCmsEUBrUq+7aVyPGMFH8z0eTP0tkqAvv34fzN6z+201d3T8HPb1svWSKHQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<script type="module">
import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const s = new THREE.Scene();
const c = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
c.position.set(0, 0, 5);
 
const r = new THREE.WebGLRenderer({ antialias: true });
r.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(r.domElement);
const partOfShirt = [
new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }),
new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }),
new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }),
new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }),
new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true }), // Front of your shirt
new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }) 
];

const g = new THREE.BoxGeometry();
const shirt = new THREE.Mesh(g, partOfShirt);
s.add(shirt);

const controls = new OrbitControls(c, r.domElement);
controls.enableDamping = true;

controls.addEventListener('change', () => {
const spherical = new THREE.Spherical();
spherical.setFromVector3(c.position.clone().sub(controls.target));
spherical.phi = Math.PI / 2; // "Blocker" camera x
c.position.copy(controls.target.clone().add(new THREE.Vector3().setFromSpherical(spherical)));
});

const b = document.createElement('button');
b.innerText = 'Rotate to Front Face';
b.style.position = 'absolute';
b.style.top = '10px';
b.style.left = '10px';
b.style.padding = '10px 20px';
b.style.backgroundColor = '#28a745';
b.style.color = 'white';
b.style.border = 'none';
b.style.cursor = 'pointer';
b.style.fontSize = '16px';
document.body.appendChild(b);

b.addEventListener('click', () => {
const direction = new THREE.Vector3();
c.getWorldDirection(direction);
const targetQuaternion = new THREE.Quaternion();
targetQuaternion.setFromUnitVectors(
    new THREE.Vector3(0, 0, 1),
    direction.negate()
);
anime({
    targets: shirt.quaternion,
    x: targetQuaternion.x,
    y: targetQuaternion.y,
    z: targetQuaternion.z,
    w: targetQuaternion.w,
    duration: 2000,
    easing: 'easeInOutQuad',
    update: () => shirt.quaternion.normalize(),
});
});

function animate() {
controls.update();
r.render(s, c);
requestAnimationFrame(animate);
}
animate();

</script>

Upvotes: 2

rookie
rookie

Reputation: 218

You should rotate the camera instead of the model. First, get the position of the camera after it rotates to the back of the clothes, save it to a constant, and then use anime to transition the camera position when you need to rotate to the back of the clothes.

const backPosition = new THREE.Vector3(1, 1, 1); // The position of the camera when it is on the back of the clothes.

anime({
    targets: _camera.position,
    x: backPosition.x,
    y: backPosition.y,
    z: backPosition.z,
    duration: 2000,
    easing: 'easeInOutQuad',
    update: () => {
        _control.update();
        // renderSceneAndCamera();
    }
});

Upvotes: 0

Related Questions