# How to repeat image texture on the mesh material based on the texture's actual size

**URL:** <https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883>\
**Category:** Questions\
**Tags:** rotation, texture-loader, texture-mapping, blurry-texture, mesh, textures, materials, geometry\
**Created:** [June 15, 2024, 5:22am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883 "2024-06-15T05:22:13Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 15, 2024, 5:22am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/1 "2024-06-15T05:22:13Z")

</div>

I am trying to repeat the tile image texture on the already create walls & floor mesh material.

what I am trying to do is apply all the available materials randomly on the floor or walls, but in current code i am able to choose one of the texture. also I want to keep ` texture.repeat.set(10, 10);` as ` texture.repeat.set(1, 1);` but if we keep (1,1) only one single texture covers whole area.

also how can we rotate whole texture in specific angle, like when we try 45,135 image were rotated but how to rotate those drawn lines ?

with 45 angle

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/5/350cc33edc53821a53a613885cbf020abc81a3c9.jpeg)

with 90 angle

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/7/17d66e57e60e1cc6b3eae41f4f617b1c2be70cbd.jpeg)

Queries :

1. how to repeat all the generated image textures with their original ratio on the mesh material based on the texture’s original size.
2. how to rotate whole texture repetition.

codepen link : [https://codepen.io/Vatsal-Pandya-the-solid/pen/PovEqgp](https://codepen.io/Vatsal-Pandya-the-solid/pen/PovEqgp)

I am new to ThreeJS, maybe this questions are very basic, any help or suggestions is much appreciated.Thanks in advance 🙂

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 16, 2024, 3:48pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/2 "2024-06-16T15:48:18Z")

</div>

Bump… Still stucked in this issue, help & suggestions required.

Thanks.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [June 16, 2024, 4:32pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/3 "2024-06-16T16:32:30Z")

</div>

I don’t think you want to do this:

```javascript
        const canvas = document.createElement("canvas");
        const context = canvas.getContext("2d");
        // Rotate the image if needed
        let rotatedImage = rotateImage(image, rotateAngle);

```

Instead set the texture.rotation = Math.PI \* .5 // Rotate the texture 90 degrees

[https://threejs.org/docs/#api/en/textures/Texture.rotation](https://threejs.org/docs/#api/en/textures/Texture.rotation)

and texture.repeat.set( 10, 10) //Make the texture repeat 10 times…

[https://threejs.org/docs/#api/en/textures/Texture.repeat](https://threejs.org/docs/#api/en/textures/Texture.repeat)

preserving the aspect ratio is a bit trickier math…

you’ll have to get it as aspect = image.width/image.height

then scale one axis of the repeat like texture.repeat.set(10, 10 / aspect )

Or smth, hth!

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 16, 2024, 4:51pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/4 "2024-06-16T16:51:18Z")

</div>

okay will give a try for rotation. and can you please guide how can we combine & create a new texture which is combination of some different textures.

> [@Vatsal\_Pandya](#):
>
> how to repeat all the generated image textures with their original ratio on the mesh material based on the texture’s original size.

something like this. I found one reference for this but not sure how to implement follow code file.  
[engine.tile.js](https://discourse.threejs.org/uploads/short-url/olKJatBSHt7Ifq1wy3GWJdVpBrd.js) (30.1 KB)

in this reference code they are rotating the texture and repeating them as well based on the angle.

Thanks in advance for the guidance

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 17, 2024, 3:50am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/5 "2024-06-17T03:50:33Z")

</div>

> [@manthrax](#):
>
> Instead set the texture.rotation = Math.PI \* .5 // Rotate the texture 90 degrees

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/d/cd543d6d7dfd9835324a53e47b7b16901aa6c6a7.jpeg)

it worked. thanks  
I kept value as 0.25 for 45 angle. is it correct ? any guide book to apply the number as per the angle value ?

```javascript
        texture.rotation = Math.PI * 0.25; // Rotate the texture 45 degrees

```

now wondering how can I repeat the different texture on mesh.

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/b/0/b024a4c1eddb7a6f393629ce4eb2f4824901b179.jpeg)

blurry lines in those area where multiple obstacles are present. there are 3 skybox layers for matt & glossy effect and below that tile texture layer exists. I assume blurriness occuring due to those multiple layers. as I want to apply glossy and matt effects on the tiles so those layers are above the tile texture mesh layer. **Is it possible to fix the issue without changing renderOrder of mesh and skyboxes ?**

please guide for this. Thanks in Advance

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 17, 2024, 7:51am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/6 "2024-06-17T07:51:05Z")

