【Threejs进阶教程-着色器篇】6. 2D SDF(三) 移动图形,限制图形,绘制多个图形

2D SDF 移动与合并图形

  • 前五篇地址,建议按顺序学习
  • 本篇使用到的初始代码
  • 减小扩散范围
    • clamp函数
    • 修改maxDistance来修改扩散范围
  • 移动扩散中心
  • 添加第二个扩散点
    • 降低点的同步率
    • 调整参数来优化效果
    • 添加更多扩散点
  • 完整源码
  • 如有不明白的,可以在下方留言或者加群

前五篇地址,建议按顺序学习

【Threejs进阶教程-着色器篇】1. Shader入门(ShadertoyShader和ThreejsShader入门)
【Threejs进阶教程-着色器篇】2. Uniform的基本用法与Uniform的调试
【Threejs进阶教程-着色器篇】3. Uniform的基本用法2与基本地球昼夜效果
【Threejs进阶教程-着色器篇】4. 2D SDF(一) SDF的基本用法
【Threejs进阶教程-着色器篇】5. 2D SDF(二)圆形波纹效果

本篇使用到的初始代码

【Threejs进阶教程-着色器篇】5. 2D SDF(二)圆形波纹效果
请在此文的最后,自行复制粘贴对应的上一篇完整代码,本篇将会以上一篇的代码为基础,扩展当前的效果

减小扩散范围

因为现在我们是用透明度来控制扩散效果的,所以,我们本次的修改也主要以透明度为准

我们现在的透明度情况,是以中心为准,每一圈的内圈起点处透明度最低,透明度为0,每一圈的外圈终点处,透明度为1,我们是用fract限制了这个值的最大值只能为1,但是并没有限制半径,所以我们从半径下手

  1. 先设定一个扩散半径
  2. 然后计算当前的auv值到扩散中心的距离,与半径的比值,
  3. 用这个比值,与最终计算的alp值相乘

以默认值为例,我们现阶段的默认的iFreq的值为10.0,也就是说,在图形的四个边缘处到中心的距离,等于半径,当前值为10,四个角上的顶点处,距离中心的距离为 sqrt(10 * 10),所以,我们可以先设置一个低于10的值

