Three.js 无论网格大小如何,制作固定纹理

Three.js making fixed texture irrespective of mesh size

我正在制作一个简单的动画,我必须将平面的高度从 100% 设置为 0。平面上有纹理。我检查了多个示例,但找不到一种方法来制作固定尺寸的纹理,而不管网格的尺寸如何。

我创建了一个基本的动画示例here

不能使用这个,因为我可能有不同的背景纹理(不是黑色)。

在搜索了几个小时后,我找到了这个 (when I was about to post a question myself). Found the interesting setUv() function. I modified this function to make another example。 基本上我在每次迭代中处理几何体并将新纹理分配给新几何体(比以前的小)。

var group, mesh, geometry, meterial;
var planeHeight, planeWidth;
var UVwr, UVhr;
planeHeight = planeWidth = 3;
UVwr = UVhr = 1.5;
function drawElements(){
  group = new THREE.Group();
  geometry = new THREE.PlaneGeometry( planeWidth, planeHeight );
  var texture = new THREE.Texture( generateTexture() );
  texture.needsUpdate = true;
  texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
  texture.repeat.set(1,1);
  material = new THREE.MeshBasicMaterial( { map: texture, transparent: true } );
  plane = new THREE.Mesh( geometry, material );
  var v = plane.geometry.faceVertexUvs[0];
  setUv( v, 0, UVwr, UVhr );
  group.add( plane );
    scene.add( group );
}

/* Plane Geometry */
function setUv( v, index, wr, hr ) {
    for (var i=index*2; i<(index+1)*2; i++) {
        for (var j=0; j<3; j++) {
            v[i][j].x = v[i][j].x * wr;
            v[i][j].y = v[i][j].y * hr;         
        }
    }
}
function animate(){
  planeHeight -= 0.01;
  UVhr -= 0.005;
  planeHeight = planeHeight < 0.01 ? 3 : planeHeight;
  UVhr = UVhr < 0.005 ? 1.5 : UVhr;
  group.children[0].geometry.dispose();
  group.children[0].geometry = new THREE.PlaneGeometry( planeWidth, planeHeight );
  
  var v = plane.geometry.faceVertexUvs[0];
  setUv( v, 0, UVwr, UVhr );
}

我想知道是否有其他更好的方法来制作这个动画。

也许我们可以使用 2 个纹理(1. 图像纹理和 2. 透明纹理),然后应用具有偏移量的第二个纹理(透明纹理)并将该纹理从底部向上移动。这样我们就不必每次都处理几何体。 (只是想知道这是否可能)

谢谢!

你知道你的几何参数,因此你可以用它来计算 uv 坐标:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var planeGeom = new THREE.PlaneBufferGeometry(10, 10);
console.log(planeGeom);
var planeMat = new THREE.MeshBasicMaterial({
  map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/UV_Grid_Sm.jpg")
});
var plane = new THREE.Mesh(planeGeom, planeMat);
scene.add(plane);

var clock = new THREE.Clock();
var y = 0,
  yUv = 0,
  h = planeGeom.parameters.height;

renderer.setAnimationLoop(() => {

  y = Math.sin(clock.getElapsedTime()) * 2.5 + 2.5;
  
  plane.position.y = y;

  planeGeom.attributes.position.setY(0, h * 0.5 - y * 2);
  planeGeom.attributes.position.setY(1, h * 0.5 - y * 2);
  planeGeom.attributes.position.needsUpdate = true;

  yUv = (Math.sin(clock.getElapsedTime()) * h * 0.5 + h * 0.5) / h;

  planeGeom.attributes.uv.setY(0, 1 - yUv);
  planeGeom.attributes.uv.setY(1, 1 - yUv);
  planeGeom.attributes.uv.needsUpdate = true;

  renderer.render(scene, camera);
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>