</div>

@manthrax I have reduced code of engine.tile.js and kept only default code as of now for grid layout.  
[engine.tile.js](https://discourse.threejs.org/uploads/short-url/m9SsU0VRQjLppIA6ANYrPZNzLfh.js) (16.3 KB)

now can you please guide how they are repeating it ?

overview of debug till now

**randsim** function is used to avoid repeating same tile texture next to each other.

they are creating texture material with following for loops, but not able to understand how they are positioning the textures.

```javascript
for (var qx = 0; qx * gtw <= plane_width + 1; qx++) {
        for (var qy = 0; qy * gth <= plane_height + 1; qy++) {
            var addThisFloor = true;
            var rgb = [temp_01 % 256, Math.floor(temp_01 / 256), index_m];
            var met_dat = {
                transparent: true,
                depthTest: false
            };
            if (for_indexize) {
                met_dat.color = "rgb(" + rgb + ")";
            } else {
                var isI = isIndexed(rgb + "");
                var isD = free_tid == 0 || isI;
                met_dat.map = randsim(imgs[(qx) % imgs.length], qx, qy, 'random', data[0]).texture;
                if (is_free && !isD) {
                    addThisFloor = false;
                }
            }
            if (addThisFloor) {
                var floorMaterial = new THREE.MeshBasicMaterial(met_dat);
                if (rotateAngle === 45 && typeof met_dat.map == "undefined") {
                    rotateTexture(floorGeometry, floorMaterial, rotateAngle, iw, ih);
                }
                floor = new THREE.Mesh(floorGeometry, floorMaterial);
                floor.position.x = (qx + 0.5) * gtw + skew_width * qy;
                floor.position.y = (qy + 0.5) * gth + skew_height * qx;
                floor.position.z = -index_m * 0.0001;
                obj.add(floor);
            }
            temp_01++;
        }
    }

```

data object values :

```javascript
{0: 1, 1: -149.5, 2: -123, 3: -168, 4: 0, 5: 71.5, 6: 0, 7: 500, 8: 500, 9: 22, 10: 22, 11: Array(8), 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 176: 'Wall', 177: 0}

```

output with data values

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/5/455780906e1ddd8a68b6462f3e0f4b851c75b77e.jpeg)

debug values :

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/0/1041339fda040d6d849337723d038f664793a194.png)

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 17, 2024, 9:58am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/7 "2024-06-17T09:58:08Z")

</div>

![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/d/4d651114e4d3de47a3c7b6b5e66abd6a7bf43059.jpeg)

even with the walls & floor layer only, texture lines looks blurry as distance increases from the camera point

I found that [anisotropy](https://threejs.org/docs/#api/en/textures/Texture.anisotropy) may help to fix this.

but how to calculate the required number to fix the issue. like this ?

```javascript
   texture.anisotropy = 100; 

```

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [June 17, 2024, 10:17am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/8 "2024-06-17T10:17:11Z")

</div>

Anisotropy range is 1-16  
`texture.anisotropy = renderer.capabilities.getMaxAnisotropy();`

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 17, 2024, 10:20am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/9 "2024-06-17T10:20:18Z")

</div>

I guess it worked. Thanks

could you guide further by reviewing above questions once, I want to repeat the texture as per the layer’s size.

Thanks in advance 🙂

