0

I currently have a city based on the example of Mr Doob's tutorial: "How to do a procedural city in 100 lines". In the tutorial you can see the that he creates 100 building meshes which then get merged into 1 city mesh for performance reasons. Then one material gets made that is applied to the city mesh, giving every building a texture.

What I want to stop is the clamping and stretching of the building texture. In order to create a more realistic "the windows are the same height on different buildings" look.

What I think would be the solution is to manipulate the face vertex UV's with the scaling values of the geometry.

With the following code I can scale the texture 2x.

  let faceVertexUvs = buildingMesh.geometry.faceVertexUvs[0];
  for (let k = 0; k < faceVertexUvs.length; k++) {
    const uvs = faceVertexUvs[k];
    if ( k == 4 || k == 5){
      // Make the roof blank
      uvs[0].set(0, 0);
      uvs[1].set(0, 0);
      uvs[2].set(0, 0);
    }
    else if( k % 2 == 0) {
      uvs[0].set(0, 0.5);
      uvs[1].set(0, 0);
      uvs[2].set(0.5, 0.5);
    }
    else {
      uvs[0].set(0, 0);
      uvs[1].set(0.5, 0);
      uvs[2].set(0.5, 0.5);
    }
  }

However I would like to only scale vertically and leave the horizontal scaling alone. But I don't completely understand the relation between the 2 triangles.

HermanChan
  • 65
  • 1
  • 8

2 Answers2

0

Perhaps you should modify the .repeat property of the city model's texture. document link: https://threejs.org/docs/#api/textures/Texture.repeat

Jim Tang
  • 92
  • 7
  • Ok yes but the same texture is applied to the whole city mesh. So buildings that are 400 units(?) tall have the same texture scaling (amount of windows) as buildings 10 units tall. Therefore I need something that can be applied to each individual building mesh. – HermanChan Feb 26 '18 at 14:49
  • Ah, you're right. So it's only way to change the UVs every single building. But the city demo is too old, CubeGeometry is deprecated by BoxGeometry, and the source code is a little bit complicated, maybe you can set some vertex color and use a checker texture to debug the indices and uvs information. – Jim Tang Feb 26 '18 at 17:12
  • Using a debug texture and guessing which values need to be changed I solved my problem. Thanks! – HermanChan Feb 26 '18 at 21:49
0

After using a debug image and guessing some values I came to the following code to scale a texture vertically, horizontally or both.

  let scale_y = buildingMesh.scale.y/200;
  let scale_x = buildingMesh.scale.x/100;

  for (let k = 0; k < faceVertexUvs.length; k++) {
    const uvs = faceVertexUvs[k];
    else if( k % 2 == 0) {
      uvs[0].set(0, texture_scale_y);                 // 0 1
      uvs[1].set(0, 0);                               // 0 0
      uvs[2].set(texture_scale_x, texture_scale_y);   // 1 1
    }
    else {
      uvs[0].set(0, 0);                               // 0 0
      uvs[1].set(texture_scale_x, 0);                 // 1 0
      uvs[2].set(texture_scale_x, texture_scale_y);   // 1 1
    }
  }

This solves my problem but I still would like to know the explanation. I can see that the X is always first and the Y second but that might be a bad conclusion to make.

I couldn't color my vertices so I can't tell which vertex is which.

HermanChan
  • 65
  • 1
  • 8
  • I think your code would be understandable if you avoided renaming your "uvs" to "faces". Do this, instead: `let faceVertexUvs = buildingMesh.geometry.faceVertexUvs[ 0 ];` and `uvs = faceVertexUvs[ k ]; and `uvs[ 0 ].set( 0, scale_y ); – WestLangley Feb 27 '18 at 16:06
  • Point taken and implemented. Do you know the relation between the UV's of the 2 triangles? Which vertices are the "shared" vertices and which one is the one not shared for example. – HermanChan Feb 28 '18 at 17:17
  • Render a `BoxGeometry` in wireframe to see the triangles. Try doing some experiments. – WestLangley Feb 28 '18 at 17:59