Material: Feature request to use world coordinates of vertex as UV

Description of the problem

There is an abundance of textures that can be repeated without showing seams. However, if they are applied to anything but the simplest of shapes (squares in a perfect grid), seams will re-emerge. One important feature of seamless textures is that the specific UVs are irrelevant. What matters is that the UVs are consistent between multiple shapes.

In the image, a “seamless” texture has been applied to a grid of hexagons (one of the 3 possible regular polygons that can form a grid). Circled are the intersecting hexagon vertices and arrows point to the edge. Seams have been reintroduced due to the fact that the texture was designed to be seamless over a square, not a hexagon. Some textures, especially ones with higher contrast, appear much worse with these seams.
Screenshot from 2020-03-29 13-59-20

Using debug texture to highlight that, while specific UVs work for grids of squares, they don’t for grids of hexagons (or triangles for that matter):
Screenshot from 2020-03-29 14-12-02

Describe the bug or feature request in detail

One way to achieve this consistency is the use a global coordinate system to drive the UVs, such as scene/world coordinates. There is a slight complication that the axis that translates world to uv coordinates is relevant to the process. Therefore, I propose that the axis be configurable. The lack of such an axis would indicate that the geometry’s specific, local UVs should be used.

Potential API: material.uvsAxis = quaternion | plane | vector (normal to plane)

Alternate API: material.uvsAxis = THREE.XZ | THREE.XY | THREE.YZ (only support 3 axes)

Alternate API: geometry.uvsAxis = (see above); material.useUvsAxis = true (allow each geometry to have its own UV axis.

Both would solve my problem, with the first being highly flexible. To be clear, the implementation would project the world coordinate onto the axis to determine the resulting UV coordinate.

Not a solution: User having to manually set the UVs of each vertex of each mesh at all times. This approach doesn’t support InstancedMesh, where each instance has the same UVs. It is also needlessly difficult.

Three.js version

As long as I can remember

Browser
  • All of them
OS
  • All of them

2 thoughts on “Material: Feature request to use world coordinates of vertex as UV

  1. You can accomplish this with custom shaders, or with the node material system in the examples:

    const material = new THREE.StandardNodeMaterial();
    const uv = new SwitchNode( new PositionNode(), 'xy' );
    material.color = new TextureNode( texture, uv );

    I don’t think world coordinates as UVs is likely to be supported in a way other than the ideas above — the problem of selecting an existing UV set for specific textures has been stalled for a while, even though it is easier and more common.

  2. In the end, it was trivial to add this feature and support instancing by using code-injection in the built-in material. NodeMaterial was not used.

    In meshphysical_vert.glsl.js:

    #include <worldpos_vertex>
    
    vec4 wPos = instanceMatrix * vec4( transformed, 1.0 );
    vUv = ( uvTransform * vec3( wPos.xz, 1 ) ).xy;