---

<div class="post-metadata">

**Author:** ![Chaser\_Code](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/chaser_code/32/20199_2.png) [@Chaser\_Code](https://discourse.threejs.org/u/Chaser_Code)\
**Post date:** [June 17, 2024, 12:00pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/10 "2024-06-17T12:00:18Z")

</div>

For not angled objects like box you need for “Triplanar shader”.  
But maybe you need manualy change tile repeating by changing uv coordinates, not texture.repeat  
uv was 0,0,1,1 and now is like 0,0,10,10 then texture will repeats 10 times  
[![](https://blenderartists.org/uploads/default/optimized/4X/f/d/a/fda1337f4e9db88576cbbded337acfeceb808682_2_690x388.jpeg) ](https://blenderartists.org/uploads/default/optimized/4X/f/d/a/fda1337f4e9db88576cbbded337acfeceb808682_2_690x388.jpeg)

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 17, 2024, 12:03pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/11 "2024-06-17T12:03:30Z")

</div>

okay understood. I am implementing on flat surface, all objects are images only, 3D isn’t use for this.

I have shared a reference file here in which they have done mapping, I am trying to replicate that.

> [@Vatsal\_Pandya](#):
>
> [engine.tile.js](https://discourse.threejs.org/uploads/short-url/m9SsU0VRQjLppIA6ANYrPZNzLfh.js) (16.3 KB)

Thanks.

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 17, 2024, 2:04pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/12 "2024-06-17T14:04:18Z")

</div>

this is latest changes which I have managed with debugging and help of AI chatbot. still facing scaling issue a bit and texture became blurry.

```javascript
function loadTextureAndSetRepeat({
  element,
  rotateAngle = 0, // Default to 0 if not provided
}) {
  let surfaceData = element.userData;
  let currentTexture = tilesData[5]; 
  const imageUrls = currentTexture.imgUrl;
  const gth = (16 * currentTexture.height) / 500;
  const gtw = (16 * currentTexture.width) / 500;
  const plane_height = surfaceData.height;
  const plane_width = surfaceData.width;
  const textures = [];

  Promise.all(imageUrls.map(loadImage))
    .then((images) => {
      images.forEach((image) => {
        const canvas = document.createElement("canvas");
        const context = canvas.getContext("2d");

        canvas.width = image.width;
        canvas.height = image.height;
        context.drawImage(image, 0, 0, canvas.width, canvas.height);

        if (grout_v_width > 0 || grout_h_width > 0) {
          context.strokeStyle = grout_color;
          context.globalAlpha = grout_alpha;
          if (grout_v_width > 0) {
            context.lineWidth = grout_v_width;
            context.beginPath();
            context.moveTo(0, 0);
            context.lineTo(canvas.width, 0);
            context.closePath();
            context.stroke();
            context.beginPath();
            context.moveTo(0, canvas.height);
            context.lineTo(canvas.width, canvas.height);
            context.closePath();
            context.stroke();
          }
          if (grout_h_width > 0) {
            context.lineWidth = grout_h_width;
            context.beginPath();
            context.moveTo(0, 0);
            context.lineTo(0, canvas.height);
            context.closePath();
            context.stroke();
            context.beginPath();
            context.moveTo(canvas.width, 0);
            context.lineTo(canvas.width, canvas.height);
            context.closePath();
            context.stroke();
          }
          context.globalAlpha = 1;
        }

        const texture = new THREE.Texture(canvas);
        texture.premultiplyAlpha = false;
        texture.needsUpdate = true;
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
        texture.repeat.set(1, 1);

        textures.push(texture);
      });

      // Create a combined canvas
      const combinedCanvas = document.createElement("canvas");
      combinedCanvas.width = nextPowerOf2(plane_width);
      combinedCanvas.height = nextPowerOf2(plane_height);
      const combinedContext = combinedCanvas.getContext("2d");

      for (let indexQx = 0; indexQx * gtw <= combinedCanvas.width; indexQx++) {
        for (let indexQy = 0; indexQy * gth <= combinedCanvas.height; indexQy++) {
          const randomTexture = textures[Math.floor(Math.random() * textures.length)].image;
          combinedContext.drawImage(
            randomTexture,
            indexQx * gtw,
            indexQy * gth,
            gtw,
            gth
          );

          // Draw grout lines
          if (grout_v_width > 0) {
            combinedContext.strokeStyle = grout_color;
            combinedContext.globalAlpha = grout_alpha;
            combinedContext.lineWidth = grout_v_width;
            combinedContext.beginPath();
            combinedContext.moveTo(indexQx * gtw, indexQy * gth);
            combinedContext.lineTo((indexQx + 1) * gtw, indexQy * gth);
            combinedContext.lineTo((indexQx + 1) * gtw, (indexQy + 1) * gth);
            combinedContext.lineTo(indexQx * gtw, (indexQy + 1) * gth);
            combinedContext.closePath();
            combinedContext.stroke();
          }

          if (grout_h_width > 0) {
            combinedContext.strokeStyle = grout_color;
            combinedContext.globalAlpha = grout_alpha;
            combinedContext.lineWidth = grout_h_width;
            combinedContext.beginPath();
            combinedContext.moveTo(indexQx * gtw, indexQy * gth);
            combinedContext.lineTo(indexQx * gtw, (indexQy + 1) * gth);
            combinedContext.lineTo((indexQx + 1) * gtw, (indexQy + 1) * gth);
            combinedContext.lineTo((indexQx + 1) * gtw, indexQy * gth);
            combinedContext.closePath();
            combinedContext.stroke();
          }
        }
      }

      const combinedTexture = new THREE.Texture(combinedCanvas);
      combinedTexture.needsUpdate = true;
      combinedTexture.wrapS = THREE.RepeatWrapping;
      combinedTexture.wrapT = THREE.RepeatWrapping;
      combinedTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
      combinedTexture.repeat.set(plane_width / combinedCanvas.width, plane_height / combinedCanvas.height);

      // Map the combined texture to the element
      element.material.map = combinedTexture;
      element.material.needsUpdate = true;

      renderer.render(scene, camera);
    })
    .catch((error) => {
      console.error("Error loading images:", error);
    });

  // Function to load an image
  function loadImage(url) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.crossOrigin = "anonymous";
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    });
  }

  // Function to find the next power of 2
  function nextPowerOf2(x) {
    return Math.pow(2, Math.ceil(Math.log2(x)));
  }
}

```

output :

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/6/460c561af4b52a8996cdda7ecf9a011e6efdd7ec.jpeg)

expected similar output:

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/0/0/00b275c41676a7a583e476a8f063df27f175cf8f.jpeg)

thanks in advance

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 18, 2024, 1:36am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/13 "2024-06-18T01:36:36Z")

