我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么使用threejs实现实时多边形折射

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么使用threejs实现实时多边形折射

这篇文章将为大家详细讲解有关怎么使用threejs实现实时多边形折射,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

JavaScript的特点

1.JavaScript主要用来向HTML页面添加交互行为。2.JavaScript可以直接嵌入到HTML页面,但写成单独的js文件有利于结构和行为的分离。3.JavaScript具有跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行。

前言

渲染3D对象时,无论使用某种3D软件还是使用WebGL进行实时显示,始终都必须为其分配材料以使其可见并具有所需的外观。

可以使用Three.js之类的库中的现成程序来模仿许多类型的材料,但是在本教程中,我将向您展示如何使用三个对象(三个步骤)使对象看起来像玻璃一样。

步骤1:设定和正面折射

在本演示中,我将使用菱形几何图形,但是您可以跟随一个简单的盒子或任何其他几何图形。

让我们建立我们的项目。我们需要一个渲染器,一个场景,一个透视相机和我们的几何图形。为了渲染我们的几何图形,我们需要为其分配材质。创建此材料将是本教程的主要重点。因此,继续创建具有基本顶点和片段着色器的新ShaderMaterial。

与您期望的相反,我们的材料将不是透明的,实际上,我们将对钻石后面的任何东西进行采样和变形。为此,我们需要将场景(没有菱形)渲染为纹理。我只是使用正交摄影机渲染全屏平面,但这也可能是充满其他对象的场景。在Three.js中从菱形分割背景几何图形的最简单方法是使用“图层”。

this.orthoCamera = new THREE.OrthographicCamera( width / - 2,width / 2, height / 2, height / - 2, 1, 1000 );// assign the camera to layer 1 (layer 0 is default)this.orthoCamera.layers.set(1);const tex = await loadTexture('texture.jpg');this.quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(), new THREE.MeshBasicMaterial({map: tex}));this.quad.scale.set(width, height, 1);// also move the plane to layer 1this.quad.layers.set(1);this.scene.add(this.quad);

我们的渲染循环如下所示:

