ThreeJS Shader的效果样例光影墙、扩散面(四)

news/2024/11/15 10:00:16/文章来源:https://www.cnblogs.com/codeOnMar/p/18406443

一、实现一个光影墙

  1. 根据自定义坐标点,输出一个光影墙

  

/*** 添加光影墙*/
function addLightWall() {const geometry = new THREE.BufferGeometry();const vertices = new Float32Array([5, 0, 2,3, 0, 5,-2, 0, 5,-4, 0, 2,-4, 5, 2,-2, 5, 5,3, 5, 5,5, 5, 2]);const indices = new Uint16Array([0, 1, 7,1, 6, 7,1, 2, 6,2, 5, 6,2, 3, 5,3, 4, 5])geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));geometry.setIndex(new THREE.BufferAttribute(indices, 1));geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));const uniforms = {uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
}function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];scene.add(planeMesh);
}
自定义坐标

 

  2. 圆柱体的光影墙

  

/*** 添加光影墙*/
function addLightWall() {const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));// 生成一个渐变色的光影墙const vertex = `varying vec3 vPosition;varying vec2 vUv;varying float vHeight;attribute float aHeight;void main() {vHeight = aHeight;vUv = uv;vPosition = position;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `varying vec3 vPosition;varying vec2 vUv;varying float vHeight;void main() {float d = (vHeight - distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z))) / vHeight;gl_FragColor = vec4(0.0, 1.0, 1.0, d);}`;const uniforms = {uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
}function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];scene.add(planeMesh);
}
圆柱体光影墙

 

  3. 为圆柱体添加可移动的线圈

  

/*** 添加光影墙*/
function addLightWall() {const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));// 生成一个可以向上移动的墙体线const vertex = `varying vec3 vPosition;varying vec2 vUv;varying float vHeight;attribute float aHeight;void main() {vHeight = aHeight;vUv = uv;vPosition = position;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `uniform float uTime;varying vec3 vPosition;varying vec2 vUv;varying float vHeight;void main() {float dis = distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z));float highlightPos = mod(uTime * 5.0, vHeight) - 2.5;float highlightDis = distance(vec3(vPosition.x, highlightPos, vPosition.z), vec3(vPosition.x, -2.5, vPosition.z));float highlightOpa = (vHeight - highlightDis) / vHeight;float opacity = (vHeight - dis) / vHeight;if (abs(dis - highlightDis) < 0.05) {gl_FragColor = vec4(0.04, 0.95, 0.95, highlightOpa + 0.2);} else {gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);}}`;const uniforms = {uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
}function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];scene.add(planeMesh);
}
移动线圈光影墙

 

二、实现一个渐变色的波纹圆圈

  1. 实现一个固定的渐变色圆圈

  原理:

    1) UV点的范围是[0, 1],所以各个像素点距离圆心的距离范围是0~0.5,如果乘以2刚好是透明度的范围(0~1),这样就可以实现一个简单的渐变圆

    2) 假设厚度为t,那么颜色的透明度的范围是[1, 1-t],而我们实际需要的是[1, 0],可以用图二来表示两个线性关系,可以得到两个方程式

      方程式1:y = -x + 1; 

      方程式2:y = -t + 1;  

      现在我们知道方程式二中的y的值(像素点到中心的距离distance),通过解方程式就可以得到方程式1中所对应的透明度的值为 (distance - 1) / t + 1;

              

  

  

/*** 添加一个扩散面*/
function addDiffuseCircle() {const geometry = new THREE.CircleGeometry(3, 48);// 绘制一个渐变圈宽度可控的圆弧const vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `uniform float uTime;uniform float uThickness;varying vec2 vUv;void main() {// 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2float distance = length(vUv - 0.5) * 2.0;float opacity = (distance - 1.0) / uThickness + 1.0;gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);}`;const uniforms = {uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度uSpeed: { value: 0.5, range: [0, 5] },uTime: { value: 0.01 },};setGui(uniforms);setShader(geometry, vertex, frag, [0,0,0], uniforms);
}function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];planeMesh.rotateX(Math.PI / 2);scene.add(planeMesh);
}
厚度可变的渐变圆

 

  2. 半径自动缩放的渐变圆

  

/*** 添加一个扩散面*/
function addDiffuseCircle() {const geometry = new THREE.CircleGeometry(3, 48);// 创建一个大小可控的渐变圆弧const vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `uniform float uTime;uniform float uThickness;uniform float uSpeed;varying vec2 vUv;void main() {// 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2// 假设从内像外开始扩散,距离和时间关系是 最内部: 距离0,时间0;最外部:距离1,时间1,如果用1-时间的话,// 所以此时1-时间+距离和样例1中的透明度相同float timeDis = fract(uTime * uSpeed);float distance = length(vUv - 0.5) * 2.0;if (timeDis < distance) {gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0);} else {float opacity = (1.0 - timeDis + distance - 1.0) / uThickness + 1.0;gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);}}`;const uniforms = {uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度uSpeed: { value: 0.5, range: [0, 5] },uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0,0,0], uniforms);
}function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];planeMesh.rotateX(Math.PI / 2);scene.add(planeMesh);
}
自动缩放的渐变圆

 

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

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