</div>

Bump… Still stucked in calculating number of repetitions & on blurred combined material.

Any suggestion or guidance is much appreciated. Thanks

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [June 18, 2024, 2:51am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/14 "2024-06-18T02:51:50Z")

</div>

yeah .25\*PI is 45 degrees.  
.5 is 90  
1 == 180  
2 == 360

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [June 18, 2024, 2:58am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/15 "2024-06-18T02:58:17Z")

</div>

If you have a world space size of an object…

For instance:

```javascript
let bounds = new THREE.Box3().setFromObject( yourObject );

```

and a texture (loaded from an image)  
and you want to tile the texture while preserving aspect ratio…  
Your calculation might look something like this:

```javascript
let {width,height} = texture.source.data; //Get texture dimensions
let textureAspect = width/height; //Get texture aspect ratio

let size = bounds.getSize(new THREE.Vector3()) //Get Object dimensions in world space

let modelAspect = size.x / size.y; //Get the aspect ratio of the model in worldspace
//This assumes you want x/y not z/y or something

texture.repeat.set(1,aspect/modelAspect); //Set the texture repeat as some function of both of those aspect ratios.. it might be * it might be /. But something like this...

```

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 18, 2024, 3:13am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/16 "2024-06-18T03:13:50Z")

</div>

Thanks @manthrax I will try this

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 18, 2024, 2:16pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/17 "2024-06-18T14:16:59Z")

