gpt4 book ai didi

javascript - THREEjs - 裁剪纹理而不是拉伸(stretch)以适应

转载 作者:行者123 更新时间:2023-12-03 04:01:02 50 4
gpt4 key购买 nike

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

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

当前代码设置为简单地创建一个全窗口 Canvas ,创建一个跨越整个 Canvas 的 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;

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

squashed woman

我想要的是background-size: cover的等价物。我希望它缩小到最大的窗口尺寸(在我的示例中为 1000x1000),然后从中心裁剪以仅显示中间 500px 的高度。

最佳答案

您需要展示您的相机,您使用的是PerspectiveCameraOrthographicCamera还是占位符Camera。而且,如果您使用自定义着色器,您需要展示如何计算顶点位置(您是否使用 projectionMatrix 等...)。如果没有这些知识,没有人能够回答这个问题。

以下是如何使用刚刚设置为单位矩阵的 OrthographicCamera 和 2 个单位 PlaneGeometry 来实现此操作。

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

  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;

const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, -1, 1);

const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);

const geometry = new THREE.PlaneGeometry(2, 2);
const material = new THREE.MeshBasicMaterial({});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

camera.position.z = 1;

function render() {
resize();

if (!material.map.image) {
return;
}

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;


renderer.render(scene, camera);
}

function resize() {
const canvas = renderer.domElement
const width = canvas.clientWidth;
const height = canvas.clientHeight;
if (canvas.width !== width || canvas.height !== height) {
renderer.setSize(width, height, false);
}
}

window.addEventListener('resize', render);

const loader = new THREE.TextureLoader();
loader.crossOrigin = "";

// load a resource
loader.load('http://i.imgur.com/TSiyiJv.jpg', function (texture) {
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;
texture.minFilter = THREE.LinearFilter;
material.map = texture;
render();
});
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>

关于javascript - THREEjs - 裁剪纹理而不是拉伸(stretch)以适应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44720511/

50 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com