iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >如何用threejs实现实时多边形折射
  • 260
分享到

如何用threejs实现实时多边形折射

2024-04-02 19:04:59 260人浏览 泡泡鱼
摘要

目录前言步骤1:设定和正面折射步骤2:反射和菲涅耳方程步骤3:多边折射局限性前言 在本教程中,您将学习如何使用Three.js在三个步骤中使对象看起来像玻璃。 渲染3D对象时,无论使

前言

在本教程中,您将学习如何使用Three.js在三个步骤中使对象看起来像玻璃。

渲染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 1
this.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 );
};

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

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


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);
}

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

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

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

在片段着色器中,我们将使用菲涅耳方程来计算反射光线与折射光线之间的比率。不幸的是,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);
}

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

步骤3:多边折射

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

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

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

让我们像在步骤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只是一个标量值,指示应应用背面法线的数量。

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

局限性

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

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

以上就是如何用threejs实现实时多边形折射的详细内容,更多关于JS库的资料请关注编程网其它相关文章!

--结束END--

本文标题: 如何用threejs实现实时多边形折射

本文链接: https://www.lsjlt.com/news/125343.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • 如何用threejs实现实时多边形折射
    目录前言步骤1:设定和正面折射步骤2:反射和菲涅耳方程步骤3:多边折射局限性前言 在本教程中,您将学习如何使用Three.js在三个步骤中使对象看起来像玻璃。 渲染3D对象时,无论使...
    99+
    2024-04-02
  • 怎么使用threejs实现实时多边形折射
    这篇文章将为大家详细讲解有关怎么使用threejs实现实时多边形折射,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。JavaScript的特点1.JavaScript主要用来向HTML页面添加交互行为。2....
    99+
    2023-06-14
  • css如何实现多边形和梯形盒阴影
    小编给大家分享一下css如何实现多边形和梯形盒阴影,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一般情况下,我们给块状元素(四边形)添加阴影样式,直接用css box-shadow: 0 1px 3px 0 rgba(0,...
    99+
    2023-06-08
  • css如何实现六边形
    小编给大家分享一下css如何实现六边形,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧! css实现六边...
    99+
    2024-04-02
  • css实现多边形的方法
    这篇文章主要介绍“css实现多边形的方法”,在日常操作中,相信很多人在css实现多边形的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”css实现多边形的方法”的疑惑有所帮...
    99+
    2024-04-02
  • Vue使用openlayers实现绘制圆形和多边形
    目录绘制圆形绘制多边形绘制编辑多边形完成绘制这个地方我就简单点写吧,因为一些东西比较乱,有的包啥的就按照官网API开发文档根据报错提示自己添加就可以了,我这个地方就不重复写了。 绘制...
    99+
    2024-04-02
  • 基于C#如何实现多边形冲突检测
    这篇文章主要为大家展示了“基于C#如何实现多边形冲突检测”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“基于C#如何实现多边形冲突检测”这篇文章吧。前言之前在项目上碰到了一个多边形冲突检测的问题,...
    99+
    2023-06-20
  • 基于Flutter如何实现多边形和多角星组件
    这篇文章主要介绍了基于Flutter如何实现多边形和多角星组件的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇基于Flutter如何实现多边形和多角星组件文章都会有所收获,下面我们一起来看看吧。组件功能正多边形正...
    99+
    2023-06-30
  • OpenCV实现轮廓外接多边形
    本文实例为大家分享了OpenCV实现轮廓外接多边形的具体代码,供大家参考,具体内容如下 取轮廓最大外接矩形 Rect boundingRect( InputArray array...
    99+
    2024-04-02
  • css如何实现六边形图片
    小编给大家分享一下css如何实现六边形图片,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!先上效果: 用简单的div配合伪元素,即可‘画出’这幅六边形图片,原理是三个相同宽高...
    99+
    2023-06-08
  • css如何实现图形化边界
    这篇文章给大家分享的是有关css如何实现图形化边界的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。图形化边界  顾名思义,图形化边界就是允许使用图片作为对象的边界,语法如下:  border: 5px&n...
    99+
    2023-06-27
  • WPF如何实现能自由改变形状的四边形和六边形
    本文小编为大家详细介绍“WPF如何实现能自由改变形状的四边形和六边形”,内容详细,步骤清晰,细节处理妥当,希望这篇“WPF如何实现能自由改变形状的四边形和六边形”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。效果图...
    99+
    2023-07-05
  • Flutter绘制3.4边形及多边形渐变动画实现示例
    目录正文绘制3.4边形整数边形的绘制分数边形的绘制具体代码效果改进1效果改进2正文 项目被优化了,人也跟着被优化了,正好趁这一个月整理整理关于flutter的一些东西。 绘制3.4边...
    99+
    2022-11-13
    Flutter绘制3.4边形渐变动画 Flutter绘制渐变动画
  • 纯CSS如何实现单一div的正多边形变换
    小编给大家分享一下纯CSS如何实现单一div的正多边形变换,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!正三角形正三角形不需要用到伪元素,只需要设定div本身的边...
    99+
    2023-06-08
  • 如何使用纯CSS实现单一div的正多边形变换
    这篇文章给大家分享的是有关如何使用纯CSS实现单一div的正多边形变换的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。   纯粹利用CSS,让“单一个”div,从正三角形变换为正...
    99+
    2024-04-02
  • 如何使用SVG 画多边形
    这篇文章主要讲解了“如何使用SVG 画多边形”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用SVG 画多边形”吧!一、 Polygon 画多边形简单的...
    99+
    2024-04-02
  • CSS3实现缺角矩形、折角矩形以及缺角边框的案例
    这篇文章将为大家详细讲解有关CSS3实现缺角矩形、折角矩形以及缺角边框的案例,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。效果图:缺角  1. 伪元素实现<div class=&...
    99+
    2023-06-08
  • 如何实现多色CSS边框
    小编给大家分享一下如何实现多色CSS边框,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!多色CSS边框如果我们想给边框加上比前面的示例更多的颜色怎么办我们甚至可以将...
    99+
    2023-06-27
  • 基于Flutter实现多边形和多角星组件
    目录前言组件功能1、原理2、找点小结:前言 开发中,免不了会用到多边形、多角星等图案,比较常用的多边形比如雷达图、多角星比如评价星级的五角星等,本篇文章就使用Flutter绘制封装一...
    99+
    2024-04-02
  • vue+echarts如何实现多条折线图
    小编给大家分享一下vue+echarts如何实现多条折线图,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体内容如下数据未使用json格式,直接写在页面大致效果页面代码:<template> &nbs...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作