</div>

I understood one thing that the tile images which I was using were not properly scaled. I have updated them.

also figured out to calculate the number of repetition.

_now the issue is currently creating the new combinedCanvas and appling on it. instead of that I want to update the intersected object’s material and also want to do repetition on it._

Edit : canvas is being generated as per the intersected wall / floor. just looping of repetition not working correctly

can someone guide ? thanks.

```javascript

function loadTextureAndSetRepeat({ element, rotateAngle = 0 }) {
  let surfaceData = element.userData;
  let randomIndex = Math.floor(Math.random() * tilesData.length);
  let currentTexture = tilesData[randomIndex];

  const imageUrls = currentTexture.imgUrl;
  const firstImageUrl = imageUrls[0];

  loadImage(firstImageUrl)
    .then((firstImage) => {
      const tiWidth = firstImage.width;
      const tiHeight = firstImage.height;
      var gtw = (informazione.wall_tile_w * tiWidth) / 500;
      var gth = (informazione.wall_tile_h * tiHeight) / 500;

      const plane_height = surfaceData.height;
      const plane_width = surfaceData.width;
      const textures = [];

      Promise.all(imageUrls.map(loadImage))
        .then((images) => {
          images.forEach((image) => {
            const canvas = document.createElement("canvas");
            const context = canvas.getContext("2d");
            canvas.width = nextPowerOf2(image.width);
            canvas.height = nextPowerOf2(image.height);
            context.drawImage(image, 0, 0, canvas.width, canvas.height);
            const texture = new THREE.Texture(canvas);
            texture.premultiplyAlpha = false;
            texture.needsUpdate = true;
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
            texture.repeat.set(5, 5);
            textures.push(texture);
          });

          // Create a combined canvas
          const combinedCanvas = document.createElement("canvas");
          combinedCanvas.width = plane_width;
          combinedCanvas.height = plane_height;
          const combinedContext = combinedCanvas.getContext("2d");
          for (let indexQx = 0; indexQx * gtw <= combinedCanvas.width; indexQx++) {
            for (let indexQy = 0; indexQy * gth <= combinedCanvas.height; indexQy++) {
              const randomTexture = textures[Math.floor(Math.random() * textures.length)].image;
              combinedContext.drawImage(randomTexture, indexQx * gtw, indexQy * gth, gtw, gth);

              // Draw grout lines
              if (grout_v_width > 0) {
                combinedContext.strokeStyle = grout_color;
                combinedContext.globalAlpha = grout_alpha;
                combinedContext.lineWidth = grout_v_width;
                combinedContext.beginPath();
                combinedContext.moveTo(indexQx * gtw, indexQy * gth);
                combinedContext.lineTo((indexQx + 1) * gtw, indexQy * gth);
                combinedContext.lineTo((indexQx + 1) * gtw, (indexQy + 1) * gth);
                combinedContext.lineTo(indexQx * gtw, (indexQy + 1) * gth);
                combinedContext.closePath();
                combinedContext.stroke();
              }

              if (grout_h_width > 0) {
                combinedContext.strokeStyle = grout_color;
                combinedContext.globalAlpha = grout_alpha;
                combinedContext.lineWidth = grout_h_width;
                combinedContext.beginPath();
                combinedContext.moveTo(indexQx * gtw, indexQy * gth);
                combinedContext.lineTo(indexQx * gtw, (indexQy + 1) * gth);
                combinedContext.lineTo((indexQx + 1) * gtw, (indexQy + 1) * gth);
                combinedContext.lineTo((indexQx + 1) * gtw, indexQy * gth);
                combinedContext.closePath();
                combinedContext.stroke();
              }
            }
          }

          const combinedTexture = new THREE.Texture(combinedCanvas);
          combinedTexture.needsUpdate = true;
          combinedTexture.wrapS = THREE.RepeatWrapping;
          combinedTexture.wrapT = THREE.RepeatWrapping;
          combinedTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
          combinedTexture.repeat.set(1, 1);

          // Map the combined texture to the element
          element.material.map = textures[0];
          element.material.needsUpdate = true;

          renderer.render(scene, camera);
        })
        .catch((error) => {
          console.error("Error loading images:", error);
        });
    })
    .catch((error) => {
      console.error("Error loading first image:", error);
    });
}

```

