title: THREEjs - crop texture instead of stretching-to-fit
body: <p>I'm attempting to build an image-based art-making app using three.js.</p>
  
  <p>I'm using React.js, but hopefully the following is clear even for those without React experience. The component renders a , and it's passed a locally-hosted image URL from a parent component.</p>
  
  <p>The current code is set up to simply create a full-window canvas, create a 2D shape that spans the entire canvas, and set the provided image as a texture:</p>
  
  <pre><code>import React, { PureComponent } from 'react';
  import * as THREE from 'three';
  
  const textureLoader = new THREE.TextureLoader();
  
  const vertexShader = `
    varying vec2 vUv;
  
    void main() {
        vUv = uv;
        gl_Position = vec4(uv * 2. - vec2(1, 1), 0., 1.);
    }
  `;
  
  const fragmentShader = `
    precision highp float;
  
    varying vec2 vUv;
    uniform sampler2D texture1;
    void main() {
        gl_FragColor = texture2D(texture1, vUv.xy);
    }
  `;
  
  class Canvas extends PureComponent {
    state = {
      width: window.innerWidth,
      height: window.innerHeight
    }
  
    componentDidMount() {
      // TODO: resize handlers for width/height
      const {width, height} = this.state;
  
      this.canvas.width = width;
      this.canvas.height = height;
  
      const rendererParams = {
        canvas: this.canvas,
      };
      const cameraParams = [
        -width / 2,
        width / 2,
        -height / 2,
        height / 2,
      ];
  
      this.renderer = new THREE.WebGLRenderer(rendererParams);
      this.renderer.setClearColor(0xFFFFFF, 1.0)
      this.renderer.setSize(width, height);
  
      this.camera = new THREE.OrthographicCamera(...cameraParams);
      this.camera.position.set(0, 0, 200);
  
      this.scene = new THREE.Scene();
      this.scene.add(this.camera);
  
      // Our initial texture will be the specified default image.
      const imageSrc = this.props.defaultImageSrc;
  
      textureLoader.load(imageSrc, texture =&gt; {
        this.texture = texture;
  
        // TODO: Do I need this?
        this.material = new THREE.ShaderMaterial({
          vertexShader,
          fragmentShader,
          uniforms: {
            texture1: {
              type: "t",
              value: this.texture
            }
          }
        });
  
        this.mesh = new THREE.Mesh(new THREE.PlaneGeometry(1), this.material);
  
        this.scene.add(this.mesh);
  
        this.animate();
      })
    }
  
    animate = () =&gt; {
      requestAnimationFrame(this.animate);
  
      this.renderer.render(this.scene, this.camera);
    }
  
    render() {
      return (
        &lt;canvas innerRef={elem =&gt; this.canvas = elem} /&gt;
      );
    }
  }
  
  export default Canvas;
  </code></pre>
  
  <p>The issue I'm having is that the texture will be stretched to fit. This means that if the image is a square 1600x1600, but the browser window is 1000x500, the image will be squashed and distorted, since it's mapping the image to fit perfectly in the available space:</p>
  
  <p><a href="https://i.stack.imgur.com/clgI2.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/clgI2.jpg" alt="squashed woman"></a></p>
  
  <p>What I want is an equivalent of <code>background-size: cover</code>. I want it to shrink to the largest window dimension (1000x1000, in my example), and then crop from the center to only show the middle 500px worth of height.</p>