this.envFBO = new THREE.WebGLRenderTarget(width, height);this.renderer.autoClear = false;render() {    requestAnimationFrame( this.render );    this.renderer.clear();    // render background to fbo    this.renderer.setRenderTarget(this.envFbo);    this.renderer.render( this.scene, this.orthoCamera );    // render background to screen    this.renderer.setRenderTarget(null);    this.renderer.render( this.scene, this.orthoCamera );    this.renderer.clearDepth();    // render geometry to screen    this.renderer.render( this.scene, this.camera );};

好吧,现在该花一点点理论了。透明材料(如玻璃)可以弯曲,因此可见。那是因为光在玻璃中的传播要比空气中的传播慢,因此当光波以一定角度撞击玻璃物体时,这种速度变化会导致光波改变方向。波浪方向的这种变化描述了折射现象。

怎么使用threejs实现实时多边形折射

为了在代码中复制这一点,我们将需要知道我们的眼睛向量与世界空间中钻石表面(法线)向量之间的角度。让我们更新顶点着色器以计算这些向量。

varying vec3 eyeVector;varying vec3 worldNormal;void main() {    vec4 worldPosition = modelMatrix * vec4( position, 1.0);    eyeVector = normalize(worldPos.xyz - cameraPosition);    worldNormal = normalize( modelViewMatrix * vec4(normal, 0.0)).xyz;    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}

在片段着色器中,我们现在可以将eyeVector和worldNormal用作glsl内置折射函数的前两个参数。第三个参数是折射率的比率,即我们的快速介质(空气)的折射率(IOR)除以我们的慢速介质(玻璃)的IOR。在这种情况下,该值为1.0 / 1.5,但是您可以调整该值以获得所需的结果。例如,水的IOR为1.33,钻石的IOR为2.42。

uniform sampler2D envMap;uniform vec2 resolution;varying vec3 worldNormal;varying vec3 viewDirection;void main() {    // get screen coordinates    vec2 uv = gl_FragCoord.xy / resolution;    vec3 normal = worldNormal;    // calculate refraction and add to the screen coordinates    vec3 refracted = refract(eyeVector, normal, 1.0/ior);    uv += refracted.xy;        // sample the background texture    vec4 tex = texture2D(envMap, uv);    vec4 output = tex;    gl_FragColor = vec4(output.rgb, 1.0);}

怎么使用threejs实现实时多边形折射

真好!我们成功编写了折射着色器。但是我们的钻石几乎看不见……部分原因是我们只处理了玻璃的一种视觉特性。并非所有的光都会穿过要折射的材料,实际上,一部分光会被反射。让我们看看如何实现它!

步骤2:反射和菲涅耳方程

为了简单起见,在本教程中,我们将不计算适当的反射,而仅将白色用作反射光。现在,我们怎么知道什么时候该反思,什么时候该折射?理论上,这取决于材料的折射率,当入射矢量和表面法线之间的角度大于临界角时,光波将被反射。

怎么使用threejs实现实时多边形折射

在片段着色器中,我们将使用菲涅耳方程来计算反射光线与折射光线之间的比率。不幸的是,glsl也没有内置此方程式,但是您可以从这里复制它:

float Fresnel(vec3 eyeVector, vec3 worldNormal) {    return pow( 1.0 + dot( eyeVector, worldNormal), 3.0 );}

现在,我们可以根据刚计算出的菲涅耳比,简单地将折射纹理颜色与白色反射颜色混合。

uniform sampler2D envMap;uniform vec2 resolution;varying vec3 worldNormal;varying vec3 viewDirection;float Fresnel(vec3 eyeVector, vec3 worldNormal) {    return pow( 1.0 + dot( eyeVector, worldNormal), 3.0 );}void main() {    // get screen coordinates    vec2 uv = gl_FragCoord.xy / resolution;    vec3 normal = worldNormal;    // calculate refraction and add to the screen coordinates    vec3 refracted = refract(eyeVector, normal, 1.0/ior);    uv += refracted.xy;    // sample the background texture    vec4 tex = texture2D(envMap, uv);    vec4 output = tex;    // calculate the Fresnel ratio    float f = Fresnel(eyeVector, normal);    // mix the refraction color and reflection color    output.rgb = mix(output.rgb, vec3(1.0), f);    gl_FragColor = vec4(output.rgb, 1.0);}

怎么使用threejs实现实时多边形折射

看起来已经好多了,但是还有一些不足之处……嗯,我们看不到透明对象的另一面。让我们解决这个问题!

步骤3:多边折射

到目前为止,我们已经了解了有关反射和折射的知识,我们可以理解,光在离开对象之前可以在对象内部来回反弹几次。

为了获得物理上正确的结果,我们将必须跟踪每条光线,但是不幸的是,这种计算量太大,无法实时渲染。因此,我将向您展示一个简单的近似值,至少可以直观地看到我们钻石的背面。

在一个片段着色器中,我们需要几何图形的正面和背面的世界法线。由于我们不能同时渲染两侧,因此需要首先将背面法线渲染为纹理。

怎么使用threejs实现实时多边形折射

让我们像在步骤1中一样制作一个新的ShaderMaterial,但是这次我们将世界法线渲染为gl_FragColor。

varying vec3 worldNormal;void main() {    gl_FragColor = vec4(worldNormal, 1.0);}

接下来,我们将更新渲染循环以包括背面通道。

this.backfaceFbo = new THREE.WebGLRenderTarget(width, height);...render() {    requestAnimationFrame( this.render );    this.renderer.clear();    // render background to fbo    this.renderer.setRenderTarget(this.envFbo);    this.renderer.render( this.scene, this.orthoCamera );    // render diamond back faces to fbo    this.mesh.material = this.backfaceMaterial;    this.renderer.setRenderTarget(this.backfaceFbo);    this.renderer.clearDepth();    this.renderer.render( this.scene, this.camera );    // render background to screen    this.renderer.setRenderTarget(null);    this.renderer.render( this.scene, this.orthoCamera );    this.renderer.clearDepth();    // render diamond with refraction material to screen    this.mesh.material = this.refractionMaterial;    this.renderer.render( this.scene, this.camera );};

现在,我们在折射材料中采样背面法线纹理。

vec3 backfaceNormal = texture2D(backfaceMap, uv).rgb;

最后,我们结合了正面和背面法线。

float a = 0.33;vec3 normal = worldNormal * (1.0 - a) - backfaceNormal * a;

在此等式中,a只是一个标量值,指示应应用背面法线的数量。

怎么使用threejs实现实时多边形折射

我们做到了!我们可以看到钻石的所有侧面,仅是因为我们对钻石的材质进行了折射和反射。

局限性

正如我已经解释的那样,用这种方法实时渲染物理上正确的透明材料是不可能的。当在彼此前面渲染多个玻璃对象时会发生另一个问题。由于我们仅对环境采样一次,因此无法看透一连串的对象。最后,我在这里演示的屏幕空间折射在画布的边缘附近效果不佳,因为光线可能会折射到其边界之外的值,并且在将背景场景渲染到渲染目标时我们没有捕获到该数据。

当然,有多种方法可以克服这些限制,但是对于您在WebGL中进行实时渲染,它们可能并不是全部很好的解决方案。

关于“怎么使用threejs实现实时多边形折射”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么使用threejs实现实时多边形折射

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么使用threejs实现实时多边形折射

这篇文章将为大家详细讲解有关怎么使用threejs实现实时多边形折射,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。JavaScript的特点1.JavaScript主要用来向HTML页面添加交互行为。2.
2023-06-14

使用css3怎么实现一个六边形边框

使用css3怎么实现一个六边形边框?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。实现代码:HTML代码
2023-06-08

使用matplotlib怎么实现一个多边形选区功能

本篇文章为大家展示了使用matplotlib怎么实现一个多边形选区功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。多边形选区概述多边形选区是一种常见的对象选择方式,在一个子图中,单击鼠标左键即构建
2023-06-06

怎么使用CSS实现酷炫六边形网格背景图

本文小编为大家详细介绍“怎么使用CSS实现酷炫六边形网格背景图”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用CSS实现酷炫六边形网格背景图”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。如何绘制六边形?首
2023-07-04

vue怎么使用echarts实现折线图

这篇文章主要讲解了“vue怎么使用echarts实现折线图”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue怎么使用echarts实现折线图”吧!效果图:代码: