【Three.js】shader特效 能量盾

news2024/11/26 10:04:16

shader特效之能量盾

  • 前言
  • 效果噪点图
  • 主要代码
    • index.html
    • depth-fs.js
    • depth-vs.js
    • shield-fs.js
    • shield-vs.js
  • 相关项目

效果图

前言

效果噪点图

为了可以自定义能量球的效果,这里使用外部加载来的噪点图做纹理,省去用代码写特效的过程。
在这里插入图片描述

主要代码

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>Energy shield</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
  <style>
    body {
      margin: 0;
      padding: 0;
    }
  </style>
</head>

<body>
  <script type="module">
    import * as THREE from '../../build/three.module.js'
    import * as TWEEN from '../../build/tween.esm.js'
    import Stats from '../jsm/libs/stats.module.js'
    import { OrbitControls } from '../jsm/controls/OrbitControls.js'
    
    import { shader as depthVertexShader } from './shaders/depth-vs.js'
    import { shader as depthFragmentShader } from './shaders/depth-fs.js'
    import { shader as shieldVertexShader } from './shaders/shield-vs.js'
    import { shader as shieldFragmentShader } from './shaders/shield-fs.js'
    
    // renderer
    const renderer = new THREE.WebGLRenderer({ antialias: true })
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.shadowMap.enabled = true
    renderer.shadowMap.type = THREE.PCFSoftShadowMap
    renderer.outputEncoding = THREE.sRGBEncoding
    renderer.gammaFactor = 2.2
    document.body.append(renderer.domElement)
    // stats
    const stats = new Stats()
    document.body.appendChild(stats.domElement)
    // scene
    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 100)
    camera.position.set(0, 1, 2)
    // control
    const controls = new OrbitControls(camera, renderer.domElement)
    controls.minDistance = 0.5
    controls.maxDistance = 10
    controls.enableDamping = true
    controls.dampingFactor = 0.05
    controls.screenSpacePanning = true
    controls.autoRotate = false
    // cube
    const cubeGeometry = new THREE.BoxBufferGeometry(0.4, 0.4, 0.4)
    const cubeMaterial = new THREE.MeshStandardMaterial({
      color: 'rgb(100, 70, 30)',
      roughness: 0.4,
      metalness: 0.0,
      side: THREE.DoubleSide
    })
    const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
    cube.castShadow = cube.receiveShadow = true
    cube.position.set(-0.6, 0.2, -0.6)
    cube.rotation.set(-Math.PI / 2, 0, 0)
    scene.add(cube)
    // ground
    const groundGeometry = new THREE.PlaneBufferGeometry(3, 3)
    const groundMaterial = new THREE.MeshStandardMaterial({
      color: 'rgb(20, 20, 30)',
      roughness: 0.4,
      metalness: 0.0,
      side: THREE.DoubleSide
    })
    const ground = new THREE.Mesh(groundGeometry, groundMaterial)
    ground.castShadow = ground.receiveShadow = true
    ground.position.set(0, 0, 0)
    ground.rotation.set(-Math.PI / 2, 0, 0)
    scene.add(ground)
    // light1
    const light = new THREE.DirectionalLight(0xffffff)
    light.position.set(-2, 2, 0.5)
    light.castShadow = true
    light.shadow.camera.top = 2
    light.shadow.camera.bottom = -2
    light.shadow.camera.right = 2
    light.shadow.camera.left = -2
    light.shadow.bias = -0.00001
    light.shadow.mapSize.set(4096, 4096)
    scene.add(light)
    // light2
    const hemiLight = new THREE.HemisphereLight(0xbbbbbb, 0x080808, 1)
    scene.add(hemiLight)
    // light1 helper
    scene.add(new THREE.DirectionalLightHelper(light, 2, 0xFFFF00))
    // axis helper
    scene.add(new THREE.AxesHelper(100))
    
    const depthMaterial = new THREE.RawShaderMaterial({
      uniforms: {},
      vertexShader: depthVertexShader,
      fragmentShader: depthFragmentShader,
    })
    const depth = new THREE.WebGLRenderTarget(1, 1, {
      wrapS: THREE.ClampToEdgeWrapping,
      wrapT: THREE.ClampToEdgeWrapping,
      minFilter: THREE.LinearFilter,
      magFilter: THREE.LinearFilter,
      format: THREE.RGBAFormat,
      type: THREE.UnsignedByteType,
      stencilBuffer: false,
      depthBuffer: true
    })
    const hdr = new THREE.WebGLRenderTarget(1, 1, {
      wrapS: THREE.ClampToEdgeWrapping,
      wrapT: THREE.ClampToEdgeWrapping,
      minFilter: THREE.LinearFilter,
      magFilter: THREE.LinearFilter,
      format: THREE.RGBAFormat,
      type: THREE.UnsignedByteType,
      stencilBuffer: false,
      depthBuffer: true
    })
    // shield
    const textureLoader = new THREE.TextureLoader()
    const texture = textureLoader.load('./imgs/noise1.png')
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping
    const shieldGeometry = new THREE.SphereBufferGeometry(0.5, 100, 100)
    const shieldMaterial = new THREE.RawShaderMaterial({
      uniforms: {
        depthBuffer: { value: null },
        resolution: { value: new THREE.Vector2(1, 1) },
        bufColor: { value: null },
        u_tex: { value: null },
        time: { value: 0 }
      },
      vertexShader: shieldVertexShader,
      fragmentShader: shieldFragmentShader,
      transparent: true,
      depthWrite: false,
      side: THREE.DoubleSide
    })
    const shield = new THREE.Mesh(shieldGeometry, shieldMaterial)
    shield.position.set(0, 0.3, 0)
    shield.material.uniforms.depthBuffer.value = depth.texture
    shield.material.uniforms.bufColor.value = depth.texture
    shield.material.uniforms.u_tex.value = texture
    scene.add(shield)
    // tween
    function moveCube() {
      const tween = new TWEEN.Tween(cube.position)
      tween.to({
        x: 0.6,
        z: 0.6
      }, 5000)
      tween.yoyo(true)
      tween.repeat(Infinity)
      tween.start()
    }
    // resize
    function resize() {
      const width = window.innerWidth
      const height = window.innerHeight
      const dPR = window.devicePixelRatio
      camera.aspect = width / height
      camera.updateProjectionMatrix()
      renderer.setSize(width, height)
      depth.setSize(width * dPR, height * dPR)
      hdr.setSize(width * dPR, height * dPR)
      shield.material.uniforms.resolution.value.set(width * dPR, height * dPR)
    }
    // render
    function render() {
      shield.visible = false
      scene.overrideMaterial = depthMaterial
      renderer.setRenderTarget(depth)
      renderer.render(scene, camera)
    
      shield.visible = true
      scene.overrideMaterial = null
      renderer.setRenderTarget(null)
      renderer.render(scene, camera)
    
      renderer.setAnimationLoop(render)
      TWEEN.update()
      stats.update()
      controls.update()

      shield.material.uniforms.time.value = performance.now()
    }
    
    window.addEventListener('resize', resize)
    
    moveCube()
    resize()
    render()
    
  </script>
