I think @sebavan’s solution would work to convert UVs of any LHS mesh to RHS, regardless of how complex the mesh is.
yup, it should work the same on any meshes.
Only works on simple mesh with UV map 0,0 to 1,1 and zero rotation.
Unfortunately, most of the logic I have maps UV dynamically to account for rotation, scale, offsets (i.e UV can range from 0,0 to random numbers, like -1.6, 99). Even flipping V to -V is not enough.
Example: wall faces use coordinates to compute exact locations in 3d space to achieve continuous texture across sections (almost like tri-planar mapping).
Will sleep on this until I get a good solution…
I am not sure to understand as here we are speaking on creating meshes from only babylon created meshes like Cube Spheres and such not your complex GLTF ones ?
Yes, by Babylon created Meshes
I mean one of Babylon’s static MeshBuilder
methods, like MeshBuilder.CreatePolygon
, MeshBuilder.CreateBox
- I’m using and plan to use most of parametric shapes to allow users to draw/create custom Meshes inside the app. These cannot be imported as GLTF, because the user created them inside the app to begin within.
Each of Babylon’s created meshes alone is not hard to set UV map for. But combined, like wall sections with dynamic windows cutout using CSG, the UV mapping logic gets complex really fast.
Refactoring UV logic gets harder as the app adds more features using Babylon meshes.
Currently GLTF is only used for importing complex Mesh shapes created by Blender/other tools.
From user’s perspective, the app uses RHS with z up to be consistent with the most popular CAD software and physics convention (but in reality, it’s using Babylon LHS with y up)
the 1 - v trick should be ok though even outside the range 0-1 cause -1.6, 99 will be the exact opposite with repeat patterns ?
Thing is even right handed here would not solve it, as it is a UV convention issue. what is considered the top left of a texture is different.
That’s only the case with the assumption that your Texture repeat is exactly every 1,1
UV, with no offset, no scale, and no rotation.
Here is the example of UV difference for a Texture that maps roughly to 0.6 0.4
UV (where 1,1 is 1 meter by 1 meter surface area), even with zero offset, zero scale, zero rotation:
// the 1-x UV box
var uvs = box.getVerticesData(BABYLON.VertexBuffer.UVKind);
for (var i = 0; i < uvs.length; i += 2) {
uvs[i + 1] = 1 - uvs[i + 1];
}
box.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
The GLTF standard will not go away, if not becoming more popular.
Does this mean Babylon’s UV convention is not the same as GLTF? If I’m to refactor (and it’s not trivial work), I want to refactor to match GLTF standard.
Correct.
Could you share your example in the playground ?
Here is over-simplified PG version of what I have in the app (without taking absolute Mesh dimensions into account, and the cube has the simplest UV logic). It should produce identical looking cubes, but it’s not.
I tried different combinations, but it’s not possible for me to have Babylon UV sync with GLTF by modifying Mesh UVs, when accounting for rotation/scale/offset.
And I do want users to have an intuitive experience when editing texture, which I achieved, before introducing GLTF meshes.
Is it possible to override Babylon’s core UV mapping function that is called by all Babylon created meshes when applying materials? (if you could point me to the code where this is defined, that should be enough, I will hack my own version of Babylon that uses GLTF’s UV convention).
Ohhhh I see you are using texture transforms so yes this would not work as intented and I agree you d need to create the uvs similarly in both.
You can look into all the …Builder.ts files for the vertexData creation functions.
Hi @ecoin just checking in to see how things are there
I haven’t got a chance to fix this yet. Will probably have to fork my own Babylon, or submit a PR with some sort of flag to fix it.
It’s related to Babylon’s UV map convention history, as Sebavan pointed out, putting here for reference.
Hi Sebavan, after digging deeper, I believe this is an actual bug in Babylon, and not just my use case of mixing use of Babylon native Meshes with GLTF ones. Check this difference in normal map Texture taken from babylon docs:
Looks like a correct fix would be to:
- Disable Texture.constructor default .invertY = true option (so default is false)
- Refactor all native BABYLON.MeshBuilder.Create* methods to map UV from bottom left
My understanding after looking into the code is that UV mapping logic is spread all over different files (boxBuilder.ts, cylinderBuilder.ts, etc.), and there is no central place where this is controlled. Is this correct?
I don’t know Babylon well enough to know all the places where UV is mapped (for now I only know what I use), or else I’d have submitted PR a long time ago.
Images are all considered by Babylon.js to have (0, 0) at bottom left hand corner and (1, 1) at top right corner thus the image on this page
showing gltf v babylon file uvs is wrong. It is also wrong for the gltf file - both top left and bottom right cannot be (0, 0)
However the mapping of uvs to mesh could be wrong if vertex construction and index labelling was done without considering lettering…
For example CreatePolygon starts the uvs at the first vertex chosen, if this vertex happens to be the top right corner this places uv (0, 0) at this place.
It also looks like the cylinder was constructed with rings going in a clockwise direction thus mapping u increasing the wrong way round. As I am only on a mobile I will have to wait until tomorrow or the next day to fully investigate
Looking at the use of stored images on BJS StandardMaterials and Bump Map we can pick out the conventions.
The used images are
texture ----
normal map ------
By examining the vertexData or by using the PG export tool to save as a .babylon file the positions and uv data are
positions = [-0.5, -0.5, 0, 0.5 ,-0.5, 0, 0.5, 0.5, 0, -0.5, 0.5, 0]
uvs = [0, 0, 1, 0, 1, 1, 0, 1]
both of which have the order bottom left, bottom right, top right, top left
result is the PG plane - texture
Using the normal map above the direct use produces indents (left plane in PG below) and for raised sections additional properties invertNormalMapX and invertNormalMapY
have to be set on the material, see PG planes - bump map
In the following PG there are nine meshes created with Babylon.js using the same material, the writing varies from mesh to mesh. In all cases Babylon.js let V be a vertex assigned (u, v) to map the image, consistently this means that the image data for V is taken from the point a distance u from the bottom left hand corner measured horizontaly towards the right and a distance v from the bottom left hand corner measured vertically upwards. The difference in text direction comes from how the vertices are placed and indexed during construction.
In the PG above, looking at the two boxes the one on the right has wrap set to true which recalculates the vertex order for each side during construction, the cylinder is formed clockwise reflecting the text except on the top face, the capsule reflects the text as does the disc and extension.
There is nothing to say other mesh creation software doesn’t do similar things.
When importing, a mesh and/or texture can
- be from a left handed system y up, left handed system z up, right handed system y up, right handed system z up
- indent or raise bumps from a normal map
- reflect u or v values.
Applying scene.useRightHandedSystem = true; will not solve problems for all meshes from a mixed economy as it would correct issues for some and create some for others. Solutions would need to be applied to each individual mesh with appropriate menu options. Probably not what your wanted to hear.
2 should be able to be dealt with using invertNormalMapX and invertNormalMapY
3 should be able to be dealt with using uScale = -1 and/or vScale = 1
1 could possibly be dealt with if there was a mesh.reflect property.
This does not seem to be in alignment with my experience mapping UV in Babylon. This is how Babylon maps UV for Polygon sides when using MeshBuilder.CreatePolygon:
The proof of it is this Wall Tool:

