Подгонка для масштабирования отображенной текстуры на плоскости в THREE.js

#javascript #three.js

#javascript #three.js

Вопрос:

Я пытаюсь «подгонять к масштабированию» отображенную текстуру изображения на одной плоскости. своего рода имитация поведения object-fit:cover .

Таким образом, карта изображения должна увеличиваться или уменьшаться пропорционально, чтобы полностью покрыть всю плоскость.

Я попытался поиграть с повторением и смещением текстуры, но безуспешно. (прокомментировано в моем коде)

Как вы можете видеть, что у меня есть до сих пор в приведенном ниже фрагменте, изображение все еще растягивается для подгонки. Любая помощь приветствуется!

 var renderer = new THREE.WebGLRenderer({ canvas : document.getElementById('canvas'), antialias:true});
    renderer.setClearColor(0x7b7b7b);
    //  use device aspect ratio //
    renderer.setPixelRatio(window.devicePixelRatio);
    // set size of canvas within window 
    renderer.setSize(window.innerWidth, window.innerHeight);

    // SCENE
    var scene = new THREE.Scene();

    // CAMERA
    var camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 0.1, 1000 );
    camera.position.z = 5;




    // MESH 0

    // texture
  var texture_0 = new THREE.  TextureLoader().load("https://i.imgur.com/YO0ygMx.jpg");
  texture_0.wrapS = THREE.ClampToEdgeWrapping;
  texture_0.wrapT = THREE.RepeatWrapping;
    // var tileWidth = 2;
    // var tileHeight = 1;
    // repeatX = tileWidth * 1024 / (tileHeight * 2048);
    // repeatY = 1;
    // texture_0.repeat.set(repeatX, repeatY);

    var geometry_0 = new THREE.PlaneGeometry(1.3,1,32);
    var material_0 = new THREE.MeshBasicMaterial({
      color: 0xd8d0d1,
      side: THREE.DoubleSide,
      map: texture_0
    });

    var mesh_0 = new THREE.Mesh(geometry_0, material_0);
    scene.add(mesh_0);

    mesh_0.position.x = -0.7



    // MESH 1

  var texture_1 = new THREE.TextureLoader().load("https://i.imgur.com/YO0ygMx.jpg");
  texture_1.wrapS = THREE.ClampToEdgeWrapping;
  texture_1.wrapT = THREE.RepeatWrapping;


    var geometry_1 = new THREE.PlaneGeometry(1,3,32);
    var material_1 = new THREE.MeshBasicMaterial({
      color: 0xd8d0d1,
      side: THREE.DoubleSide,
      map: texture_1
    });

    var mesh_1 = new THREE.Mesh(geometry_1, material_1);
    scene.add(mesh_1);

    mesh_1.position.x = 0.7


    // RENDER   ANIMATE
    function animate() {
        /* render scene and camera */
        renderer.render(scene,camera);
        requestAnimationFrame(animate);



    }

    requestAnimationFrame(animate);

    // RESIZE EVENTS
    window.addEventListener('resize', onResize);

    function onResize() {
        width = window.innerWidth;
        height = window.innerHeight;
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
    }  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js"></script>
<canvas id="canvas"></canvas>  

Ответ №1:

Существует множество возможных аспектов. Есть аспект самой текстуры, размер плоскости, размер отображаемой плоскости (например, если вы ее масштабировали) и т. Д..

В любом случае, как минимум, вам нужно знать аспект изображения и аспект плоскости. Если вы не будете жестко кодировать размер изображения в своем приложении, вы не будете знать аспект изображения до тех пор, пока оно не будет загружено. На этом этапе вы можете вычислить правильное смещение и повторить настройки, как подробно описано в этой статье

   // Set the repeat and offset properties of the background texture
  // to keep the image's aspect correct.
  const planeAspect = planeWidth / planeHeight;
  const imageAspect = texture.image.width / texture.image.height;
  const aspect = imageAspect / planeAspect;
 
  texture.offset.x = aspect > 1 ? (1 - 1 / aspect) / 2 : 0;
  texture.repeat.x = aspect > 1 ? 1 / aspect : 1;
 
  texture.offset.y = aspect > 1 ? 0 : (1 - aspect) / 2;
  texture.repeat.y = aspect > 1 ? 1 : aspect;
  

 var renderer = new THREE.WebGLRenderer({ canvas : document.getElementById('canvas'), antialias:true});
    renderer.setClearColor(0x7b7b7b);
    //  use device aspect ratio //
    renderer.setPixelRatio(window.devicePixelRatio);
    // set size of canvas within window 
    renderer.setSize(window.innerWidth, window.innerHeight);

    // SCENE
    var scene = new THREE.Scene();

    // CAMERA
    var camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 0.1, 1000 );
    camera.position.z = 5;




  // Set the repeat and offset properties of the background texture
  // to keep the image's aspect correct.
  function fixTexture(planeWidth, planeHeight) {
    return function(texture) {
      const planeAspect = planeWidth / planeHeight;
      const imageAspect = texture.image.width / texture.image.height;
      const aspect = imageAspect / planeAspect;

      texture.offset.x = aspect > 1 ? (1 - 1 / aspect) / 2 : 0;
      texture.repeat.x = aspect > 1 ? 1 / aspect : 1;

      texture.offset.y = aspect > 1 ? 0 : (1 - aspect) / 2;
      texture.repeat.y = aspect > 1 ? 1 : aspect;
    }
  }
    // MESH 0

    // texture
  var texture_0 = new THREE.  TextureLoader().load("https://i.imgur.com/YO0ygMx.jpg", fixTexture(1.3, 1));
  texture_0.wrapS = THREE.ClampToEdgeWrapping;
  texture_0.wrapT = THREE.RepeatWrapping;
    // var tileWidth = 2;
    // var tileHeight = 1;
    // repeatX = tileWidth * 1024 / (tileHeight * 2048);
    // repeatY = 1;
    // texture_0.repeat.set(repeatX, repeatY);

    var geometry_0 = new THREE.PlaneGeometry(1.3,1,32);
    var material_0 = new THREE.MeshBasicMaterial({
      color: 0xd8d0d1,
      side: THREE.DoubleSide,
      map: texture_0
    });

    var mesh_0 = new THREE.Mesh(geometry_0, material_0);
    scene.add(mesh_0);

    mesh_0.position.x = -0.7



    // MESH 1

  var texture_1 = new THREE.TextureLoader().load("https://i.imgur.com/YO0ygMx.jpg", fixTexture(1,3));
  texture_1.wrapS = THREE.ClampToEdgeWrapping;
  texture_1.wrapT = THREE.RepeatWrapping;


    var geometry_1 = new THREE.PlaneGeometry(1,3,32);
    var material_1 = new THREE.MeshBasicMaterial({
      color: 0xd8d0d1,
      side: THREE.DoubleSide,
      map: texture_1
    });

    var mesh_1 = new THREE.Mesh(geometry_1, material_1);
    scene.add(mesh_1);

    mesh_1.position.x = 0.7


    // RENDER   ANIMATE
    function animate() {
        /* render scene and camera */
        renderer.render(scene,camera);
        requestAnimationFrame(animate);



    }

    requestAnimationFrame(animate);

    // RESIZE EVENTS
    window.addEventListener('resize', onResize);

    function onResize() {
        width = window.innerWidth;
        height = window.innerHeight;
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
    }  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js"></script>
<canvas id="canvas"></canvas>  

Комментарии:

1. Спасибо! я думаю, что смогу работать с этим и сделать его динамичным в зависимости от размера изображения!