</body>

</html>

depth-fs.js

const shader = `#version 300 es

precision highp float;

#include <packing>

in vec2 vUv;
in float vDepth;

out vec4 color;

void main() {
  float depth = (vDepth - .1) / ( 10.0 -.1);
  color = packDepthToRGBA(depth);
}
`;

export { shader };

depth-vs.js

const shader = `#version 300 es

precision highp float;

in vec3 position;
in vec2 uv;

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

out vec2 vUv;
out float vDepth;

void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  vDepth = gl_Position.z;
}
`;

export { shader };

shield-fs.js

const shader = `#version 300 es

precision highp float;

#include <packing>

uniform sampler2D depthBuffer;
uniform vec2 resolution;
uniform float time;
uniform sampler2D u_tex;

in float vRim;
in vec2 vUv;
in float vDepth;

out vec4 color;

const vec4 baseColor = vec4(0.0,0.9,0.0,0.1);

void main() {
    // 基础色
    color = baseColor;

    // 动态纹理
    vec4 maskA = texture(u_tex, vUv);
    maskA.a = maskA.r;
    color += maskA;
    
    // 边界高亮
    vec2 uv = gl_FragCoord.xy / resolution;
    vec4 packedDepth = texture(depthBuffer, uv);
    float sceneDepth = unpackRGBAToDepth(packedDepth);
    float depth = (vDepth - .1) / ( 10.0 -.1);
    float diff = abs(depth - sceneDepth);
    float contact = diff * 20.;
    contact = 1. - contact;
    contact = max(contact, 0.);
    contact = pow(contact, 20.);
    contact *= diff*1000.;
    float a = max(contact, vRim);
    float fade = 1. - pow(vRim, 10.);
    color += a * fade;
}
`;

export { shader };

shield-vs.js