<!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;float sdCircle( vec2 p, float r ){return length(p) - r;}void main(){vec2 aUv = (vUv - 0.5) * iFreq;float alp = fract(sdCircle(aUv, 0.5) - iTime * iSpeed);alp = pow(alp,iPower);//对扩散的光波pow可以减少光波有颜色的部分的宽度float maxDistance = 5.0;//扩散半径alp *= distance(aUv,vec2(0.0)) / maxDistance;gl_FragColor = vec4(iColor,alp);}
</script>

在这里插入图片描述
但是,这个效果明显是不对的,不仅半径没有得到限制,且中心变的透明化了
既然是中心变的透明化了,说明最终的计算值已经是0了,那么想让中心实色化,就用1.0 - 计算结果即可,但是,因为计算的值,可能会小于1,那么,我们做个限制,让它取值为0~1即可

<!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;float sdCircle( vec2 p, float r ){return length(p) - r;}void main(){vec2 aUv = (vUv - 0.5) * iFreq;float alp = fract(sdCircle(aUv, 0.5) - iTime * iSpeed);alp = pow(alp,iPower);//对扩散的光波pow可以减少光波有颜色的部分的宽度float maxDistance = 5.0;//扩散半径alp *= 1.0 - distance(aUv,vec2(0.0)) / maxDistance;//一定注意,alp是float类型的,这里写大于的时候,后面的数字必须是float类型,不能是1,不然threejs会报错if(alp > 1.0){alp = 1.0;}else if(alp < 0.0){alp = 0.0;}gl_FragColor = vec4(iColor,alp);}
</script>

在这里插入图片描述

clamp函数

不过,上面的写法是可以优化的,glsl内置了clamp函数,来取代上面的if-else写法

//原写法if(alp > 1.0){alp = 1.0;}else if(alp < 0.0){alp = 0.0;}
//新写法alp = clamp(alp,0.0,1.0);

clamp函数不仅对float类型数据有效,对向量也可用,截图截取自《webgl编程指南》431页
注意使用的时候,看清楚函数的数据类型,以及,min值不要大于max值
在这里插入图片描述

修改maxDistance来修改扩散范围

通过修改maxDistance到2.0,我们就得到了这样的一个效果
在这里插入图片描述

移动扩散中心

既然我们可以更改扩散范围,那么,我们亦可更改扩散的中心点
在片元着色器中,修改 vUv - 0.5的位置为: vUv - vec2(0.2,0.5),即可让扩散中心向左侧偏移
这里的vec2(0.2,0.5),本质上就是扩散中心的位置

		//原代码vec2 aUv = (vUv - 0.5) * iFreq;//新代码vec2 aUv = (vUv - vec2(0.2,0.5)) * iFreq;

在这里插入图片描述

但是,我们这样来搞就麻烦了,所以我们现在需要封装一个方法出来,为了方便后续的开发内容

<!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;float sdCircle( vec2 p, float r ){return length(p) - r;}//三个参数分别为: 扩散中心,基本半径,最大半径float createWave(vec2 center,float radius,float maxDistance){vec2 aUv = (vUv - center) * iFreq;float alp = fract(sdCircle(aUv,0.5) - iTime * iSpeed);alp = pow(alp,iPower);alp *= 1.0 - distance(aUv,vec2(0.0)) / maxDistance;alp = clamp(alp,0.0,1.0);return alp;}void main(){float alp = createWave(vec2(0.2,0.5),0.5,2.0);gl_FragColor = vec4(iColor,alp);}
</script>

添加第二个扩散点

第二个扩散点其实非常简单,就是利用一下上面我们封装好的函数,直接追加一份即可

<!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;float sdCircle( vec2 p, float r ){return length(p) - r;}//三个参数分别为: 扩散中心,基本半径,最大半径float createWave(vec2 center,float radius,float maxDistance){vec2 aUv = (vUv - center) * iFreq;float alp = fract(sdCircle(aUv,0.5) - iTime * iSpeed);alp = pow(alp,iPower);alp *= 1.0 - distance(aUv,vec2(0.0)) / maxDistance;alp = clamp(alp,0.0,1.0);return alp;}void main(){float alp = createWave(vec2(0.2,0.5),0.5,2.0);alp += createWave(vec2(0.8,0.5),0.5,2.0);alp += createWave(vec2(0.5,0.2),0.5,2.0);alp += createWave(vec2(0.5,0.8),0.5,2.0);gl_FragColor = vec4(iColor,alp);}
</script>

在这里插入图片描述
为什么直接添加就能出效果?
非常简单,那个位置的透明度为0,0加任何的数据,都等于任何数据

降低点的同步率

现在的四个点,同步率非常的高,我们只需要在iTime上做手脚,让他们的初始速度发生变化即可

  1. 在封装的createWave方法中,添加参数 waveValue
  2. 调用方法时,传入不同的值
<!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;float sdCircle( vec2 p, float r ){return length(p) - r;}//三个参数分别为: 扩散中心,基本半径,最大半径float createWave(vec2 center,float radius,float maxDistance, float waveValue){vec2 aUv = (vUv - center) * iFreq;float alp = fract(sdCircle(aUv,radius) - iTime * iSpeed + waveValue);alp = pow(alp,iPower);alp *= 1.0 - distance(aUv,vec2(0.0)) / maxDistance;alp = clamp(alp,0.0,1.0);return alp;}void main(){float alp = createWave(vec2(0.2,0.5),0.5,2.0,0.2);alp += createWave(vec2(0.8,0.5),0.5,2.0,0.4);alp += createWave(vec2(0.5,0.2),0.5,2.0,0.6);alp += createWave(vec2(0.5,0.8),0.5,2.0,0.8);gl_FragColor = vec4(iColor,alp);}
</script>

在这里插入图片描述

调整参数来优化效果

  1. 将maxDistance抽出,使用unifrom + lil.gui来控制
  2. 调整参数到效果接近想要的效果
    在这里插入图片描述

添加更多扩散点

首先要说明的是,在shader中,没有随机数!随机只能借助noise函数来实现
现阶段,暂时仅建议多手敲几个点到图像上,简单看一下效果即可,在后续讲到noise函数的时候,这里还会再次提及

<!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;uniform float maxDistance;float sdCircle( vec2 p, float r ){return length(p) - r;}//三个参数分别为: 扩散中心,基本半径,最大半径float createWave(vec2 center,float radius, float waveValue){vec2 aUv = (vUv - center) * iFreq;float alp = fract(sdCircle(aUv,radius) - iTime * iSpeed + waveValue);alp = pow(alp,iPower);alp *= 1.0 - distance(aUv,vec2(0.0)) / maxDistance;alp = clamp(alp,0.0,1.0);return alp;}void main(){float alp = createWave(vec2(0.2,0.5),0.5,0.1);alp += createWave(vec2(0.12,0.35),0.5,0.2);alp += createWave(vec2(0.6,0.33),0.5,0.3);alp += createWave(vec2(0.49,0.24),0.5,0.4);alp += createWave(vec2(0.87,0.14),0.5,0.5);alp += createWave(vec2(0.35,0.88),0.5,0.6);alp += createWave(vec2(0.23,0.34),0.5,0.7);alp += createWave(vec2(0.65,0.44),0.5,0.8);alp += createWave(vec2(0.57,0.12),0.5,0.9);alp += createWave(vec2(0.88,0.92),0.5,0.9);alp += createWave(vec2(0.75,0.72),0.5,0.9);gl_FragColor = vec4(iColor,alp);}
</script>

在这里插入图片描述

完整源码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>body{width:100vw;height: 100vh;overflow: hidden;margin: 0;padding: 0;border: 0;}</style>
</head>
<body><script type="importmap">{"imports": {"three": "../three/build/three.module.js","three/addons/": "../three/examples/jsm/"}}</script><script type="x-shader/x-vertex" id="vertexShader">varying vec2 vUv;void main(){vUv = vec2(uv.x,uv.y);vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_Position = projectionMatrix * mvPosition;gl_Position = projectionMatrix * modelMatrix * viewMatrix * vec4( position, 1.0 );}</script><!-- 片元着色器代码 -->
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;uniform float iTime;uniform float iFreq;uniform vec3 iColor;uniform float iSpeed;uniform float iPower;uniform float maxDistance;float sdCircle( vec2 p, float r ){return length(p) - r;}//三个参数分别为: 扩散中心,基本半径,最大半径float createWave(vec2 center,float radius, float waveValue){vec2 aUv = (vUv - center) * iFreq;float alp = fract(sdCircle(aUv,radius) - iTime * iSpeed + waveValue);alp = pow(alp,iPower);alp *= 1.0 - distance(aUv,vec2(0.0)) / maxDistance;alp = clamp(alp,0.0,1.0);return alp;}void main(){float alp = createWave(vec2(0.2,0.5),0.5,0.1);alp += createWave(vec2(0.12,0.35),0.5,0.2);alp += createWave(vec2(0.6,0.33),0.5,0.3);alp += createWave(vec2(0.49,0.24),0.5,0.4);alp += createWave(vec2(0.87,0.14),0.5,0.5);alp += createWave(vec2(0.35,0.88),0.5,0.6);alp += createWave(vec2(0.23,0.34),0.5,0.7);alp += createWave(vec2(0.65,0.44),0.5,0.8);alp += createWave(vec2(0.57,0.12),0.5,0.9);alp += createWave(vec2(0.88,0.92),0.5,0.9);alp += createWave(vec2(0.75,0.72),0.5,0.9);gl_FragColor = vec4(iColor,alp);}
</script><script type="module">import * as THREE from "../three/build/three.module.js";import {OrbitControls} from "../three/examples/jsm/controls/OrbitControls.js";import {GUI} from "../three/examples/jsm/libs/lil-gui.module.min.js";window.addEventListener('load',e=>{init();addMesh();render();})let scene,renderer,camera;let orbit;function init(){scene = new THREE.Scene();renderer = new THREE.WebGLRenderer({alpha:true,antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,0.1,2000);camera.add(new THREE.PointLight());camera.position.set(15,15,15);scene.add(camera);orbit = new OrbitControls(camera,renderer.domElement);orbit.enableDamping = true;scene.add(new THREE.GridHelper(10,10));}let uniforms = {iTime:{value:0},iFreq:{value:21},//频率,光波圈数iColor:{value:new THREE.Color('#d1d1d1')},//光波颜色iSpeed:{value:2},//扩散速度iPower:{value:2.5},//光波强度maxDistance:{value:6.37},//最大扩散半径}function addMesh() {//常规情况下,planeGeometry,circleGeometry是与z轴垂直的,改成与y轴垂直,只需要沿着x轴让几何体旋转-90度即可//let geometry = new THREE.PlaneGeometry(10,10).rotateX(-Math.PI/2);//为了让效果更适用于圆形,我们从方形的planeGeometry换成CircleGeometrylet geometry = new THREE.CircleGeometry(5,32).rotateX(-Math.PI/2);let material = new THREE.ShaderMaterial({uniforms,vertexShader:document.getElementById('vertexShader').textContent,fragmentShader:document.getElementById('fragmentShader').textContent,transparent:true})let mesh = new THREE.Mesh(geometry,material);scene.add(mesh);let param = {color:"#d1d1d1" //lil.gui读取threejs的颜色比较麻烦,个人习惯在这里单独写一个来控制};let gui = new GUI();gui.add(uniforms.iFreq,'value',0,50,0.01).name('光波圈数');gui.add(uniforms.iPower,'value',0,50,0.01).name('光波强度');gui.add(uniforms.iSpeed,'value',0,50,0.01).name('扩散速度');gui.add(uniforms.maxDistance,'value',0,50,0.01).name('最大扩散半径');gui.addColor(param,'color').name('光波颜色').onChange(v=>{uniforms.iColor.value = new THREE.Color(v);})}function render() {uniforms.iTime.value += 0.01;renderer.render(scene,camera);orbit.update();requestAnimationFrame(render);}</script>
</body>
</html>

如有不明白的,可以在下方留言或者加群

如有其他不懂的问题,可以在下方留言,也可以加入qq群咨询,
Web3D+GIS开源社区为新群,群内相对来说学习气氛良好,群号131995948
本人的群,群号867120877
欢迎大家来群里交流技术
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/52831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GIT】Idea中的git命令使用-全网最新详细(包括现象含义)

原文网址&#xff1a;【GIT】Idea中的git命令使用-全网最新详细&#xff08;包括现象含义&#xff09; 文章目录 **命令1&#xff1a;查看当前所处分支&#xff1a;****命令2&#xff1a;拉取最新代码&#xff1a;****命令3&#xff1a;切换分支&#xff1a;****命令4&#xff…

MAC 、 IP ARP

MAC地址 基本概念 MAC地址是以太网的MAC子层所使用的地址——数据链路层 使用点对点信道的数据链路层不需要使用地址 使用广播信道的数据链路层必须使用地址来区分各主机 实现同一个广播信道上的不同主机之间的通信 每个主机都必须要有一个唯一的表示——一个数据链路层地址…

基于Java+SpringBoot+Vue的学生评奖评优管理系统的设计与实现

基于JavaSpringBootVue的学生评奖评优管理系统的设计与实现 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345; 某信 gzh 搜索【智…

2024 年的 Web3 游戏:演变、趋势和市场动态

Web3 游戏行业在经历了多年的快速发展和变革之后&#xff0c;正在2024年迎来全新的阶段。这个行业从最初的边玩边赚&#xff08;Play-to-Earn, P2E&#xff09;模式出发&#xff0c;如今正在向更为平衡的“边玩边赚”模式转型。这种转型不仅解决了早期 P2E 模式下存在的可持续性…

EmguCV学习笔记 VB.Net 9.1 VideoCapture类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

编译LineageOS模拟器镜像,导出到AndroidStudio

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 源码下载 LineageOS官网&#xff1a;https://lineageos.org/ LineageOS源码 github 地址&#xff1a;https://github.com/LineageOS/android LineageOS源码国…

编写一个每次随机生成 10个 0(包括) 到 100 之间的随机正整数。

编写一个每次随机生成 10个 0&#xff08;包括&#xff09; 到 100 之间的随机正整数。 package cn.itcast.example;import java.util.Iterator; import java.util.Random; public class example {public static void main (String[] arge) {System.out.println("Math.ra…

QNN:基于QNN+example重构之后的yolov8det部署

QNN是高通发布的神经网络推理引擎&#xff0c;是SNPE的升级版&#xff0c;其主要功能是&#xff1a; 完成从Pytorch/TensorFlow/Keras/Onnx等神经网络框架到高通计算平台的模型转换&#xff1b; 完成模型的低比特量化&#xff08;int8&#xff09;&#xff0c;使其能够运行在高…

超长二进制利用Integer转换

1.Integer缺点 目前测试Integer只能一次性转4*7位二进制数&#xff0c;也就是7位16进制&#xff0c;故进行改进 2.改进 操作&#xff1a;每四位二进制一转换&#xff0c;以免到上限报错 注解格式&#xff1a;序号&#xff08;代码顺序&#xff09;解释 public class Main {…

《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层(2)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层&#xff08;1&#xff09; 7.1 数据链路层的组成结构 数据链路层使用ACK/NAK协议发送和接收TLP&#xff0c;由发送部件和接收部件组成。其中&#xff0c;发送部件由…

Springboot里集成Mybatis-plus、ClickHouse

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; Springboot里集成Mybati…

基于Java+SpringBoot+Vue的汽车销售网站

基于JavaSpringBootVue的汽车销售网站 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345; 某信 gzh 搜索【智能编程小助手】获取项…

【大模型】llama系列模型基础

前言&#xff1a;llama基于transformer架构&#xff0c;与GPT相似&#xff0c;只用了transformer的解码器部分。本文主要是关于llama&#xff0c;llama2和llama3的结构解读。 目录 1. llama1.1 整体结构1.2 RoPE1.3 SwiGLU 激活函数 2. llama22.2 GQA架构2.3 RLHF 3. llama3参考…

Springboot中使用Elasticsearch(部署+使用+讲解 最完整)

目录 引言 一、docker中安装Elasticsearch 1、创建es专有的网络 2、开放端口 3、在es-net网络上安装es和kibana 4、可能出现的问题 5、测试 6、安装IK分词器 7、测试IK分词器 二、结合业务实战 1、准备依赖 2、配置yml 3、读取yml配置 4、准备es配置类 5、编写测…

Leetcode面试经典150题-136.只出现一次的数字

解法都在代码里&#xff0c;不懂就留言或者私信 这个题不知道为啥会考&#xff0c;过于简单了&#xff0c;我解题写注释用了两分钟不到&#xff0c;5行代码。。。 class Solution {public int singleNumber(int[] nums) {/**这个题目确实时间的题&#xff0c;根据位运算法则我…

斗破C++编程入门系列之十九:C++程序设计必知:多文件结构和编译预处理命令(九星斗者)

斗破C目录&#xff1a; 斗破C编程入门系列之前言&#xff08;斗之气三段&#xff09; 斗破C编程入门系列之二&#xff1a;Qt的使用介绍&#xff08;斗之气三段&#xff09; 斗破C编程入门系列之三&#xff1a;数据结构&#xff08;斗之气三段&#xff09; 斗破C编程入门系列之…

ctfshow之web55~web57(无字母的rce)

目录 web55 思路一&#xff1a; 思路二&#xff1a; web56 web57 本系列主要针对无字母rce或无字母无数字rce 声明&#xff1a;本章内容是引荐几位师傅的博客&#xff0c;然后根据自己的理解编写而成。 web55 if(isset($_GET[c])){$c$_GET[c];if(!preg_match("/\…

乐凡三防:工业界的硬核产品——重新定义三防平板的极限

在工业4.0的浪潮中&#xff0c;科技与制造业的深度融合催生了一系列高性能、高耐用的智能产品。乐凡三防平板&#xff0c;作为工业界的新宠&#xff0c;正以其卓越的防护性能和强大的功能&#xff0c;重新定义了三防平板的极限&#xff0c;成为硬核科技的代表。 硬核防护&#…

GD32F4xx---RTC初始化设置及闹钟方式实现秒中断讲解

GD32F4xx—RTC初始化设置及闹钟方式实现秒中断讲解 1、下载链接:源码工程 一、概述 GD32F4x的RTC例程网上资源较少,详细阅读用户手册后做出如下配置。RTC模块提供了一个包含日期(年/月/日)和时间(时/分/秒/亚秒)的日历功能。除亚秒用二进制码显示外,时间和日期都以BC…

大连网站建设手机网页页面设计

在现代社会&#xff0c;随着智能手机的普及&#xff0c;越来越多的用户选择通过手机访问网站&#xff0c;这使得移动端网页设计的重要性日益凸显。大连作为一个经济和文化中心&#xff0c;网站建设行业也在不断发展。针对大连的网站建设&#xff0c;手机网页页面设计需要特别注…