diff --git a/packages/dev/serializers/src/OBJ/objSerializer.ts b/packages/dev/serializers/src/OBJ/objSerializer.ts index 833c1384435..1da14c32633 100644 --- a/packages/dev/serializers/src/OBJ/objSerializer.ts +++ b/packages/dev/serializers/src/OBJ/objSerializer.ts @@ -4,6 +4,7 @@ import { Tools } from "core/Misc/tools"; import type { StandardMaterial } from "core/Materials/standardMaterial"; import type { Geometry } from "core/Meshes/geometry"; import type { Mesh } from "core/Meshes/mesh"; +import { Material } from "core/Materials/material"; /** * Class for generating OBJ data from a Babylon scene. @@ -30,29 +31,30 @@ export class OBJExport { output.push("mtllib " + matlibname + ".mtl"); } for (let j = 0; j < meshes.length; j++) { - const objectName = meshes[j].name || `mesh${j}}`; + const mesh = meshes[j]; + const objectName = mesh.name || `mesh${j}}`; output.push(`o ${objectName}`); //Uses the position of the item in the scene, to the file (this back to normal in the end) let inverseTransform: Nullable = null; if (globalposition) { - const transform = meshes[j].computeWorldMatrix(true); + const transform = mesh.computeWorldMatrix(true); inverseTransform = new Matrix(); transform.invertToRef(inverseTransform); - meshes[j].bakeTransformIntoVertices(transform); + mesh.bakeTransformIntoVertices(transform); } //TODO: submeshes (groups) //TODO: smoothing groups (s 1, s off); if (materials) { - const mat = meshes[j].material; + const mat = mesh.material; if (mat) { output.push("usemtl " + mat.id); } } - const g: Nullable = meshes[j].geometry; + const g: Nullable = mesh.geometry; if (!g) { Tools.Warn("No geometry is present on the mesh"); @@ -92,7 +94,8 @@ export class OBJExport { } const blanks: string[] = ["", "", ""]; - const [offset1, offset2] = useRightHandedSystem ? [2, 1] : [1, 2]; + const sideOrientation = mesh.overrideMaterialSideOrientation ?? mesh.material?.sideOrientation ?? mesh.getScene().defaultMaterial.sideOrientation; + const [offset1, offset2] = sideOrientation === Material.ClockWiseSideOrientation ? [2, 1] : [1, 2]; for (let i = 0; i < trunkFaces.length; i += 3) { const indices = [String(trunkFaces[i] + v), String(trunkFaces[i + offset1] + v), String(trunkFaces[i + offset2] + v)]; @@ -125,7 +128,7 @@ export class OBJExport { } //back de previous matrix, to not change the original mesh in the scene if (globalposition && inverseTransform) { - meshes[j].bakeTransformIntoVertices(inverseTransform); + mesh.bakeTransformIntoVertices(inverseTransform); } v += currentV; textureV += currentTextureV; diff --git a/packages/tools/tests/test/visualization/ReferenceImages/gltfToObjLH.png b/packages/tools/tests/test/visualization/ReferenceImages/gltfToObjLH.png new file mode 100644 index 00000000000..cd08c1fcfd0 Binary files /dev/null and b/packages/tools/tests/test/visualization/ReferenceImages/gltfToObjLH.png differ diff --git a/packages/tools/tests/test/visualization/ReferenceImages/gltfToObjRH.png b/packages/tools/tests/test/visualization/ReferenceImages/gltfToObjRH.png new file mode 100644 index 00000000000..cd08c1fcfd0 Binary files /dev/null and b/packages/tools/tests/test/visualization/ReferenceImages/gltfToObjRH.png differ diff --git a/packages/tools/tests/test/visualization/config.json b/packages/tools/tests/test/visualization/config.json index f83f3b24020..dce388dffb0 100644 --- a/packages/tools/tests/test/visualization/config.json +++ b/packages/tools/tests/test/visualization/config.json @@ -1154,6 +1154,17 @@ "replace": "//options//, roundTrip = true; useRightHandedSystem = true;", "referenceImage": "objStanfordBunnyNormalsRoundTripRH.png" }, + { + "title": "glTF to OBJ (LH)", + "playgroundId": "#HYZWGK#3", + "referenceImage": "gltfToObjLH.png" + }, + { + "title": "glTF to OBJ (RH)", + "playgroundId": "#HYZWGK#3", + "replace": "//options//, useRightHandedSystem = true;", + "referenceImage": "gltfToObjRH.png" + }, { "title": "GLTF Extension KHR_materials_variants", "playgroundId": "#BKGTKL#3",