Zup, Yup, Xup - handedness space conversion?

I've been writing a dae collada importer, all is going well with geometries etc,

I am a little stuck to implement a quick method when it comes to converting geometry and transform data from Z-up, X-up to unitys Y-up world space.

I already can translate,rotate and scale geometry vertices on a node level to the correct positions by multiplying the imported vertex data by the geometry nodes transfrom data using a TRS matrix and MultiplyPoint3x4(vtx), but am looking for a decent/quick method to correct the vertex and transform data to correspond with unity's cartesian co-ord system.

some kind of vertex pos/translate pos from (a,b,c) to (b,0-a,c) and possibly some kind of quaternion or Euler.v3 from (a,b,c,w)/(a,b,c) to (0-c,b,0-a)

Any links to code or anything not too algebraic would be most usefull.

I found the below is working with Max and sketchup exports:

    private Vector3 UpPosConv(Vector3 v) {
    Vector3 r=new Vector3();
    //All x,y,z Up right handed -> Y_up left, Vertex or Translate Positions
    switch (up_axis) {
        case 0: //xR-yL
            r=new Vector3(0-v.y,v.x,0-v.z);
            break;
        case 1: //yR-yL
            r=new Vector3(v.x,v.y,0-v.z);
            break;
        case 2: //zR-zL
            r=new Vector3(v.x,v.z,v.y);
            break;
    }
    return r;
}       

private Vector3 UpScaleConv(Vector3 v) {
    Vector3 r=new Vector3();
    //All x,y,z Up right handed -> Y_up left, Scale Factors
    switch (up_axis) {
        case 0: //xR-yL
            r=new Vector3(v.y,v.x,v.z);
            break;
        case 1: //yR-yL
            r=new Vector3(v.x,v.y,v.z);
            break;
        case 2: //zR-zL
            r=new Vector3(v.x,v.z,v.y);
            break;
    }
    return r;
}

private Vector3 UpRotDirConv(Vector3 v) {
    Vector3 r=new Vector3();
    //All x,y,z Up right handed -> Y_up left,Convert Rotation(axis)Directions
    switch (up_axis) {
        case 0: //xR-yL
            r=new Vector3(v.y,0-v.x,v.z);
            break;
        case 1: //yR-yL
            r=new Vector3(0-v.x,0-v.y,v.z);
            break;
        case 2: //zR-zL
            r=new Vector3(0-v.x,0-v.z,0-v.y);
            break;
    }
    return r;
}

I am concerned that this may be wrong and is only working with the examples I can get hold of or create.

Unity's native Collada import not cutting it for you? I'm always interested in the shortcomings of such things. Working on X3D import myself. Sorry I don't have an answer for you handy, will see what I can find.

Thanks again for the response, its a runtime importer, I'll be publishing them soon for free, OBJ is working fantastically now, just finishing the DAE one, but dealing with grouping and parenting, so trying to find a efficient and conclusive method, however I understand code much better than algebra you find on wikipedia.

1 Answer

1

Took a while to get back with this, but for other people here’s my working fix:-

In 3D, we have a total of 48 different combinations of space coordinates to choose from:-

2 handed (or single axis flipped) systems x 3 axis x 4 (90 degree possible rotations around each (generally))x 2 (possible 2 flipped axis variations on the same hand same rotation) = 48 possibilities.

There are 6 ways to notate xyz in a file but this would essentially replicate one of the 48 possibilities simply converting it from one possibility to another.

The functions below will only cover translating from the 6 basic types (2 handed (or single axis flipped) systems x 3 axis) to Y-Up Left Hand system used by unity, so discounting the one that unity uses equals five conversions & one non conversion, this also presumes all notation is written x,y,z irrespective of direction.

I couldn’t find a way to do this with a matrix, was possibly thinking of a reflection matrix as the axis need shifting. Any optimisations, corrections, please amend.

private Vector3 PositionToYUpLH(Vector3 v,bool RightHanded,int UpAxis) { 
	Vector3 r=new Vector3();
	if (!RightHanded) {
		r=UpAxis==0?new Vector3(v.z,v.x,v.y):UpAxis==1?new Vector3(v.x,v.y,v.z):new Vector3(v.y,v.z,v.x);
	} else {
		r=UpAxis==0?new Vector3(0-v.z,v.x,v.y):UpAxis==1?new Vector3(0-v.x,v.y,v.z):new Vector3(0-v.y,v.z,v.x);
	}
	return r;
}	

private Vector3 RotationToYUpLH(Vector3 v,bool RightHanded,int UpAxis) { 
	Vector3 r=new Vector3();
	if (!RightHanded) {
		r=UpAxis==0?new Vector3(v.z,v.x,v.y):UpAxis==1?new Vector3(v.x,v.y,v.z):new Vector3(v.y,v.z,v.x);
	} else {
		r=UpAxis==0?new Vector3(v.z,0-v.x,0-v.y):UpAxis==1?new Vector3(v.x,0-v.y,0-v.z):new Vector3(v.y,0-v.z,0-v.x);
	}
	return r;
}	

private Vector3 ConvertScaleToYUpLH(Vector3 v,bool RightHanded,int UpAxis) { 
	Vector3 r=new Vector3();
	r=UpAxis==0?new Vector3(v.z,v.x,v.y):UpAxis==1?new Vector3(v.x,v.y,v.z):new Vector3(v.y,v.z,v.x);
	return r;
}

Thanks for sharing this code. It seems to work great except when there's an occasional rotate transform like so: <rotate>-0.5773503 0.5773503 0.5773503 -120</rotate> Instead of something like: <rotate>0 0 1 90</rotate> I cannot figure out why this rotation is formatted like that to begin with (this isn't part of the Collada documentation). Did you ever come across this issue? If so, how did you resolve it?