Three.js - 如果对象相交则剪裁平面?

发布于 2025-01-11 20:45:55 字数 260 浏览 2 评论 0原文

我使用 PlaneGeometry 作为水,并在其上添加了一艘船(gltf 模型)。问题是,当船稍微停在水中时,即使船是漂浮的,水也会显示在船内。当船(或其他模型/物体)与运动相交时,有没有办法夹住水?

输入图片此处描述

I'm using a PlaneGeometry as water, and have added a ship (gltf model) on it. Problem is, when the boat slightly rests into the water, the water is shown inside the boat, even though the boat is afloat. Is there a way to clip the water when a boat (or other models/objects) intersect with it with motion?

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

捎一片雪花 2025-01-18 20:45:55

Three.js 中的每种材质都有一个 AlphaMap 属性 可用于更改网格的不透明度。因此,您可以绘制一个黑色矩形,船将在其中“切出”不透明度为 0 的水线部分。

我认为您的船将要移动,因此您的纹理也需要移动这个黑色矩形。要解决此问题,您可以使用 HTML 元素来绘制和移动黑色矩形。然后您可以使用 THREE.CanvasTexture 转换为飞机 Alpha 的纹理。

const drawingCanvas = document.getElementById( 'drawing-canvas' );
const canvasTexture = new THREE.CanvasTexture( drawingCanvas );

const waterMaterial = new THREE.MeshBasicMaterial({
    transparent: true,
    alphaMap: squareTexture
});

请参阅此工作演示,了解如何在 3D 场景中使用 2D 画布作为纹理。当您在左上角的正方形上绘制时,您会看到它被应用到立方体上。您可以复制此方法,但不要将其分配给 material.map,而是在 material.alphaMap 上使用它。

Every material in Three.js has an AlphaMap property that you can use to change the opacity of the mesh. So you could draw a black rectangle where the boat is to "cut out" that part of the water plane with an opacity of 0.

I presume your boat is going to be moving, so your texture would also need to move this black rectangle. To solve this, you could use an HTML <canvas> element to draw and move the black rectangle. Then you could use THREE.CanvasTexture to turn the <canvas> into a texture for your plane's alpha.

const drawingCanvas = document.getElementById( 'drawing-canvas' );
const canvasTexture = new THREE.CanvasTexture( drawingCanvas );

const waterMaterial = new THREE.MeshBasicMaterial({
    transparent: true,
    alphaMap: squareTexture
});

See this working demo for how to use a 2D canvas as a texture in your 3D scene. When you draw on the top-left square, you'll see it being applied to the cube. You could copy this approach, but instead of assigning it to material.map, you'd use it on material.alphaMap.

九局 2025-01-18 20:45:55

您可以检查每帧船体顶点的位置,并且如果 PlaneGeometry 上有足够的点,您可以将船体内部表面的所有顶点移动到最近船体顶点的 y 坐标。这也可以通过自定义着色器来完成,这可能是一个更有效的解决方案。
@Marquizzo 关于 alpha 通道的想法可能也是一个更好的解决方案,因为您并不像我假设的那样真正想要模拟水的位移,而只是摆脱船内水的显示。在这种情况下,我将在船上方放置一个正交相机,将近剪裁平面和远剪裁平面设置为尽可能靠近平面,并使用 Alpha 通道或 Alpha 通道内的 CanvasTexture 作为渲染目标。这样,您将获得实时 alpha 贴图,该贴图也会对船舶的横滚、纵摇和升沉做出反应。

You could check for the position of the hull vertices of the ship each frame and, given enough points on the PlaneGeometry, you could displace all vertices of the surface inside the ship hull to the y coordinate of the nearest hull vertex. This could probably also be done by a custom shader, which is probably a more efficient solution.
@Marquizzo's idea with the alpha channel is probably a better solution, too, since you don't really want to simulate the displacement of the water, as I assume, but simply get rid of the display of water inside the ship. In this case, I would place an orthographic camera above the ship, set the near and far clipping planes as close as possible to the plane, and use the alpha channel or rather CanvasTexture inside the alpha channel as rendertarget. This way, you'll get a real time alpha map that also reacts to rolling, pitching and heave of the ship.

宣告ˉ结束 2025-01-18 20:45:55

浮动效果是通过应用于 y 坐标的 sin 函数实现的。你可以用同样的原理让gltf模型(船)在任意坐标轴上移动。

例子:

position.y = Math.sin(ship.userData.initFloating + t) * 0.15;

Effect of floating is made with sin function, applied to y-coordinate. You can use the same principle to make gltf model(ship) move on any coordinate axis.

Example:

position.y = Math.sin(ship.userData.initFloating + t) * 0.15;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文