You can test it in this 3D wall configurator using the picker (note, currently Texture has invertY = false
, because I need it to work with GTLF, and haven’t fixed this bug yet).
Yes, this is correct, I had to manually revert UV for Cylinder and Sphere from clockwise to counterclockwise direction to achieve correct mapping. Which was annoying, because at first, I expected Babylon to do correct mapping out of the box. I did not submit this as bug report because I thought it was supposed to work that way for left handed system. But TBH, I think it’s a bug too.
Tried this, did not work because I have GLTF from RHS, and Texture transform, which does not work with any scale inversion.
My point earlier is this:
Given:
I upload normal texture with raised bumps
Then:
Create new Texture(url, scene) with default options
Apply to Babylon created Mesh material also with all defaults
Expected:
Correctly raised bumps Material
Received:
Incorrectly indented Material
=> this seems like a clear bug to me, not sure how else should I describe it.
And I understand every point that everyone has mention in this thread. It still does not justify the fact that Babylon native Meshes produce incorrect UV mapping out of the box.
If this were Three.js, I’d have shut up a long time ago
But this is Babylon.js, which is known for ease of use!
@ecoin you are clearly undertaking a major and and detailed project which has discovered some bugs within the creation of Babylon.js meshes regarding text orientation. This can be very frustrating. What I am attempting to do is to analyse what and where the bugs are so they can be accurately presented to the core team along with possible solutions.
Depending where you see the light coming from you can see the 2D normal texture as having bumps or indents. I would argue that, like the left handed system, going for bumps and indents is a choice not a bug. Unrecei
ved expectations are not always a bug. You could argue that it is a wrong choice, however whether it is a bug or a wrong choice there is a way of applying a correction.
The cylinder and sphere are different issues. The text on the cylinder is reflected and no matter how you rotate the cylinder the text will remain reflected. The issue with the sphere is a viewing one, a rotation of 180o corrects the view.
Whilst what I said above is true on second thoughts it is not the only way, assigning uv values differently to vertices during mesh construction would solve some of the issues. For example in the following PG the text direction is corrected with external faceUV, with an added parameter to CreateCylinder something similar could be done on construction.
Not sure how you created the wall in your example, using a hole, as in this
PG wall.
Like the cylinder the polygon text issue for all faces would not be solved by the three functions I suggested
Sorry if I was not clear but to correct for RHS number 2 would also be necessary and applied first.
I have put forward some solutions in the feature request section
I used a separate Polygon for each Wall section, without Holes, because I need to dynamically do CSG for windows, doors, etc.
I can argue that this is not a subjective matter, because according to Babylon docs, it is supposed to work with OpenGL’s standard. So I uploaded a Normal Texture from the same Babylon docs to test. And it does not look like the original uploaded Texture with default settings. I had to set invertY: false
to make the normal direction correct, but then it had inverted the texture upside down, like posted above with screenshots, which you can easily repro in PG.
Here is the root cause of it all: