# Sandbox: The KHR\_texture\_transform property of GLTFExport cannot be exported

**URL:** <https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425>\
**Category:** Bugs\
**Tags:** gltf, gltfexport\
**Created:** [December 17, 2024, 12:10pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425 "2024-12-17T12:10:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![brightMoon](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/brightmoon/32/9959_2.png) [@brightMoon](https://forum.babylonjs.com/u/brightMoon)\
**Post date:** [December 17, 2024, 12:10pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/1 "2024-12-17T12:10:00Z")

</div>

In the Sandbox, adjust the wAng of the texture, and then export glb：

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/c/5/c546165af49361e85d59fa8634437188817adf64.jpeg)

prompt exporter: Texture BoomBox\_Mat (Base Color) with rotation not centered at the origin cannot be exported with KHR\_texture\_transform

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/c/b/cbff830502465e3d9403f37e167d2011d580eed5.png)

By checking the source code, it is found that uRotationCenter and vRotationCenter cannot be exported when they are not 0, view code:

```auto
if (babylonTexture.uAng !== 0 || babylonTexture.vAng !== 0) {
    Tools.Warn(`${context}: Texture ${babylonTexture.name} with rotation in the u or v axis is not supported in glTF.`);
    resolve(null);
} else if (babylonTexture.wAng !== 0 && (babylonTexture.uRotationCenter !== 0 || babylonTexture.vRotationCenter !== 0)) {
    Tools.Warn(`${context}: Texture ${babylonTexture.name} with rotation not centered at the origin cannot be exported with ${NAME}`);
    resolve(null);
} else {
    resolve(babylonTexture);
}

```

For the default texture, both uRotationCenter and vRotationCenter are 0.5：

> <https://github.com/BabylonJS/Babylon.js/blob/286942025fd42d09b948e0449ebeb52bec498e27/packages/dev/core/src/Materials/Textures/texture.ts#L265-L275>

So this is where the cause lies, is it reasonable

* * *

When loading glb with KHR\_texture\_transform extension attribute, uRotationCenter and vRotationCenter will be set to 0, see:

> <https://github.com/BabylonJS/Babylon.js/blob/286942025fd42d09b948e0449ebeb52bec498e27/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_texture_transform.ts#L70-L71>

So how to export wAng from KHR\_texture\_transform in glTFExporter

---

<div class="post-metadata">

**Author:** ![Deltakosh](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/deltakosh/32/26635_2.png) [@Deltakosh](https://forum.babylonjs.com/u/Deltakosh)\
**Post date:** [December 17, 2024, 5:46pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/3 "2024-12-17T17:46:54Z")

</div>

cc @alexchuber

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [December 18, 2024, 4:27pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/4 "2024-12-18T16:27:35Z")

</div>

I’ll look into this this week 🙂 I’m not yet familiar with the spec for KHR\_texture\_transform, but this is the perfect excuse to read up on it.

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [December 18, 2024, 7:50pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/5 "2024-12-18T19:50:45Z")

</div>

Nevermind, this was a lot quicker than expected.

TL;DR: the KHR\_texture\_transform spec defines that rotations must be applied at the origin, but we should be able to calculate this ourselves by displacing the `offset` property using `uRotationCenter` and `vRotationCenter`.

PR: [Adjust KHR\_texture\_transform offset for non-zero rotation center by alexchuber · Pull Request #16015 · BabylonJS/Babylon.js · GitHub](https://github.com/BabylonJS/Babylon.js/pull/16015)

---

<div class="post-metadata">

**Author:** ![brightMoon](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/brightmoon/32/9959_2.png) [@brightMoon](https://forum.babylonjs.com/u/brightMoon)\
**Post date:** [December 19, 2024, 12:43pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/6 "2024-12-19T12:43:43Z")

</div>

I just tried using the latest version of the sandbox, adjusted wAngle and offset, and exported it. However, when I imported the exported model back into the sandbox, the results were inconsistent.

Before exporting：

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/a/2/a292863419d89472d0cae8a1d718d8f2f92f4890.jpeg)

After exporting:

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/1/6/167a97777dc7bb49129280852dc76ff86c3408b6.jpeg)

So is there a problem with this？

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [December 19, 2024, 4:11pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/7 "2024-12-19T16:11:42Z")

</div>

Ah, I need a coffee. I must have overlooked scaling. Let me give it another go.

---

<div class="post-metadata">

**Author:** ![sebavan](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/sebavan/32/57_2.png) [@sebavan](https://forum.babylonjs.com/u/sebavan)\
**Post date:** [December 19, 2024, 4:56pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/8 "2024-12-19T16:56:14Z")

</div>



---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [December 19, 2024, 9:25pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/9 "2024-12-19T21:25:04Z")

</div>

Gave it a go and didn’t get far. Let’s just go back to the original behavior if scaling is not 1 🙂 [Limit cases where KHR\_texture\_transform offset is adjusted for non-origin rotation by alexchuber · Pull Request #16019 · BabylonJS/Babylon.js · GitHub](https://github.com/BabylonJS/Babylon.js/pull/16019)

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [January 6, 2025, 3:22pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/10 "2025-01-06T15:22:23Z")

</div>



---

<div class="post-metadata">

**Author:** ![Anupam\_Das](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/anupam_das/32/16709_2.png) [@Anupam\_Das](https://forum.babylonjs.com/u/Anupam_Das)\
**Post date:** [January 24, 2025, 4:01am UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/11 "2025-01-24T04:01:03Z")

</div>

@alexchuber I too am experiencing issues with this (ive tried latest as well as the version we were using (^7.14.0). Infact, when I use latest, NONE of the scaling and rotation is being exported correctly so its even more broken. (we use uv scaling/offsets pretty much on every material).  
with 7.14.0 I am essentially seeing the above discussed behavior and warning. Soooo any updates on this?

I see the comment in the PR:  
/\*\*

- Computes the adjusted offset for a rotation centered about the origin.
- This does not work when scaling is involved; investigation is needed.
- @internal  
\*/

i’ll assume this is still being actively investigated? I’ll try to dig around and see if I can fix it but would appreciate your assistance.

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [January 24, 2025, 5:50pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/12 "2025-01-24T17:50:52Z")

</div>

Hi there,

Could you share a playground example of the issue?

Exporting texture rotation is tricky. We can’t export any rotation along the U or V axes, as there is no equivalent representation in the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform#gltf-schema-updates) spec. The schema only supports W rotation around the origin.

Up until recently, this meant that we would not export any W rotation if either of the U and V rotation centers were not at the origin. But, when I initially encountered this post, I had the idea of baking this transform to the origin in the U and V offsets-- which is where you found that comment-- so long as scaling was uninvolved. I couldn’t derive the right equation to account for scaling. I’m not sure if it is impossible, or if I just didn’t find it 😉

While this is not being actively investigated, I’d be happy to support anyone looking to tackle the issue. You could also make a feature request.

In any case, the best way to approach exporting texture transforms would be to make sure that your materials U and V rotation centers are at 0. It’s regrettable that the Babylon default values for these are not 0, but I doubt it’d be worth the breaking change to update them.

---

<div class="post-metadata">

**Author:** ![Anupam\_Das](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/anupam_das/32/16709_2.png) [@Anupam\_Das](https://forum.babylonjs.com/u/Anupam_Das)\
**Post date:** [January 24, 2025, 6:11pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/13 "2025-01-24T18:11:43Z")

</div>

Greetings, thanks for the quick response. I made a small modification to your code. Seems like its better ish but still does not match exactly. I guess for now we dont really need the pivot to match exactly on export as long as the UVs are rotated and scales are correct. The resulting asset for us has pretty close visual appearance. the below solution seems to work better but still not good enough for a PR 😉 Im going to try to undregister the babylonjs KHR\_texture\_transform and register our own on export. Hoping that will unblock us for now. Perhaps the below code will inspire some further ideas.

```auto
/**
 * Computes the adjusted offset for a rotation centered about the origin.
 * @internal
 */
function AdjustOffsetForRotationCenter(babylonTexture: Texture): [number, number] {
    const { uOffset, vOffset, uRotationCenter, vRotationCenter, wAng, uScale, vScale } = babylonTexture;
    const cosAngle = Math.cos(-wAng);
    const sinAngle = Math.sin(-wAng);
    
    // Apply scaling to rotation center coordinates
    const scaledUCenter = uRotationCenter * uScale;
    const scaledVCenter = vRotationCenter * vScale;
    
    // Calculate offset adjustments with scaling
    const deltaU = scaledUCenter * (1 - cosAngle) - scaledVCenter * sinAngle;
    const deltaV = scaledVCenter * (1 - cosAngle) + scaledUCenter * sinAngle;
    
    // Apply scaling to the final offset
    return [
        (uOffset + deltaU) * uScale,
        (vOffset + deltaV) * vScale
    ];
}

```

then just need to change the part where we check wAng

```auto
       if (babylonTexture.wAng !== 0) {
            if (babylonTexture.uRotationCenter !== 0 || babylonTexture.vRotationCenter !== 0) {
                Tools.Warn(`${context}: Texture ${babylonTexture.name} with rotation not centered at the origin will be exported with an adjusted texture offset for ${NAME}.`);
                textureTransform.offset = AdjustOffsetForRotationCenter(babylonTexture);
            }
            textureTransform.rotation = -babylonTexture.wAng;
            transformIsRequired = true;
        }

```

I’ll try to get this shim working, if not I’ll post a PG example. But to repro: any asset that has wAng, scales are ignored on export.

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [January 24, 2025, 6:38pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/14 "2025-01-24T18:38:40Z")

</div>

The code you posted is on the right track 🙂 That’s one of the methods I tried-- but, as you’ve already pointed out, the visual result was not exact. If we want to support scaling with wAng at a non-origin, I think we’d either want to get it 100% right or not support it at all. Otherwise, it might lead to more confusion.

As far as the repro goes… that is odd. If I recall correctly, in the past, assets with non-origin rotation center + wAng + scale would have ~~exported with just their scale only, no rotation at all~~ not exported KHR\_texture\_transform at all. That should be the same behavior today.

---

<div class="post-metadata">

**Author:** ![Anupam\_Das](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/anupam_das/32/16709_2.png) [@Anupam\_Das](https://forum.babylonjs.com/u/Anupam_Das)\
**Post date:** [January 24, 2025, 6:44pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/15 "2025-01-24T18:44:30Z")

</div>

I agree with you, cant really make any updates at the core API without getting it 100% right. Hence my attempt to override the extension behavior with our own code. I’ll keep you posted. At the very least it might be useful for people to see how to customize the exporter for their own needs/usecase.

---

<div class="post-metadata">

**Author:** ![Anupam\_Das](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/anupam_das/32/16709_2.png) [@Anupam\_Das](https://forum.babylonjs.com/u/Anupam_Das)\
**Post date:** [January 25, 2025, 6:02am UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/16 "2025-01-25T06:02:14Z")

</div>

@alexchuber instead of moving this thread off topic I decided to just post a new topic on how to create a custom extension handeler on export. Unfortunately I dont seem to have access to the GLTFExport api to register/unregister my own extensions on export. see: [How to register/unregister custom extensions when using GLTF2Exporter](https://forum.babylonjs.com/t/how-to-register-unregister-custom-extensions-when-using-gltf2exporter/56184)

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [January 27, 2025, 3:35pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/18 "2025-01-27T15:35:38Z")

</div>

Sounds good, we will talk more there about registering extensions.

Could you confirm, though, that behavior hasn’t regressed in the latest version? When I try to repro by exporting with a non-zero origin + wAng + scale, in both versions, I get a warning and the KHR\_texture\_transform extension is (intentionally and correctly) not exported at all.

---

<div class="post-metadata">

**Author:** ![Anupam\_Das](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/anupam_das/32/16709_2.png) [@Anupam\_Das](https://forum.babylonjs.com/u/Anupam_Das)\
**Post date:** [January 27, 2025, 5:30pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/19 "2025-01-27T17:30:27Z")

</div>

It seems it has regressed at least from my tests. I’ll post a repro here from latest version vs the BJS version we were using (^7.14.0) sometime today.

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [January 27, 2025, 6:05pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/20 "2025-01-27T18:05:08Z")

</div>

That would be great, thanks!

---

<div class="post-metadata">

**Author:** ![sebavan](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/sebavan/32/57_2.png) [@sebavan](https://forum.babylonjs.com/u/sebavan)\
**Post date:** [January 27, 2025, 7:02pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/21 "2025-01-27T19:02:59Z")

</div>

@Anupam_Das the repro would be much helpful thanks a lot

---

<div class="post-metadata">

**Author:** ![alexchuber](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alexchuber/32/52000_2.png) [@alexchuber](https://forum.babylonjs.com/u/alexchuber)\
**Post date:** [February 5, 2025, 6:35pm UTC](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425/22 "2025-02-05T18:35:00Z")

</div>



[Next page](https://forum.babylonjs.com/t/sandbox-the-khr-texture-transform-property-of-gltfexport-cannot-be-exported/55425.md?page=2)
