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 ?
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/three@0.170.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.170.0/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>