const shader = `#version 300 es

precision highp float;

in vec3 position;
in vec3 normal;
in vec2 uv;

uniform mat3 normalMatrix;
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform float time;

out vec2 vUv;
out float vRim;
out float vDepth;

void main() {
  vUv = uv;
  vUv.x += time * 0.0001;
  vUv.y += time * 0.0006;

  vec3 n = normalMatrix * normal;
  vec4 viewPosition = modelViewMatrix * vec4( position, 1. );
  vec3 eye = normalize(-viewPosition.xyz);
  vRim = 1.0 - abs(dot(eye,n));
  vRim = pow(vRim, 5.);
  vec3 worldPosition = (modelMatrix * vec4(position, 1.)).xyz;  
  gl_Position = projectionMatrix * viewPosition;
  vDepth = gl_Position.z;
}
`;

export { shader };

相关项目

🚩——坦克大战
📦—— 立体库房
🎄—— 圣诞树
✅—— 程序员升职记
🏀—— 投个篮吧
💖——粒子爱心

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

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

相关文章

数据表(一) - 数据表的种类

在游戏项目中缺少不了数据表&#xff0c;数据决定了游戏的整个进程&#xff0c;因此怎么用数据表配置数&#xff0c;配置数据时是否方便成了关键的问题。那么如何来理解数据表的存在呢&#xff1f;数据表完全可以认为是一个本地的数据库&#xff0c;只不过这个数据库里的数据是…

Facebook Shop和Facebook Marketplace如何选择?

Facebook Shop和Facebook Marketplace都是可以让facebook用户售卖商品的平台&#xff0c;这两者有什么区别&#xff1f;在facebook上开网店要使用那一个平台更好&#xff1f;又要如何开通使用&#xff1f;这篇文章都会一一告诉你&#xff01; 一、Facebook Shop Facebook shop主…

【项目实战】Protobuf入门介绍以及如何生成proto对象文件

一、 Protobuf 介绍 1.1 诞生背景 常用的数据格式是 JSON&#xff0c;XML&#xff0c;或者 YAML&#xff0c;这些都是文本格式&#xff0c;特点是容易被人识别&#xff0c;非常容易编程&#xff0c;缺点是数据量有点大。在某些特定场景下&#xff0c;比如帧同步、各个应用之间…

个人创业做什么比较好?需要具备哪些基本素质?

个人创业是一种创造、追求自由和独立的方式&#xff0c;也是许多人梦寐以求的事情。但是&#xff0c;很多人并不知道该做什么才能取得成功。在这篇文章中&#xff0c;我将探讨一些个人创业的建议&#xff0c;希望能够帮助你找到自己的方向。 1. 站在行业创新的前沿 在当前竞争…

Echarts数据可视化图表设计 学习笔记 python

&#x1f4e3; 概况 Echarts 是一个由百度开源的数据可视化&#xff0c;凭借着良好的交互性&#xff0c;精巧的图表设计&#xff0c;得到了众多开发者的认可。而 Python 是一门富有表达力的语言&#xff0c;很适合用于数据处理。当数据分析遇上数据可视化时&#xff0c;pyechar…

高端Zynq ultrascale+使用GTH回环测试 提供2套工程源码和技术支持

这目录1、前言2、GTH 高速收发器介绍GTH 高速收发器结构参考时钟的选择和分配GTH 发送端GTH 接收端3、vivado工程详解4、上板调试验证5、福利&#xff1a;工程代码的获取1、前言 Xilinx系列FPGA内置高速串行收发器&#xff0c;配有可配置的IP方便用户调用&#xff0c;按照速度…

QML ComboBox简介

1.简介 ComboBox是一个组合按钮和弹出列表。它提供了一种以占用最小屏幕空间的方式向用户显示选项列表的方法。 ComboBox用数据模型填充。数据模型通常是JavaScript数组、ListModel或整数&#xff0c;但也支持其他类型的数据模型。 常用属性&#xff1a; count : int&#x…

R语言基础(四):数据类型

R语言基础(一)&#xff1a;注释、变量 R语言基础(二)&#xff1a;常用函数 R语言基础(三)&#xff1a;运算 5.数据类型 5.1 基本数据类型 R语言基本数据类型大致有六种&#xff1a; 整数Integer、浮点数Numeric、文本(字符串)Character、逻辑(布尔)Logical、复合类型Complex、…

基于Docker快速搭建蜜罐Dionaea(30)

实验目的 1. 快速搭建Dionaea蜜罐 2. 使用Nmap扫描测试Dionaea蜜罐预备知识1. 初步认识Dionaea dionaea&#xff0c;中文的意思即捕蝇草&#xff0c;是否形容蜜罐很形象&#xff1f;dionaea是nepenthes&#xff08;猪笼草&#xff09;的发展和后续&#xff0c;更加容易被部署和…

华大单片机、STM32单片机如何做printf串口打印格式化输出