tilesData

```javascript
var tilesData = [
  {
    index: 1,
    imgUrl: [
      "images/1/1.jpg",
      "images/1/2.jpg",
      "images/1/3.jpg",
      "images/1/4.jpg",
      "images/1/5.jpg",
      "images/1/6.jpg",
      "images/1/7.jpg",
      "images/1/8.jpg",
    ],
    width: 600,
    height: 600,
  },
];

var informazione = {
  floor_tile_w: 6,
  floor_tile_h: 12,
  wall_tile_w: 12,
  wall_tile_h: 6,
  camera_fov: 75,
  camera_position_x: 0,
  camera_position_y: 0,
  camera_position_z: 3,
  intensity: 0.98,
  R_intensity: 0.01,
  wall_tile_width: 2400,
  wall_tile_height: 1200,
  floor_tile_width: 2400,
  floor_tile_height: 1200,
};

```

output with combinedTexture

```javascript
          element.material.map = combinedTexture;

```

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/b/3b10a655e3a1312ca6233214bb32f56549110a7f.jpeg)

output when we just map image texture

```javascript
          element.material.map = textures[0];

```

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/a/ca1d71402d3977210995cc47668b260149bb5898.jpeg)

as image scale is small and repeated in 1,1 set so it became blurry. trying to manage it with repetition loop

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 18, 2024, 3:49pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/18 "2024-06-18T15:49:42Z")

</div>

I have applied changes as per the reference, I am not able to set the obj on the same position as the actual element.

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/0/0/0093066cf6d634340fc12da388ba68f4d447d76c.jpeg)

