gpt4 book ai didi

three.js - 如何在应用纹理旋转时保留 threejs 纹理比例

转载 作者:行者123 更新时间:2023-12-04 01:33:57 27 4
gpt4 key购买 nike

我想让用户能够在矩形上旋转纹理,同时保持纹理图像的纵横比不变。我正在矩形表面上旋转 1:1 纵横比图像(比如 width: 2length: 1)

重现步骤:在下面的纹理旋转示例中

https://threejs.org/examples/?q=rotation#webgl_materials_texture_rotation

如果我们像下面这样改变几何体的一个面:

https://github.com/mrdoob/three.js/blob/master/examples/webgl_materials_texture_rotation.html#L57

var geometry = new THREE.BoxBufferGeometry( 20, 10, 10 );

然后您可以看到,当您使用旋转控件时,图像纵横比发生了扭曲。 (把正方形变成奇怪的形状)

在 0 度: At 0 Degree

在 0 到 90 之间的某个角度: enter image description here

我知道通过改变 repeatX 和 repeatY 因子我可以控制它。也很容易看出 0 度、90 度旋转时的值。

但我正在努力想出 repeatX 和 repeatY 的公式,该公式适用于给定矩形面的 lengthwidth 的任何纹理旋转。

最佳答案

不幸的是,当像那样拉伸(stretch)几何体时,您会在 3D 空间而非 UV 空间中得到扭曲。在此示例中,一个 UV.x 单元占用的 3D 空间是一个 UV.y 单元的两倍: enter image description here

这会在旋转之间为您提供那些水平倾斜的菱形: enter image description here

遗憾的是,没有办法通过纹理矩阵变换来解决这个问题。水平拉伸(stretch)将在 3D 空间中纹理变换后应用,因此 texture.repeat 无法帮助您避免这种情况。解决这个问题的唯一方法是修改 UV,使 UV.x 单位占用与 UV.y 单位一样多的 3D 空间: enter image description here

对于复杂的模型,您可以在 3D 编辑器中进行这种“均衡”,但由于几何结构足够简单,我们可以通过代码来完成。请参见下面的示例。我在我的 UV.y 重新映射中使用了一个宽度/高度比率变量,这样 UV 转换就会匹配,无论它有多宽。

//////// Boilerplate Three setup
const renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});
const camera = new THREE.PerspectiveCamera(50, 1, 1, 100);
camera.position.z = 3;
const scene = new THREE.Scene();

/////////////////// CREATE GEOM & MATERIAL
const width = 2;
const height = 1;
const ratio= width / height; // <- magic number that will help with UV remapping
const geometry = new THREE.BoxBufferGeometry(width, height, width);

let uvY;
const uvArray = geometry.getAttribute("uv").array;

// Re-map UVs to avoid distortion
for (let i2 = 0; i2 < uvArray.length; i2 += 2){
uvY = uvArray[i2 + 1]; // Extract Y value,
uvY -= 0.5; // center around 0
uvY /= ratio; // divide by w/h ratio
uvY += 0.5; // remove center around 0
uvArray[i2 + 1] = uvY;
}
geometry.getAttribute("uv").needsUpdate = true;

const uvMap = new THREE.TextureLoader().load("https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/uv_grid_opengl.jpg");

// Now we can apply texture transformations as expected
uvMap.center.set(0.5, 0.5);
uvMap.repeat.set(0.25, 0.5);
uvMap.anisotropy = 16;

const material = new THREE.MeshBasicMaterial({map: uvMap});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

window.addEventListener("mousemove", onMouseMove);
window.addEventListener("resize", resize);

// Add rotation on mousemove
function onMouseMove(ev) {
uvMap.rotation = (ev.clientX / window.innerWidth) * Math.PI * 2;
}

function resize() {
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}

function animate(time) {
mesh.rotation.y = Math.cos(time/ 3000) * 2;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}

resize();
requestAnimationFrame(animate);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://threejs.org/build/three.js"></script>
<canvas></canvas>

关于three.js - 如何在应用纹理旋转时保留 threejs 纹理比例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60269433/

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