相关文章

2024年youtube 视频在线下载工具

1.youtube to wav这是一个将 YouTube 视频转换为 WAV 格式的在线工具的网站链接。根据提供的信息,使用该工具的步骤如下: 开始:将 YouTube 视频的 URL 粘贴到搜索框中,然后点击 “Start” 按钮。 转换:选择转换为 WAV 的质量(推荐使用默认选项),然后点击 “Convert” 按…

Idea 配置多端口启动参数

1、编辑配置2、在弹出配置中增加要使用端口接口,添加端口参数配置、设置VM options: 参数值为: -Dserver.port= portNumber下面以应用 TranSendServiceApplication 为例,增加两个端口:8099 和8091 为例。截图如下:

【闲话】假如我们都是猫娘

你是一袋猫粮猫娘驯化实录 ZHESHIWOYAOMOZHENGBEIDISANJIEMOZHENGXIANHUADASAIDECANSAIZUOPIN. (A:Chat-GPT 4.0) (另:因为某些纯魔怔原因,我们连皮下内容也回了)。 A 17:33:41 喵~主人你好呀!我是您的猫娘助手,挪威森林猫品种,身高148cm,梳着双马尾~需要我帮忙做…

chainLink vrf实验

目标 用vrf写一个随机红包 数据结构 红包: struct Envelope {Type t; // 类型,只是erc20 和eth红包ERC20 token; // erc20 ,如果是erc20红包,这里是erc2o的地址address sender; // 发红包的senderuint balance; // 金额bool allowAll; // 允许所有人领取uint32 maxRe…

代码随想录算法 - 二叉树3

题目1513. 找树左下角的值 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1:输入: root = [2,1,3] 输出: 1示例 2:输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示:二叉树的节点个数的范围是 [1,104] -231 &…

Combinatorics/Probability/Expectation

前言 计数加训!!!! 以下问题都是数数。 一些纯组合问题 插板法 例 1 求 $\sum_{i=1}^kx_i=n$ 的解的组数,其中 $x_i\in \mathbb{N^+}$ 且 $x_i\ge a_i$。 考虑令 $x_i=x_i-a_i+1\ge 1$,于是有 $\sum_{i=1}^k x_i=n-k+\sum a_i$,于是答案为 $$n-k+\sum a_i-1\choose k-1$…

信息学奥赛初赛天天练-88-CSP-S2023阅读程序1-数据类型、unsigned 关键字、二进制、位运算、左移、右移、异或运算

信息学奥赛初赛天天练-88-CSP-S2023阅读程序1-数据类型、unsigned 关键字、二进制、位运算、左移、右移、异或运算 PDF文档公众号回复关键字:202409132023 CSP-S 阅读程序1 判断题正确填 √,错误填 ⨉ ;除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分) 01 #include …

来云栖大会!探展云上开发,沉浸式体验云原生 + AI 新奇玩法

计算馆将展示中国最先进的云计算产业链全景,从底层硬件到数据创新,从云计算基础设施到数据管理服务、人工智能平台和模型服务,全景式呈现 AI 时代云计算最新技术形态和产品进展。2024 云栖大会来了! 本届云栖大会将于 9 月 19 日至 9 月 21 日 在杭州云栖小镇召开 汇集全球…

最后的记录

最后的挣扎但是做的题太少了根本算不上长征。 写这个是因为 NOIP2024 剩百日,这他妈是最后一次了,就让我拿个一等吧,别无所求了。 把之前做过的题都重新总结一遍,怎么说也都能吃透了。 P6880 JOI 2020 Final] オリンピックバス 给一个有向图,经过边有代价 \(C_i\),可以反…

ENSP 某台设备出现乱码的情况

故障现象:新建拓扑没问题,打开其他人发的拓扑就会出现乱码(或者打开ENSP的示例也会出现问题),配置文档正常可以正常导出不受影响。 故障发现时间:2022年底 故障原因:windows系统BUG,常见于inter 13代CPU(例如I5-13500) 处理方法1:重装系统(一劳永逸) 处理方法2:例…

10、Linux文本编辑器

文本编辑器 常见文本编辑器 WindowsNotepad(记事本) Sublime UltraEditLinuxVI/VIM nano Emacs Sed gedit KateVI 和 VIM 的区别VI全称:Visual Interface 创建时间:1976年 创建者:Bill JoyVIM全称:VI IMproved,即 VI 的升级版 创建时间:1991年 创建者:Bram Moolenaar …