自学内容网 自学内容网

看Threejs好玩示例,学习创新与技术(LiquidRaymarching)

今天的示例有点超出我的想象,首先会科普下WGSL这种新的着色器脚本,然后说说示例《Liquid Raymarching Scene with Three.js Shading Language | Codrops (tympanus.net)》的技术流程。本示例最终呈现的效果如下。可以看到他跟QQ那个消息拖拽消灭的效果非常像。但QQ那个采用的是CSS中的溶解技术,本示例的算法另有玄机,很难一步讲清楚,请看到最后。

20240929_220411

1、什么是WGSL

我原以为在3D渲染着色器脚本方面,只有HLSL和GLSL,没想到现在针对WebGPU,推出了新的着色器脚本语言WGSL。关于WGSL的介绍我就不展开了,大家可以从官网及ThreeJS都可以找到。

在ThreeJS中,WGSL被组织成类似UE蓝图的模式,在调试过程中,可以发现每个对象具有Node这种对象形式。比如最简单的引用数值,在调试的时候其对象格式是代理变量(Proxy  VarNode)。

const t = float(1).toVar()。

虽然WGSL是一种新的开发语言,但对于学习者而言,理解并不难。为了简化描述,示例中其他的版块都是ThreeJS已封装的WGSL语言,但看起来就是JS脚本。

 2、还是画圆

看Threejs好玩示例,学习创新与技术(Noise)-CSDN博客一文中,我们学习了如何利用GLSL绘制一个标准圆。今天的示例也是画圆,但画法稍微不一样。今天采用射线(Ray)计算距离的方法。这是一个什么效果呢?

我们以上帝视角看整个屏幕,简单思考下,就应该能够想到得到如下这种效果。其中三角形表示我们眼睛的位置,每个圈表示跟眼睛位置相同距离的圆。

代码也很简单,如下(注意,我简化了代码,方便学习,实际代码会复杂那么一点点):

const _uv = uv();
const rayOrigin = vec3(0, 0, -3.3)
const rayDirection = vec3(_uv, 0)
const ray = rayOrigin.add(rayDirection).toVar()
const d = sdf(ray) // current distance to the scene
t.assign(d);
return vec3(t.mul(0.1),0,0)

 3、射线圆圈

我们看到射灯射出来的光,会形成一个簸箕状(可以看下面图的效果)。下面这个效果其跟第2章等距圆有点相似,它构建的是一个等夹角圆。算法是比较简单的。这里会有三个量,a)眼睛所在位置,b)射线目标点,3)周围照射点。

不过示例的算法,我到现在还没完全看懂,它采用还是距离判断,仍然得到上述效果,有研究的同学可以帮帮我。

我给它的代码画了一个示意图,它的算法是每次行近一段距离,并判断与中心点的距离是否小于某个阈值。当然越靠近中心点,每次步进就越小。感觉这个算法效率不高。下面是示例自己的解释。

SDF 基于计算从空间中任何点到形状表面的最短距离的概念。因此,如果点位于形状外部,则 SDF 返回的值为正,如果点位于形状内部,则返回的值为负,而恰好在表面上为零。

考虑到这一点,我们实际上只需要确定一条光线是否“足够接近”表面以使其成为命中。每个连续的步骤都会移动到最近的表面的距离,因此一旦我们越过接近 0 的某个小阈值,我们就有效地 “击中” 了一个表面,允许我们进行早期返回。

 4、交融圆

先看看两个圆交融的效果。可以看到两个圆中间部门会有一些黏黏的效果。

示例中给出的计算代码如下:

const smin = Fn(([a, b, k]) => {
  const h = max(k.sub(abs(a.sub(b))), 0).div(k)
  return min(a, b).sub(h.mul(h).mul(k).mul(0.25))
})

这段代码普通情况下是看不懂的,效果如下。其中这个a、b的范围是0~1。其中图中存在两个白线,这个白线值左边的值是负值,白线右边的值是正值。取负值表示吸附效果。这才实现上图中吸附的效果。

 本示例还有光照效果的代码,但我觉得本文到这里已经够我“喝一壶好的了”,就不在这锦上添花的说明相关代码。

国庆快乐。


原文地址:https://blog.csdn.net/htsitr2/article/details/142644176

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!