```javascript

function loadTextureAndSetRepeat({ element, rotateAngle = 0 }) {
  let surfaceData = element.userData;
  let randomIndex = Math.floor(Math.random() * tilesData.length);
  let currentTexture = tilesData[randomIndex];

  const imageUrls = currentTexture.imgUrl;
  const firstImageUrl = imageUrls[0];

  loadImage(firstImageUrl)
    .then((firstImage) => {
      const tiWidth = firstImage.width;
      const tiHeight = firstImage.height;
      const tile_rate_w = informazione.wall_tile_w;
      const tile_rate_h = informazione.wall_tile_h;
      var gtw = (tile_rate_w * tiWidth) / 500;
      var gth = (tile_rate_h * tiHeight) / 500;

      // Adjust geometry for skew using BufferGeometry
      const floorGeometry = new THREE.PlaneGeometry(gtw, gth);
      const skew_vertical = 0.1; // example value, set accordingly
      const skew_horizontal = 0.1; // example value, set accordingly
      const skew_width = gth / Math.tan((1 - skew_vertical) * Math.PI / 2);
      const skew_height = gtw / Math.tan((1 - skew_horizontal) * Math.PI / 2);

      const position = floorGeometry.attributes.position;
      position.setX(0, position.getX(0) + skew_width);
      position.setX(1, position.getX(1) + skew_width);
      position.setY(1, position.getY(1) + skew_height);
      position.setY(3, position.getY(3) + skew_height);
      position.needsUpdate = true;

      const plane_height = surfaceData.height;
      const plane_width = surfaceData.width;
      const textures = [];

      Promise.all(imageUrls.map(loadImage))
        .then((images) => {
          images.forEach((image) => {
            const canvas = document.createElement("canvas");
            const context = canvas.getContext("2d");
            canvas.width = nextPowerOf2(image.width);
            canvas.height = nextPowerOf2(image.height);
            context.drawImage(image, 0, 0, canvas.width, canvas.height);
            const texture = new THREE.Texture(canvas);
            texture.premultiplyAlpha = false;
            texture.needsUpdate = true;
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
            texture.repeat.set(1, 1);
            textures.push(texture);
          });

          const obj = new THREE.Object3D();
          // const imgs = textures.map(texture => texture.image);

          for (let qx = 0; qx * gtw <= plane_width + 1; qx++) {
            for (let qy = 0; qy * gth <= plane_height + 1; qy++) {
              const met_dat = {
                transparent: true,
                depthTest: false,
                map: textures[Math.floor(Math.random() * textures.length)],
              };
              const floorMaterial = new THREE.MeshBasicMaterial(met_dat);
              const floor = new THREE.Mesh(floorGeometry, floorMaterial);
              floor.position.x = (qx + 0.5) * gtw + skew_width * qy;
              floor.position.y = (qy + 0.5) * gth + skew_height * qx;
              floor.position.z = -Math.random() * 0.0001; // Random small offset for layering
              obj.add(floor);
            }
          }
          console.log("surfaceData", surfaceData)
          obj.position.set(
            surfaceData["position-x"],
            surfaceData["position-y"],
            surfaceData["position-z"]
          );
          // obj.position.set(
          // 1,
          // 0,
          // 0
          // );
          // obj.rotation.x = surfaceData.rotateX;
          scene.add(obj);

          renderer.render(scene, camera);
        })
        .catch((error) => {
          console.error("Error loading images:", error);
        });
    })
    .catch((error) => {
      console.error("Error loading first image:", error);
    });
}

```

surface Data object

```javascript
{
    "name": "Wall 3",
    "face": "wall",
    "width": 285,
    "height": 285,
    "position-x": -79,
    "position-y": 102,
    "position-z": -101,
    "rotateX": 3.141592653589793,
    "color": 0xfff000, //default color without any texture
    "rotation-y": 0
}

```

please suggest the approach to apply the object on the element OR is it any better way to do the same thing ?

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 22, 2024, 6:33pm UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/19 "2024-06-22T18:33:37Z")

</div>

Bump…

please someone guide 🙂

Thanks in advance

---

<div class="post-metadata">

