I am trying to rotate a propeller in an drone model in three.js.
The propellers are loaded from GLTF models, in a pivot, in a group. The total loading code is here:
const loader = new THREE.GLTFLoader();
const p1Meshes = [];
const p2Meshes = [];
const mMesh = [];
const models = [
{
path: 'zep-main-1.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x999966,
transparent: true,
opacity: 0.96,
roughness: 0.8,
metalness: 0.4,
side: THREE.DoubleSide,
},
reflection: false,
reflectionX: 0,
pivot: false,
},
{
path: 'zep-main-2.gltf',
center: new THREE.Vector3(40-17.5, -80, 250),
scale: 100,
materialProps: {
color: 0x99DDBB,
transparent: true,
opacity: 1,
roughness: 0.6,
metalness: 0.4,
side: THREE.DoubleSide,
},
reflection: false,
reflectionX: 0,
pivot: false,
},
{
path: 'zep-tailwing.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x22DDBB,
transparent: true,
opacity: 1,
roughness: 0.6,
metalness: 0.4,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-mw.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x999966,
transparent: true,
opacity: 0.7,
roughness: 0.1,
metalness: 0.4,
side: THREE.DoubleSide,
},
reflection: false,
reflectionX: 0,
pivot: false,
},
{
path: 'zep-mw-wb.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x444444,
transparent: true,
opacity: 0.9,
roughness: 0.7,
metalness: 0.1,
side: THREE.DoubleSide,
},
reflection: false,
reflectionX: 0,
pivot: false,
},
{
path: 'zep-w1.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x55DD77,
transparent: true,
opacity: 1,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-w2.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x55DD77,
transparent: true,
opacity: 1,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-w3.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x55DD77,
transparent: true,
opacity: 1,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-w4.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x55DD77,
transparent: true,
opacity: 1,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-fw.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x888844,
transparent: true,
opacity: 0.98,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-fw-wb.gltf',
center: new THREE.Vector3(40-93.7, -80-2.5, 250+80),
scale: 100,
materialProps: {
color: 0x343434,
transparent: true,
opacity: 1,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 187.4 + 32,
pivot: false,
},
{
path: 'zep-mw-ns.gltf',
center: new THREE.Vector3(40, -80, 250),
scale: 100,
materialProps: {
color: 0x668844,
transparent: true,
opacity: 0.96,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 32,
pivot: false,
},
{
path: 'zep-en-mt1.gltf',
center: new THREE.Vector3(40-1, -80+2, 250),
scale: 100,
materialProps: {
color: 0xDBDBDB,
transparent: true,
opacity: 0.96,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 33.75,
pivot: false,
},
{
path: 'zep-en-mt3.gltf',
center: new THREE.Vector3(40-5, -80, 250),
scale: 100,
materialProps: {
color: 0xDBDBDB,
transparent: true,
opacity: 0.96,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 41,
pivot: false,
},
{
path: 'zep-en.gltf',
center: new THREE.Vector3(40-5, -80, 250),
scale: 100,
materialProps: {
color: 0xDBDBDB,
transparent: true,
opacity: 0.96,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 41,
pivot: false,
},
{
path: 'zep-en-sp.gltf',
center: new THREE.Vector3(40-4.5, -80, 250),
scale: 100,
materialProps: {
color: 0x888844,
transparent: true,
opacity: 0.98,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 41,
pivot: false,
},
{
path: 'zep-p1.gltf',
center: new THREE.Vector3(40-4.5, -80, 250),
scale: 100,
materialProps: {
color: 0x448888,
transparent: true,
opacity: 0.98,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 41,
pivot: true,
},
/* {
path: 'zep-p2.gltf',
center: new THREE.Vector3(40-4.5, -80, 250),
scale: 100,
materialProps: {
color: 0x448888,
transparent: true,
opacity: 0.98,
roughness: 0.2,
metalness: 0.2,
side: THREE.DoubleSide,
},
reflection: true,
reflectionX: 41,
} */
];
const compositeModel = new THREE.Group();
function loadModel(loader, path, center, scale, materialProps, reflection = false, reflectionX = 0, pivot=false) {
return new Promise((resolve, reject) => {
loader.load(
path,
function (gltf) {
const model = gltf.scene;
// Optionally, center the model
camera.lookAt(center);
if(pivot){
var box = new THREE.Box3().setFromObject( model );
box.getCenter( model.position ); // this re-sets the mesh position
model.position.multiplyScalar( - 1 );
const pivot = new THREE.Group();
pivot.position.sub(center);
compositeModel.add(pivot);
pivot.add(model)
} else {
model.position.sub(center);
compositeModel.add(model);
}
// Set scale
model.scale.set(scale, scale, scale);
// Set material properties
model.traverse(function (child) {
if (child.isMesh) {
child.material = new THREE.MeshStandardMaterial(materialProps);
}
});
if (path.includes('zep-p1')) {
p1Meshes.push(model);
} else if (path.includes('zep-p2')) {
p2Meshes.push(model);
}
if(path.includes('zep-main-1')|| path.includes('zep-mw')) mMesh.push(model);
// If reflection is needed, create and add the reflected model
if (reflection) {
if(pivot){
const reflectedModel = model.clone();
reflectedModel.scale.x = -scale; // Reflect along the X-axis
var box = new THREE.Box3().setFromObject( reflectedModel );
box.getCenter( reflectedModel.position ); // this re-sets the mesh position
reflectedModel.position.multiplyScalar( - 1 );
const rpivot = pivot.clone();
rpivot.scale.x = -scale; // Reflect along the X-axis
rpivot.position.x -= reflectionX; // Adjust the position if neede
compositeModel.add(rpivot);
rpivot.add(reflectedModel)
} else {
const reflectedModel = model.clone();
reflectedModel.scale.x = -scale; // Reflect along the X-axis
reflectedModel.position.x -= reflectionX; // Adjust the position if needed
compositeModel.add(reflectedModel);
}
if (path.includes('zep-p1') ) {
p1Meshes.push(reflectedModel);
} else if (path.includes('zep-p2')) {
p2Meshes.push(reflectedModel);
}
}
resolve();
},
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (error) {
console.error('An error happened', error);
reject(error);
}
);
});
}
I apologize for the long code, but i am confused as to where the error might be.
Then the rotation code is:
function startAirship() {
var rotationSpeed = 0.1; // Adjust this value to change rotation speed
function animateAirshipProps() {
requestAnimationFrame(animateAirshipProps);
mMesh.forEach( m => {
console.log(m.position);
})
// Rotate p1 meshes clockwise
const originalPositions = new Map();
p1Meshes.forEach(mesh => {
console.log("mesh position before: ", mesh.position, mesh.parent.position, mesh.parent.parent, mesh);
mesh.rotation.z=rotationSpeed;
rotationSpeed = rotationSpeed + 0.01;
});
// Rotate p2 meshes counter-clockwise
p2Meshes.forEach(mesh => {
//mesh.position.sub(point);
//mesh.rotation.z -= rotationSpeed;
//mesh.position.add(point);
});
// Render the scene
renderer.render(scene, camera);
}
animateAirshipProps();
}
The output of this code shows me that the mesh (the prop model) is at position 0 0 0 in the pivot. But it keeps on rotating along an axis outside the object.
Attempt to solve
I followed the instructions here and here. But know change. A visual demonstration of the problem may be found in here.
You will see that the blue/gun metal props are going around an axis that goes through the parent group’s (that is parent of pivot) origin (almost). That is also the origin of the cad model that i made the GLTF from. So I also tried to manually shift the pivot, as well as the mesh (one at a time) to that origin , rotate, and shift back. This also does not work.
Help please.
Thank you