Ok, I found a way out avoiding again to learn GLSL

just after loading the obj, I traverse it and assign to every object inside it a custom attribute containing a random number:

```
obj.traverse(child => {
if (child instanceof THREE.Mesh) {
child.castShadow = true;
child.receiveShadow = true;
child.userData.rndmOffset = Math.random();
group.add(panel);
}
});
```

then i wrote a function to set up the uv map (obviously you need to create material, import texture and assign material to obj first.

I understand that to offset a texture map working on the uvs of a geometry is as simple as adding the same number to all uv vertex.

Imagine you have a box and you want to custom the uv map; you can traverse an object and set the UV for one or more face at the time;

Here’s an example:

```
scene.traverse(child => {
let geom = child.geometry;
if (child instanceof THREE.Mesh) {
let uvs = geom.faceVertexUvs;
let la = 0; // layer
let f1 = [0,2,8,10]; // face: 0=dx 2=sx 8=top 10=bottom
let f2 = [1,3,9,11]; // face: 1=dx 3=sx 9=top 11=bottom
for (var i = f1.length - 1; i >= 0; i--) {
uvs[la][f1[i]][0].x = 0.5;
uvs[la][f1[i]][0].y = 0;
uvs[la][f1[i]][1].x = 0;
uvs[la][f1[i]][1].y = 0;
uvs[la][f1[i]][2].x = 0.5;
uvs[la][f1[i]][2].y = 1;
uvs[la][f2[i]][0].x = 0;
uvs[la][f2[i]][0].y = 0;
uvs[la][f2[i]][1].x = 0;
uvs[la][f2[i]][1].y = 1;
uvs[la][f2[i]][2].x = 0.5;
uvs[la][f2[i]][2].y = 1;
}
geom.uvsNeedUpdate = true;
}
});
```

in this piece of code f1 is an array representing the first half of a face (a triangle) and f2 the second half. The goal is to have right, left, top, bottom faces (from camera perspective) mapped the same way.

You can of course change numerical values (0, 0.5) with variables and shorten the code using vector2.

Now if you want to offset that texture randomly for every children, what you have to do is to add child.userData.rndmOffset to every value, like this:

```
for (var i = f1.length - 1; i >= 0; i--) {
uvs[la][f1[i]][0].x = 0.5 + child.userData.rndmOffset;
uvs[la][f1[i]][0].y = 0 + child.userData.rndmOffset;
uvs[la][f1[i]][1].x = 0 + child.userData.rndmOffset;
uvs[la][f1[i]][1].y = 0 + child.userData.rndmOffset;
uvs[la][f1[i]][2].x = 0.5 + child.userData.rndmOffset;
uvs[la][f1[i]][2].y = 1 + child.userData.rndmOffset;
uvs[la][f2[i]][0].x = 0 + child.userData.rndmOffset;
uvs[la][f2[i]][0].y = 0 + child.userData.rndmOffset;
uvs[la][f2[i]][1].x = 0 + child.userData.rndmOffset;
uvs[la][f2[i]][1].y = 1 + child.userData.rndmOffset;
uvs[la][f2[i]][2].x = 0.5 + child.userData.rndmOffset;
uvs[la][f2[i]][2].y = 1 + child.userData.rndmOffset;
}
```

in this case you have an offset equal on both axis and based on a random number generated earlier.

I hope that this can be of any help to anyone.

Thank you.