第一种方法&#xff1a;使用标准C库&#xff0c;但使用标准C库你必须关闭半主机模式&#xff08;1&#xff09;添加下面代码就是关闭半主机模式/* 告知连接器不从C库链接使用半主机的函数 */ #pragma import(__use_no_semihosting)/* 定义 _sys_exit() 以避免使用半主机模式 */…

【项目日志】电商后台管理项目日志

技巧 对脚手架框架的梳理 使用脚手架建立项目后默认初始页面非空白&#xff0c;可以自行设置成空白页&#xff0c;将app.vue中的内容和样式清空即可router中的不必要的路由设置可以清除 如何右键打开powershell&#xff1f; 按住shift在空白处单击右键&#xff08;win10和2…

一个故事看懂CPU的SIMD技术

好久不见&#xff0c;我叫阿Q&#xff0c;是CPU一号车间的员工。我所在的CPU有8个车间&#xff0c;也就是8个核心&#xff0c;咱们每个核心都可以同时执行两个线程&#xff0c;就是8核16线程&#xff0c;那速度杠杠滴。 我所在的一号车间&#xff0c;除了负责执行指令的我&…

蓝牙5.4出来了,实现单个接入点与数千个终端节点双向通讯

蓝牙技术联盟最近发布了蓝牙5.4的核心规范&#xff0c;蓝牙5.4规范的主要改进之一就是实现了单个接入点与数千个终端节点进行双向无连接通信&#xff0c; 这一特性主要是针对电子货架标签市场。蓝牙5.4有哪些改进和新功能&#xff1f;蓝牙技术联盟最近发布了蓝牙5.4的核心规范&…

保姆级使用PyTorch训练与评估自己的EVA网络教程

文章目录前言0. 环境搭建&快速开始1. 数据集制作1.1 标签文件制作1.2 数据集划分1.3 数据集信息文件制作2. 修改参数文件3. 训练4. 评估5. 其他教程前言 项目地址&#xff1a;https://github.com/Fafa-DL/Awesome-Backbones 操作教程&#xff1a;https://www.bilibili.co…

【大数据处理与可视化】二 、Numpy科学计算库

【大数据处理与可视化】一 、大数据分析环境搭建&#xff08;安装 Anaconda 3 开发环境&#xff09;实验目的实验内容实验步骤1、创建一个值域范围从10到49的向量。2、创建一个 3x3 并且值从0到8的矩阵。3、创建一个 3x3 的单位矩阵。4、创建一个数组&#xff0c;数组的shape为…

第十四届蓝桥杯三月真题刷题训练——第 7 天

目录 第 1 题&#xff1a;三角回文数 问题描述 答案提交 运行限制 代码&#xff1a; 第 2 题&#xff1a;数数 问题描述 答案提交 运行限制 代码&#xff1a; 第 3 题&#xff1a;倍数问题_同余定理_分情况讨论 题目描述 输入描述 输出描述 输入输出样例 运行限…

Azure Portal 访问安全性增强

Azure Portal 访问安全性增强客户需求如何设置账号&#xff08;包括Admin&#xff09;定期修改密码&#xff0c;例如强制每90天必须修改密码如何设定账号密码的复杂性要求如何设定限制访问Azure Portal的源IP Address客户需求 为了增强访问Azure Portal的安全性&#xff0c;希…

JavaWeb--ListenerAjaxaxiosjson

Listener&Ajax&axios1 Listener1.1 概述1.2 分类1.3 代码演示2 Ajax2.1 概述2.1.1 作用2.1.2 同步和异步2.2 快速入门2.2.1 服务端实现2.2.2 客户端实现2.2.3 测试2.3 案例2.3.1 分析2.3.2 后端实现2.3.3 前端实现2.4 测试3 axios3.1 基本使用3.2 快速入门3.2.1 后端实…

32*4VKL128 LQFP44超低功耗/超低工作电流/抗干扰LCD液晶段码驱动IC/LCD驱动芯片(IC) 适用于激光/红外线测距仪

产品型号&#xff1a;VKL128产品品牌&#xff1a;永嘉微电/VINKA封装形式&#xff1a;LQFP44产品年份&#xff1a;新年份原厂&#xff0c;工程服务&#xff0c;技术支持&#xff01;VKL128概述:VKL128是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大128点&#xff08;3…

BSN-DDC基础网络详解(五):接入DDC网络(1)

BSN-DDC基础网络推出已经一年了&#xff0c;得到了行业应用方和广大开发者的高度认可。一年中BSN产品技术团队也在根据市场业务需求不断更新功能服务&#xff0c;我们将通过本系列文章为大家系统化介绍DDC网络的功能和使用&#xff0c;为感兴趣的朋友提供学习帮助。01支持DDC的…