Has anyone ever found a way to make configurable Uvs for shared vertices on a flat shaded cube?

I have a game where i make procedural generation like minecraft, every block is a cube.
I have managed with the help of some others to make every cube have 8 vertices, and be flat shaded with working lighting trough a custom shadergraph.

Only problem now, is that i cant set custom Uvs for every sepperate face of the cubes anymore, because uvs work per vertex, not per face.

Does anyone know if there is some hidden tricks, or a shadergraph or something that allows this “per face” uv behaviour?

I want to give cubes sepperate textures like below, so i can wrap these textures around each cube:
(these are solid color, but will become textures)

Im working in URP and use Entities Graphics (which is not important at the moment, but it will be later)

So awesome news, i did it.

I’m making this post to mark my question as answered and to help anyone out that is making something similar to this.
My english isnt great so ill try to provide as much clear information as possible, if anyone wants more details about anything regarding this post or similar, feel free to ask.

I have made (rather updated) a custom shadergraph to handle uvs and textures while respecting the 8 vertex based cube logic and the flat shading thats part of that.

This group of nodes:


returns a normal that is calculated from triangles, which always face the correct direction on a cube, not vertices (by default) who are “smoothed” because they have multiple triangles using them.

Putting that group of nodes into Normal World Space, makes the 8vertex cube flat shaded

Using only that, and inputing a texture > sample texture > into base color, makes a flat shaded cube with 8 vertices, but the texture is completely off, its stretched.

My cubes have their uvs calculated through a script based on their faceDirection, but because uvs are vertex based in Unitys mesh class, you cant properly give each of the 6 faces a seperate uv, because a vertex has to face 3 directions, it cant.

What i can do however, is give the left right, front and back face their uvs and store that in the XY of uv0 and give the top and bottom face their own uvs and store that in the ZW of uv0

switch (cFaceIndex)
{
    case 0: // back

        uvs[cVertexIndex + 0] = new float4(0, 0, 0, 0);
        uvs[cVertexIndex + 1] = new float4(1, 0, 1, 0);
        uvs[cVertexIndex + 2] = new float4(1, 1, 1, 0);
        uvs[cVertexIndex + 3] = new float4(0, 1, 0, 0);
        
        addedVertices = 4;
        
        break;

    case 1: // front

        uvs[cVertexIndex + 4] = new float4(1, 0, 1, 0);
        uvs[cVertexIndex + 5] = new float4(0, 0, 1, 1);
        uvs[cVertexIndex + 6] = new float4(0, 1, 1, 1);
        uvs[cVertexIndex + 7] = new float4(1, 1, 0, 1);

        addedVertices = 8;

        break;

    case 2: // right

        uvs[cVertexIndex + 1] = new float4(1, 0, 1, 0);
        uvs[cVertexIndex + 2] = new float4(1, 1, 1, 0);
        uvs[cVertexIndex + 5] = new float4(0, 0, 1, 1);
        uvs[cVertexIndex + 6] = new float4(0, 1, 1, 1);

        addedVertices = 7;

        break;

    case 3: // left

        uvs[cVertexIndex + 0] = new float4(0, 0, 0, 0);
        uvs[cVertexIndex + 3] = new float4(0, 1, 0, 0);
        uvs[cVertexIndex + 4] = new float4(1, 0, 0, 1);
        uvs[cVertexIndex + 7] = new float4(1, 1, 0, 1);

        addedVertices = 8;

        break;

    case 4: // top

        uvs[cVertexIndex + 2] = new float4(1, 1, 1, 0);
        uvs[cVertexIndex + 3] = new float4(0, 1, 0, 0);
        uvs[cVertexIndex + 6] = new float4(0, 1, 1, 1);
        uvs[cVertexIndex + 7] = new float4(1, 1, 0, 1);

        addedVertices = 8;

        break;


    case 5: // bottom

        uvs[cVertexIndex + 0] = new float4(0, 0, 0, 0);
        uvs[cVertexIndex + 1] = new float4(1, 0, 1, 0);
        uvs[cVertexIndex + 4] = new float4(1, 0, 0, 1);
        uvs[cVertexIndex + 5] = new float4(0, 0, 1, 1);

        addedVertices = 6;

        break;
}

I have a little more code going on, but this part makes uvs per face, and it knows what face its dealing with, faces facing right get the uvs for the right, left left, etc.

the X and Y coords are for the left, right, front and back faces, the Z and W coords are for the top and bottom faces, the shadergraph will do the rest of the math to fit the texture accordingly.

Im working with 1 giant texture png, that contains XtimesX T shaped textures, all containing 6 squares, for each of the faces of a cube, each T shape is 1 texture and the giant texture png (called a textureAtlas) is always as wide as long.
atlasSize is the length (and width) of the textureAtlas


This part creates with the help of textureIndex (stored in the first coord of uv1) the offset for the tiling and offset node, so the correct texture is used (according to “textureIndex”)
tiling is 1 fourth divided by atlas size, so 1 T texture is selected
“Zoom In” adds an offset to center the texture on the textureAtlas to the format of 1 T texture, which is then offsetted to the asked texture by textureIndex
I set the “textureIndexs” in the same script as above:

for (int i = 0; i < addedVertices; i++)
{
    textureData[cVertexIndex + i] = new float2(textureIndexs[cubeIndex], 0);
}

Then the uv handling:
Uv0 X and Y is used for left, right, front and back and is Inputted into a branch node for each of the faces (6)


Each face has a Dot product check, to see if the current face (triangle actually) is that face (eg left checks if triangles normal is (-1, 0, 0), if true

Add Uv for that triangle + 1block offset to the left, to get left face of T texture and go through a bunch of Add nodes and then Into the Uv of the sample texture

Up and bottom faces use Uv0 Z and W instead of X and Y


My attempted explanation is probably very, very useless, but if anyone asks a specific question about something, a script to share, idk, ill try to explain it better

heres the shader (convert filetype to .shadergraph before adding to unity, i could only send .txt files), have fun
Flat Shader.txt (291.5 KB)

1 Like