Three.js实现可透视的水面效果

Posted 当时明月在曾照彩云归

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Three.js实现可透视的水面效果相关的知识,希望对你有一定的参考价值。

本文描述使用Three.js实现可透视的水面效果

1. 引言

Three.js是著名的JavaScript 3D图形库,用于浏览器中开发 3D 交互场景的 JS 引擎,可以快速的搭建三维场景

Three.js官网为:创建一个场景 – three.js docs (threejs.org)

GitHub站点为:mrdoob/three.js: JavaScript 3D Library. (github.com)

本文描述使用Three.js实现可透视的水面效果

2. 可透视水面效果

这里主要是指以下这两个官方示例:

如果网络原因加载不出来可以使用下面的示例:

第一个是海洋Ocean,有倒影、水纹波动但是水面不透明,不能从水下往上看:

第二个是水面Water,有倒影、水纹波动,水面不透明,可以从水下往上看,但是从水下往上看没有水面效果:

此处,笔者修改一下Three.js源码中的Water.jsthree.js/Water.js at dev · mrdoob/three.js · GitHub

添加了 opacitytransparent参数并设置side参数,实现以下效果:

3. 参考资料

[1] three.js/Water.js at dev · mrdoob/three.js · GitHub

[2] three.js/Water2.js at dev · mrdoob/three.js · GitHub

如何使用 HTML5 canvas & three.js 实现 4 点透视变换?

【中文标题】如何使用 HTML5 canvas & three.js 实现 4 点透视变换?【英文标题】:How to implement 4-point perspective transform using HTML5 canvas & three.js? 【发布时间】:2019-05-28 14:35:26 【问题描述】:

首先,我要实现的视觉示例:

(图片来源:https://unsplash.com/photos/pGcqw1ARGyg)

简短的(tl;dr)问题

使用 HTML5 视频和画布,如何执行 4 点透视变换,以便在画布中仅渲染帧的“电视屏幕”部分?为什么my implementation 没有显示正确的区域?

关于我正在努力实现的目标的背景

我正在尝试构建一个如下所示的网页:

    用户将网络摄像头对准电视,使其位于画面中的某个位置(但可能以任何角度) 使用 HTML5 视频和画布,捕获网络摄像头并在网页上预览 用户可以定义(通过单击预览)电视屏幕的 4 个角的位置(4 对 x/y 坐标) ** 视频被扭曲(使用某种透视变换),因此画布显示其实际电视屏幕的图像部分(而不是整个网络摄像头视图)** 然后对图像执行一些处理(例如,识别最突出的颜色)。这部分超出了这个问题的范围,除了指出我希望能够在最后访问 HTML5 画布的内容/像素。

我正在努力解决的部分是第 4 步。为了确保我只为视频的每一帧处理图像的相关部分,重要的是我“扭曲”图像以便它只显示“电视屏幕”区域,而不是整个网络摄像头图片。

看了一些资料,我的理解是:

这需要某种透视变换,而且由于网络摄像头可以处于任何角度,而且我们不处理平行线,因此需要 3 维变换而 2D 是不够的。这是因为 2D 变换(平移/旋转/缩放/倾斜)无法处理收敛的边。 HTML5 画布是二维上下文,因此只能支持 2D 变换,不能支持 3D 变换。因为我需要一个适用于canvas 的解决方案,所以我不能简单地使用3D CSS 变换(例如https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d)。这表明 WebGL 可能更适合我处理 3D 方面的需求。

到目前为止我所做的尝试

考虑到这一点,我尝试了以下方法:

a) 使用video 标签捕获网络摄像头

b) 使用three.js,创建一个渲染为canvas 元素的3D 场景(这样我就可以对生成的画布内容进行图像处理)

c) three.js 场景包括: - 包含使用VideoTexture 在一侧显示视频的平面网格。 - 一个透视相机,最初的位置是为了显示整个网络摄像头图像

d) 允许用户单击四个角点来定义电视的位置,计算 x/y 坐标并保存它们

e) 计算一个透视变换,该变换将“拉伸”图像以使正确的区域“填充框架”。换句话说,将四个单击的“电视角”点拉伸到视口的四个角。我一直在使用这个库:https://github.com/jlouthan/perspective-transform 来计算这个。

f) 我的想法是,如果对包含视频的网格应用适当的变换,并且相机保持在固定位置,那么输出画布将包含在 2D 中查看所需的图像。

链接到我当前的(损坏的)实现

这是我目前在上述尝试的链接。它显示视频并允许您单击四个角。如果您单击原点周围的点(在中心)似乎可以工作,但问题是如果您选择图像中的其他区域,它会显示错误的区域。

https://bitbucket.org/mattwilson1024/perspective-transform/src/master/

总结

我非常感谢任何帮助找出为什么它没有按我预期的那样工作,或者任何关于是否有更好/更简单的方法来实现我需要的指示。

【问题讨论】:

【参考方案1】:

原始实现的问题在于 transformMatrix 的创建方式。

我可以通过更改它来使其工作:

transformMatrix.set(a1, a2, a3, 0, 
                    b1, b2, b3, 0, 
                    c1, c2, c3, 0, 
                    0,  0,  0,  1);

到这里:

transformMatrix.set(a1, a2, 0, a3, 
                    b1, b2, 0, b3, 
                    0,  0,  0, 1, 
                    c1, c2, 0, c3);

This answer on the Math StackExchange 有助于解决这个问题。

为了以后发现此问题的任何人的利益,我已更新原始问题,使其指向包含损坏代码的存档分支。工作版本可以在here找到。

【讨论】:

以上是关于Three.js实现可透视的水面效果的主要内容,如果未能解决你的问题,请参考以下文章

HTML5+Three.js实现可拖拽的虚拟天空环境全景动画

如何在 Three.js 中获取透视相机的角度值?

THREE.JS : 带有光线投射器和透视相机的点击事件

WEBGL实现--three.js笔记整理

three.js之正投影摄像机与透视投影摄像机的区别

10-THREE.JS perspective透视摄像机和orthographic正交摄像机区别