Javascript THREEjs-裁剪纹理,而不是拉伸以适应

Javascript THREEjs-裁剪纹理,而不是拉伸以适应,javascript,three.js,Javascript,Three.js,我正在尝试使用three.js构建一个基于图像的艺术制作应用程序 我使用的是React.js,但希望下面的内容对那些没有React经验的人来说也很清楚。组件呈现一个,并从父组件传递一个本地托管的图像URL 当前代码设置为只创建一个完整的窗口画布,创建一个横跨整个画布的2D形状,并将提供的图像设置为纹理: import React, { PureComponent } from 'react'; import * as THREE from 'three'; const textureLoade

我正在尝试使用three.js构建一个基于图像的艺术制作应用程序

我使用的是React.js,但希望下面的内容对那些没有React经验的人来说也很清楚。组件呈现一个,并从父组件传递一个本地托管的图像URL

当前代码设置为只创建一个完整的窗口画布,创建一个横跨整个画布的2D形状,并将提供的图像设置为纹理:

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 => {
      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 = () => {
    requestAnimationFrame(this.animate);

    this.renderer.render(this.scene, this.camera);
  }

  render() {
    return (
      <canvas innerRef={elem => this.canvas = elem} />
    );
  }
}

export default Canvas;
我遇到的问题是,纹理将被拉伸以适合。这意味着,如果图像为1600x1600正方形,但浏览器窗口为1000x500,则图像将被挤压和扭曲,因为它将图像映射为完全适合可用空间:


我想要的是一个相当于背景大小的:封面。在我的例子中,我希望它缩小到最大的窗口尺寸1000x1000,然后从中心裁剪,只显示中间500px的高度。

您需要显示您的相机,您使用的是透视相机、正交相机还是占位符相机。而且,如果你正在使用一个自定义着色器,你需要展示你是如何计算你的顶点位置的,他们是否使用projectionMatrix等等。。。。没有这些知识,没有人能回答这个问题

下面是如何使用一个正交摄影机来实现这一点,该摄影机刚刚设置为单位矩阵和2个单位的平面几何体

如果我们不做任何更改,这将显示一个填充画布的平面。之后,我们根据画布的侧面和图像的侧面对其进行缩放

  const canvas = renderer.domElement;
  const image = material.map.image;
  const canvasAspect = canvas.clientWidth / canvas.clientHeight;
  const imageAspect = image.width / image.height;

  // this assumes we want to fill vertically
  let horizontalDrawAspect = imageAspect / canvasAspect;
  let verticalDrawAspect = 1;
  // does it fill horizontally?
  if (horizontalDrawAspect < 1) {
    // no it does not so scale so we fill horizontally and
    // adjust vertical to match
    verticalDrawAspect /= horizontalDrawAspect;
    horizontalDrawAspect = 1;
  }
  mesh.scale.x = horizontalDrawAspect;
  mesh.scale.y = verticalDrawAspect;

您需要展示您的相机,您使用的是透视相机、正交相机还是占位符相机。而且,如果您使用的是自定义着色器,则需要显示如何计算顶点位置,以及它们是否使用projectionMatrix。没有这些知识,没有人能回答这个问题嘿@gman,谢谢你的帮助!我的缺点是假设摄影机和着色器没有必要更新我的代码片段-我确实在使用正交摄影机。我之所以使用自定义顶点着色器,仅仅是因为我无法在没有它的情况下渲染图像,但我将给MeshBasicMaterial另一个镜头。非常感谢你的投入,我真的很感激。