如何减少和增加对象上图像的大小 - ThreeJS

时间:2017-01-05 16:54:47

标签: three.js

我正在使用THREE.ImageUtils.loadTexture函数加载图片,然后将其粘贴到我的场景中的每个对象上,如下所示:

_.forEach(bags, (bag) => {
  if(bag['children'][0] && bag['children'][0].material) {
    let material = new THREE.MeshPhongMaterial({map: tex});
    bag['children'][0].material = material;
  }
});

我已查看tex.scale.xtex.scale.y& tex.offset.xtex.offset.y但这些似乎并不是我需要的。这是目前物体的样子

enter image description here

但我在每一方都有更严格的定位。像这样的东西(伪代码)会将左上角放在那个位置的所需边上。

sideA.image.setSize(x,y);

有没有人有这方面的例子?

编辑

感谢目前为止的反馈。 @Martin我已经设置了一个基本的PlaneGeometry形状来测试它。所以这个形状的脸是基本的两个三角形相互连接;我附上了您发布的紫外线设置的图片:

enter image description here

所以从你所说的我不能延伸其中一个三角形会破坏使用的几何体,所以我需要操纵两个三角形来正确地移动图像。正确的吗?

1 个答案:

答案 0 :(得分:5)

不幸的是,在three.js中没有简单的方法可以做到这一点。

为了正确控制非平凡网格的纹理,您可能需要先对模型进行UV-unwrapping。这应该通常由提供网格的人来完成,因为在blender,3dstudio,cinema4d等工具中更容易做到这一点。

但是,我认为由于某些原因你没有提供该人,并且需要在javascript中执行此操作。这种方式更有趣。让我们进一步假设,我们只想将图像映射到包的正面和背面,内部和边缘不会被纹理化。

在three.js和大多数其他3D应用程序中,纹理的精确映射通过为每个面提供每个顶点的纹理坐标(也称为UV坐标)来实现。这些UV坐标(范围从0到1)指定纹理中属于顶点的位置。点(0, 0)是图像的左下角,(1, 1)是右上角,与图像的宽高比无关。

因此,对于一个由两个三角形组成的简单四边形,这将是这样的:

const geometry = new THREE.Geometry();
const vertices = [
   // the four vertices ABCD
   [0,0,0], [0,1,0], [1,0,0], [1,1,0]
].map(v => new THREE.Vector3(...v));

// setup two triangles ADB and ACD:
//
// B---D
// | / |
// A---C

const normal = new THREE.Vector3(0,0,1);
const faces = [
  new THREE.Face3(0, 3, 1, normal),
  new THREE.Face3(0, 2, 3, normal)
];

geometry.vertices = vertices;
geometry.faces = faces;

所以,这只是几何本身,但了解它是如何为下一步构建的非常重要 - 紫外线坐标:

const uvs = geometry.faceVertexUvs[0];
const vertexUvs = [
  [0,0], [0,1], [1,0], [1,1]
].map(p => new THREE.Vector2(...p));

// we need to set the UV-coordinates for both faces separately, using 
// the same scheme as before:
uvs[0] = [vertexUvs[0], vertexUvs[3], vertexUvs[1]];
uvs[1] = [vertexUvs[0], vertexUvs[2], vertexUvs[3]];

基本上就是这样。这大致是THREE.PlaneGeometry所做的。关于这一点的更多要点:

  • three.js能够处理两组不同的uv坐标,这就是geometry.faceVertexUvs[0]的原因。
  • 该数组中的索引对应于faces-array中的索引,因此uvs[0]是第一个面,uvs[1]是第二个面。
  • 每个都是长度为3的数组,对应于该面的顶点。

现在,对于你的行李箱,应该可以找出哪两个面是正面和背面的部分。您需要找到它们并编辑它们的UV坐标以匹配您想要看到的图像中的位置(我不知道这些模型的外观,所以我在这里可以帮助您更多) 。所有其他UV坐标都可以设置为某个安全值,如(0, 0),那么不是前面或后面的所有内容都将具有纹理左下角像素的颜色。

如果你想要对它们进行纹理处理,你应该考虑在适当的3D编辑软件中进行纹理贴图。

编辑(2017-01-15)

使用角度徽标查看图像,左上角三角形被翻转。这是因为three.js使用的是与我的示例中不同的面或顶点顺序。

如果您只是在浏览器控制台或调试器中使用它,那么理解这些内容会有很大帮助(这就是我刚才所做的)。据此,来自three.js的平面几何具有以下结构:

// A---B
// | / |
// C---D

vertices = [A, B, C, D]
faces = [Face3(A, C, B), Face3(C, B, D)]

值得注意的是,无论出于何种原因,第一张脸是逆时针方向,第二张脸是顺时针方向(我认为这是一种不好的做法,三角形应该始终是逆时针方向)。看一下几何的faceVertexUV,看看它在这种情况下的样子(只需在浏览器控制台中输入new THREE.PlaneGeometry(1,1).faceVertexUvs[0]

现在换另一点,缩放纹理。您可以尝试的一件事是为顶点使用大于1的UV值。这将导致纹理绘制得更小。但是,只有

才能正常工作
  • 纹理包裹模式是钳位到边缘(texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
  • 所有纹理都有1px宽边框,中性色

否则(这是我推荐的方式)你应该使用画布作为纹理并在实际使用之前准备图像。我在这里做了一个简单的例子:http://codepen.io/usefulthink/pen/GrjmrM?editors=0010