【问题标题】:how to draw a flat shape in 3-space in three.js?如何在three.js中以3空间绘制平面形状?
【发布时间】:2018-02-28 01:40:09
【问题描述】:

我正在尝试在 three.js 中构建平面形状的集合。每个都被定义为一系列共面的 Vector3 点,但形状并不都是共面的。将两个扁平矩形想象成房屋的屋顶,但形状要复杂得多。

我可以制作扁平的 Shape 对象,然后旋转和定位它们,但是由于我的形状是在 3d 坐标中构思的,所以将它全部保存在 3 空间中会简单得多,而 Shape 对象不喜欢这样。

有没有更直接的方法来简单地指定一个共面 Vector3 的数组,然后让 three.js 完成剩下的工作?

【问题讨论】:

  • stackoverflow.com/questions/37860895/…。您的情况是否可以接受,由您决定。
  • 这与我正在寻找的非常接近。不幸的是,它只适用于凸形。如果有意义的话,一个块状的“L”形被画成一个不稳定的五边形。我真的在寻找一种解决方案,它可以做与此非常相似的事情,但可以使用任何形状,按顺序跟随点而不是对组进行蒙皮。感谢您的帮助!

标签: three.js


【解决方案1】:

我考虑过这个问题并提出了这个想法,当你有一组共面点并且你知道你的点所属的平面的法线(我们将其命名为normal)时。

  1. 我们需要旋转我们的点集以使其平行于 xy 平面,因此该平面的法线为[0, 0, 1](我们将其命名为normalZ)。为此,我们找到 .setFromUnitVectors() of THREE.Quaternion() 的四元数:

    var quaternion = new THREE.Quaternion().setFromUnitVectors(normal, normalZ); var quaternionBack = new THREE.Quaternion().setFromUnitVectors(normalZ, normal);

  2. quaternion 应用于我们的点集

  3. 由于它现在平行于 xy 平面,点的 z 坐标无关紧要,所以我们现在可以创建它们的 THREE.Shape() 对象。然后从给定的形状创建THREE.ShapeGeometry()(命名为shapeGeom),这将对我们的形状进行三角测量。

  4. 我们需要将我们的积分放回原来的位置,所以我们将quaternionBack应用于他们。

  5. 毕竟,我们会将我们的点集分配给shapeGeom.vertices 属性。

就是这样。如果它对你有用,请告诉我;)

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 20, 40);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(10, 0, 10);
controls.update();

var grid = new THREE.GridHelper(50, 50, 0x808080, 0x202020); // xy-grid
grid.geometry.rotateX(Math.PI * 0.5);
scene.add(grid);

var points = [ // all of them are on the xz-plane
    new THREE.Vector3(5, 0, 5),
  new THREE.Vector3(25, 0, 5),
  new THREE.Vector3(25, 0, 15),
  new THREE.Vector3(15, 0, 15),
  new THREE.Vector3(15, 0, 25),
  new THREE.Vector3(5, 0, 25),
  new THREE.Vector3(5, 0, 5)
]

var geom = new THREE.BufferGeometry().setFromPoints(points);
var pointsObj = new THREE.Points(geom, new THREE.PointsMaterial({
  color: "red"
}));
scene.add(pointsObj);

var line = new THREE.LineLoop(geom, new THREE.LineBasicMaterial({
  color: "aqua"
}));
scene.add(line);

// normals 
var normal = new THREE.Vector3(0, 1, 0); // I already know the normal of xz-plane ;)
scene.add(new THREE.ArrowHelper(normal, new THREE.Vector3(10, 0, 10), 5, 0xffff00)); //yellow

var normalZ = new THREE.Vector3(0, 0, 1); // base normal of xy-plane
scene.add(new THREE.ArrowHelper(normalZ, scene.position, 5, 0x00ffff)); // aqua

// 1 quaternions
var quaternion = new THREE.Quaternion().setFromUnitVectors(normal, normalZ);
var quaternionBack = new THREE.Quaternion().setFromUnitVectors(normalZ, normal);

// 2 make it parallel to xy-plane
points.forEach(p => {
  p.applyQuaternion(quaternion)
});

// 3 create shape and shapeGeometry
var shape = new THREE.Shape(points);
var shapeGeom = new THREE.ShapeGeometry(shape);

// 4 put our points back to their origins
points.forEach(p => {
  p.applyQuaternion(quaternionBack)
});

// 5 assign points to .vertices
shapeGeom.vertices = points;

var shapeMesh = new THREE.Mesh(shapeGeom, new THREE.MeshBasicMaterial({
  color: 0x404040
}));
scene.add(shapeMesh);

render();

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.90.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.90.0/examples/js/controls/OrbitControls.js"></script>

【讨论】:

  • 非常感谢您清晰的解释和示例。不过,我仍然有点挣扎。我肯定需要更多地了解四元数。我有两个困难。尽管我检查了点的顺序,但我的多边形仍然显示为凸面。不知道我在那里做错了什么。而且这种方法似乎将平面旋转了一个轴,而不检查原始坐标的方向。我还在考虑。但我觉得我越来越近了,谢谢你的帮助!
  • 我做错了什么的潜在线索:多边形从顶部看起来是凸的,但是如果您旋转模型并查看底部,您所看到的只是应该减去的重叠位置从顶部。 Three.js 很吸引人,我还在摸索。
  • @gunther47 你能提供一组要点吗?所以我可以用真实的东西来测试我的算法:)
  • 我用您的代码构建了一个小提琴,并替换了我自己的观点。无法理解有什么区别。你的观点有效,我的观点无效。甚至在方格纸上画出我的,以确保它们的顺序正确。 jsfiddle.net/ftf5tk7m/2
  • 有趣。您必须通过克隆点集末尾的第一个点来关闭多边形(我已经更新了答案)。更重要的是,点必须按顺时针顺序排列。至少,在这个example 中这样做。或者也许我自己误解了一些东西:)
猜你喜欢
  • 1970-01-01
  • 2018-12-10
  • 2018-07-28
  • 2018-10-24
  • 2017-05-07
  • 2016-05-04
  • 2021-11-01
  • 1970-01-01
  • 2012-07-09
相关资源
最近更新 更多