**Author:** ![Vatsal\_Pandya](https://avatars.discourse-cdn.com/v4/letter/v/b9e5f3/32.png) [@Vatsal\_Pandya](https://discourse.threejs.org/u/Vatsal_Pandya)\
**Post date:** [June 23, 2024, 6:15am UTC](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883/20 "2024-06-23T06:15:40Z")

</div>

here is my code to set object in the same place of wall

```javascript
function loadTextureAndSetRepeat({ element, rotateAngle = 0 }) {
  let surfaceData = element.userData;
  let randomIndex = Math.floor(Math.random() * tilesData.length);
  let currentTexture = tilesData[randomIndex];

  const imageUrls = currentTexture.imgUrl;
  const firstImageUrl = imageUrls[0];

  loadImage(firstImageUrl)
    .then((firstImage) => {
      const tiWidth = firstImage.width;
      const tiHeight = firstImage.height;
      const tile_rate_w = 22;
      const tile_rate_h = 22;
      var gtw = (tile_rate_w * tiWidth) / 500;
      var gth = (tile_rate_h * tiHeight) / 500;

      // Adjust geometry for skew using BufferGeometry
      const floorGeometry = new THREE.PlaneGeometry(gtw, gth);
      const skew_vertical = 0; // example value, set accordingly
      const skew_horizontal = 0; // example value, set accordingly
      const skew_width = gth / Math.tan(((1 - skew_vertical) * Math.PI) / 2);
      const skew_height = gtw / Math.tan(((1 - skew_horizontal) * Math.PI) / 2);
      const plane_height = surfaceData.height;
      const plane_width = surfaceData.width;
      const position = floorGeometry.attributes.position;
      position.setX(0, position.getX(0) + skew_width);
      position.setX(1, position.getX(1) + skew_width);
      position.setY(1, position.getY(1) + skew_height);
      position.setY(3, position.getY(3) + skew_height);
      position.needsUpdate = true;

      const textures = [];

      Promise.all(imageUrls.map(loadImage))
        .then((images) => {
          images.forEach((image) => {
            const canvas = document.createElement("canvas");
            const context = canvas.getContext("2d");
            canvas.width = nextPowerOf2(image.width);
            canvas.height = nextPowerOf2(image.height);
            context.drawImage(image, 0, 0, canvas.width, canvas.height);
            const texture = new THREE.Texture(canvas);
            texture.premultiplyAlpha = false;
            texture.needsUpdate = true;
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
            texture.repeat.set(1, 1);
            textures.push(texture);
          });

          const obj = new THREE.Object3D();
          for (let qx = 0; qx * gtw <= plane_width + 1; qx++) {
            for (let qy = 0; qy * gth <= plane_height + 1; qy++) {
              const met_dat = {
                transparent: true,
                depthTest: false,
                map: textures[Math.floor(Math.random() * textures.length)],
              };
              const floorMaterial = new THREE.MeshBasicMaterial(met_dat);
              const floor = new THREE.Mesh(floorGeometry, floorMaterial);
              floor.position.x = (qx + 0.5) * gtw + skew_width * qy;
              floor.position.y = (qy + 0.5) * gth + skew_height * qx;
              floor.position.z = -Math.random() * 0.0001; // Random small offset for layering
              obj.add(floor);
            }
          }

          obj.position.x = surfaceData["position-x"] || 0;
          obj.position.y = surfaceData["position-y"] || 0;
          obj.position.z = surfaceData["position-z"] || 0;
          scene.add(obj);

          renderer.render(scene, camera);
        })
        .catch((error) => {
          console.error("Error loading images:", error);
        });
    })
    .catch((error) => {
      console.error("Error loading first image:", error);
    });
}

```

wall creation code :

```javascript
  for (const element of data) {
    if (element.face.toLowerCase() === "wall") {
      const wallGeometry = new THREE.PlaneGeometry(
        element.width,
        element.height
      );
      const wallMaterial = new THREE.MeshBasicMaterial({
        map: defaultWallTexture, // Use default texture
        side: THREE.DoubleSide,
        depthTest: true,
      });
      const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
      wallMesh.userData = element;
      wallMesh.position.set(
        element["position-x"],
        element["position-y"],
        element["position-z"]
      );
      wallMesh.rotation.y = element["rotation-y"];
      wallMesh.rotation.x = element.rotateX;
      group.add(wallMesh);
    }
    if (element.face.toLowerCase() === "floor") {
      const floorGeometry = new THREE.PlaneGeometry(
        element.width,
        element.height
      );
      const floorMaterial = new THREE.MeshBasicMaterial({
        map: defaultFloorTexture, // Use default texture
        side: THREE.DoubleSide,
        depthTest: true,
      });
      const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
      let dataObj = element;
      floorMesh.userData = dataObj;
      floorMesh.position.set(
        element["position-x"],
        element["position-y"],
        element["position-z"]
      );
      floorMesh.rotation.x = Math.PI / 2;
      group.add(floorMesh);
    }
  }

```

current output

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/9/490f842e1e4fc6de8959ee96a55597fa721ab08d.jpeg)

I am not able to identify how to set new object in the place of actual wall ?

please guide.

Thanks

[Next page](https://discourse.threejs.org/t/how-to-repeat-image-texture-on-the-mesh-material-based-on-the-textures-actual-size/66883.md?page=2)
