-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LWO Loader incorrect placement of geometry and mesh when used with pivot point placement #26733
Comments
I've been digging deeper... pivot: this.reader.getFloat32Array( 3 ), // Note: this seems to be superflous, as the geometry is translated when pivot is present So, I can see it actually records the pivot points. // TODO: z may need to be reversed to account for coordinate system change
geometry.translate( - layer.pivot[ 0 ], - layer.pivot[ 1 ], - layer.pivot[ 2 ] ); So, now the mesh is in the incorrect place but the geometry has been shifted over to make it "look" like it's in the correct place. |
Is that the best issue title you can come up with? 🤓 |
I suspected I typed it in as a place holder so I could gather all the information and then make a better one.. |
Correct. Pivot points like you know them from other engines/projects are not supported, see #15965. |
As a workaround, instead of transforming the geometry couldn't you add a "dummy" instance of |
Yeah, then we would just need to move the mesh so it's This is getting it "roughly" into the correct position for rotation, but not quiet yet.. I will set up a proper test environment with some simple boxes in all the orientations so I can be sure it fixes all direction scenarios |
It's the loader that sets up the hierarchy structure during it's parsing phase.. BUT, I have just seen this on github... I don't remember coming across this when stepping through the code.. but maybe I was just tired.. I will try running this code 'raw' from github and see what happens when I do testing.. maybe it's already fixed but the CDN's don't have the fix... |
const boom_z = objects.boom.userData.pivot[2]; // 2 = z;;
objects.boom.geometry.translate(0, 0, boom_z * 2);
objects.boom.translateZ(-boom_z * 2); Finally got everything to align.. |
Okay, this is how I eventually fixed the pivot points as things got more nested.. const { meshes } = await new LWOLoader().loadAsync(urlToLWOFile);
for ( const mesh of meshes ) {
fixPivots(mesh);
}
function fixPivots(mesh: THREE.Mesh) {
const [, , z] = mesh.userData.pivot;
const parentsZ = (mesh.parent?.userData.pivot[2] /* 2 = z */ ?? 0) * 2; // THIS was the killer blow..
mesh.geometry.translate(0, 0, z * 2);
mesh.translateZ(-z * 2 + parentsZ);
for (const child of mesh.children) {
fixPivots(child); // Fix Fix Fix ALL the way down.
}
} |
I have fixed a similar issue in another loader by creating a custom 3D object class and implement pivot points there. In this way, you don't have to translate geometries but update the local/world matrices which is probably more what LWO expects. Maybe you can try to enhance class LWOMesh extends Mesh {
constructor() {
super();
this.pivot = new Vector3();
}
updateMatrix() {
this.matrix.compose( this.position, this.quaternion, this.scale );
const px = this.pivot.x;
const py = this.pivot.y;
const pz = this.pivot.z;
const te = this.matrix.elements;
te[ 12 ] += px - te[ 0 ] * px - te[ 4 ] * py - te[ 8 ] * pz;
te[ 13 ] += py - te[ 1 ] * px - te[ 5 ] * py - te[ 9 ] * pz;
te[ 14 ] += pz - te[ 2 ] * px - te[ 6 ] * py - te[ 10 ] * pz;
this.matrixWorldNeedsUpdate = true;
}
} Instead of creating instances of Would be great if you could give this a shot and report back how is it going. |
Not gonna lie, I totally forgot about coming back here. I've been using my hack for so long.. I never got around to making a lwo object to test all this.. It was this and another problem I found with using the wrong property for colour with different paint types. |
Without a test asset it's impossible to properly fix and test the issue. Closing for now. |
@Mugen87 I DID IT.... And the fix "eventually" ended up being super simple... parsePoints(length: number) {
this.currentPoints = [];
for (var i = 0; i < length / 4; i += 3) {
- // z -> -z to match three.js right handed coords
+ // x -> -x to match three.js right handed coords
this.currentPoints.push(
- this.reader.getFloat32(),
+ -this.reader.getFloat32(),
this.reader.getFloat32(),
- -this.reader.getFloat32(),
+ this.reader.getFloat32(),
);
}
} also changed the pivot code. - var layer = {
- number: this.reader.getUint16(),
- flags: this.reader.getUint16(), // If the least significant bit of flags is set, the layer is hidden.
- pivot: this.reader.getFloat32Array( 3 ), // Note: this seems to be superflous, as the geometry is translated when pivot is present
- name: this.reader.getString(),
- };
+ const number = this.reader.getUint16();
+ const flags = this.reader.getUint16(); // If the least significant bit of flags is set, the layer is hidden.
+ const [x, y, z] = this.reader.getFloat32Array(3);
+ var layer = {
+ number,
+ flags, // If the least significant bit of flags is set, the layer is hidden.
+ pivot: [-x, y, z], // Note: this seems to be superflous, as the geometry is translated when pivot is present
+ name: this.reader.getString(),
+ }; that fix was slightly less nice. But now, when I have a model that faces +z in Lightwave, it now correctly faces +z in three.js Also all the pivot points just "magically" work and has allowed me to get rid of nasty hack I had to run on every model load. function* flat<T>(meshes: T | T[]) {
if (Array.isArray(meshes)) {
yield* meshes;
} else {
yield meshes;
}
}
function* getObjects(meshes: THREE.Object3D | THREE.Object3D[]): Generator<THREE.Object3D> {
for (const mesh of flat(meshes)) {
yield mesh;
for (const m of mesh.children) {
yield* getObjects(m);
}
}
}
function fixPivots(meshes: THREE.Object3D[]) {
for (const mesh of getObjectsRecursive(meshes)) {
if (!(mesh instanceof THREE.Mesh) && !(mesh instanceof THREE.Points)) {
continue;
}
const [, , z] = mesh.userData?.pivot ?? [0, 0, 0]; // THIS IS
const parentsZ = (mesh.parent?.userData?.pivot?.[2] ?? 0) * 2; // COMPLETE AND
mesh.geometry.translate(0, 0, z * 2); // UTTER MADNESS
mesh.translateZ(-z * 2 + parentsZ); // I HATE IT
}
} and my other really bizarre stuff I had to do is also much MUCH simplified export function resetMatrix(matrix: THREE.Matrix3) {
return matrix.set(1, 0, 0, 0, 1, 0, 0, 0, 1);
}
export function resetVectorApplyMatrix(vector: THREE.Vector2, matrix: THREE.Matrix3) {
return vector.set(0, 0).applyMatrix3(matrix);
}
export function linkPiston(cylinder: THREE.Object3D, ram: THREE.Object3D) {
const arm = ram.parent;
if (!arm) {
throw new Error('Ram Parent is null');
}
// NEED A VERY SPECIFIC PARENT STRUCTURE TO MAKE THIS WORK
if (!cylinder.parent?.children.includes(arm)) {
throw new Error('Cylinder and Ram-Parent not siblings, you will need custom logic');
}
const siblingOffset = new THREE.Vector2(
arm.position.z - cylinder.position.z,
arm.position.y - cylinder.position.y,
);
const vector = new THREE.Vector2();
const matrix = new THREE.Matrix3();
let lastRotation: number | null;
return {
update() {
resetMatrix(matrix);
matrix.translate(ram.position.z, ram.position.y); // APPLY THE
matrix.rotate(arm.rotation.x); // MATRIX IN
matrix.translate(siblingOffset.x, siblingOffset.y); // REVERSE ORDER
resetVectorApplyMatrix(vector, matrix);
const cylinderRot = -vector.angle() + T(0.5);
cylinder.rotation.x = cylinderRot;
ram.rotation.x = cylinderRot - T(0.5) - currentRotation;
},
};
} TO THIS export function linkPiston(cylinder: THREE.Object3D, ram: THREE.Object3D) {
const tmp = new THREE.Vector3(0, 0, 0);
return {
update() {
ram.lookAt(cylinder.getWorldPosition(tmp));
cylinder.lookAt(ram.getWorldPosition(tmp));
},
};
} As you can imagine, I am very much happier to get rid of this hacky code once I realised what the problem was |
fix: IFFParser.js now reads x as -x instead of z to -z. This now sets the geometry and pivot points in the correct location. This fixes mrdoob#26733
fix: IFFParser.js now reads x as -x instead of z to -z. This now sets the geometry and pivot points in the correct location. This fixes mrdoob#26733
* [Loader] Fix for LWOLoader geometry correction fix: IFFParser.js now reads x as -x instead of z to -z. This now sets the geometry and pivot points in the correct location. This fixes #26733 * fix: webgl_loader_lwo updated with corrected coordinates for meshes and lights and cameras
Description
Hello, I've made a few objects in Lightwave and I use the LWOLoader to load them.
Layer 1, I modeled an object around
0,0,0
and I apply rotation on that mesh, and everything works as expected.On Layer 2, I modeled another object but I positioned it where it should be relative to Layer 1. But, being a little clever boy, I set the pivot point (Lets just say
2,1,0
). In Lightwave when I tell to rotate from the pivot point, it moves as expected.But when I use THREE to rotate the mesh, it rotates from
0,0,0
and not2,1,0
.Anyone know how to make LWO respect the layer's Pivot Point?
Reproduction steps
Code
// code goes here
Live example
Screenshots
No response
Version
r156
Device
No response
Browser
No response
OS
No response
The text was updated successfully, but these errors were encountered: