【Three.js基础学习】29.Hologram Shader
前言
three.js 通过着色器如何实现全息影像,以及一些动态的效果。
一些难点的思维,代码目录
下面图是摄像机视角观看影响上的时候,如何实现光影的渐变,透视以及叠加等。
一、代码
1.index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Holographic</title><link rel="stylesheet" href="./style.css">
</head>
<body><canvas class="webgl"></canvas><script type="module" src="./script.js"></script>
</body>
</html>
2.style.css
*
{margin: 0;padding: 0;
}html,
body
{overflow: hidden;
}.webgl
{position: fixed;top: 0;left: 0;outline: none;
}
3.script.js
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import GUI from 'lil-gui'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import holographicVertexShader from './shaders/holographic/vertex.glsl'
import holographicFragmentShader from './shaders/holographic/fragment.glsl'/*** Base*/
// Debug
const gui = new GUI()// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()// Loaders
const gltfLoader = new GLTFLoader()/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(25, sizes.width / sizes.height, 0.1, 100)
camera.position.set(7, 7, 7)
scene.add(camera)// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true/*** Renderer*/
const rendererParameters = {}
rendererParameters.clearColor = '#1d1f2a'const renderer = new THREE.WebGLRenderer({canvas: canvas,antialias: true
})
renderer.setClearColor(rendererParameters.clearColor)
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))gui.addColor(rendererParameters, 'clearColor').onChange(() =>{renderer.setClearColor(rendererParameters.clearColor)})/*** Material*/
const materialParameters = {}
materialParameters.color = '#70c1ff'gui.addColor(materialParameters,'color').onChange(()=>{material.uniforms.uColor.value.set(materialParameters.color)})const material = new THREE.ShaderMaterial({vertexShader:holographicVertexShader,fragmentShader:holographicFragmentShader,uniforms:{uTime:new THREE.Uniform(0),uColor:new THREE.Uniform(new THREE.Color(materialParameters.color))},transparent:true, // 设置透明材质side:THREE.DoubleSide,depthWrite:false, // 停止深度写入blending:THREE.AdditiveBlending, // 混合叠加 叠加起来的颜色更亮})/*** Objects*/
// Torus knot
const torusKnot = new THREE.Mesh(new THREE.TorusKnotGeometry(0.6, 0.25, 128, 32),material
)
torusKnot.position.x = 3
scene.add(torusKnot)// Sphere
const sphere = new THREE.Mesh(new THREE.SphereGeometry(),material
)
sphere.position.x = - 3
scene.add(sphere)// Suzanne
let suzanne = null
gltfLoader.load('./suzanne.glb',(gltf) =>{suzanne = gltf.scenesuzanne.traverse((child) =>{if(child.isMesh)child.material = material})scene.add(suzanne)}
)/*** Animate*/
const clock = new THREE.Clock()const tick = () =>
{const elapsedTime = clock.getElapsedTime()// Update material.uniforms.uTime.value = elapsedTime;// Rotate objectsif(suzanne){suzanne.rotation.x = - elapsedTime * 0.1suzanne.rotation.y = elapsedTime * 0.2}sphere.rotation.x = - elapsedTime * 0.1sphere.rotation.y = elapsedTime * 0.2torusKnot.rotation.x = - elapsedTime * 0.1torusKnot.rotation.y = elapsedTime * 0.2// Update controlscontrols.update()// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()
4.fragment.glsl 顶点着色器
uniform float uTime;
uniform vec3 uColor;varying vec3 vPosition;
varying vec3 vNormal;/* mod(X, Y)函数返回X对Y取模的结果。如果X和Y都是数组,mod函数会对数组的每个元素分别进行取模运算对上一步的结果取模 1.0,即计算该值除以 1.0 的余数。由于取模 1.0 的效果是将值限制在 0 到 1 之间(不包括1),这个操作实际上是在做一个周期性变换,使得 vUv.x 在 0 到 10 之间变化时,结果会在 0 到 1 之间循环pow(x,y)x的y次方。如果x小于0,结果是未定义的。同样,如果x=0并且y<=0,结果也是未定义的normalize 标准化向量,返回一个方向和x相同但长度为1的向量dot 向量x,y之间的点积Fresnel 根据相机角度,进行判断,相同方向1,直角0 ,相反 1同样法线应该渲染,vertex.glsl
*/void main(){// Normal 法线标准值重新定义为1vec3 normal = normalize(vNormal); // 两个角度大的法线之间,的法线长度不是标准,重新初始化1if(!gl_FrontFacing)normal *= - 1.0;// Stripes 条纹 float stripes = mod((vPosition.y - uTime * 0.02) * 20.0, 1.0);stripes = pow(stripes, 3.0);// Fresnel 菲涅尔效果 全息vec3 viewDirection = normalize(vPosition - cameraPosition) ; // 模型位置 - 相机位置,得到视图位置float fresnel = dot(viewDirection,normal) + 1.0; // 这里加上一,原本的0变成1,-1变成0fresnel = pow(fresnel,2.0);// Falloff 平滑重映射 想要实现边界处 1-0转变 逐渐消失的效果float falloff = smoothstep(0.8,0.0,fresnel);// Holographic 全息float holographic = stripes * fresnel;holographic += fresnel * 1.25;holographic *= falloff;// Final Colorgl_FragColor = vec4(uColor,holographic);#include <tonemapping_fragment>#include <colorspace_fragment>
}
5.vertex.glsl 片段着色器
uniform float uTime; varying vec3 vPosition;
varying vec3 vNormal;/* smoothstep(edge0, edge1, x) 如果x <= edge0,返回0.0 ;如果x >= edge1 返回1.0;如果edge0 < x < edge1,则执行0~1之间的平滑埃尔米特差值。如果edge0 >= edge1,结果是未定义的。
*/#include ../includes/random2D.glslvoid main(){// Positionvec4 modelPosition = modelMatrix * vec4(position,1.0);// Glitch random2D函数会给我0-1的数据,减去0.5 相机的中心位置就不会偏移float glitchTime = uTime - modelPosition.y; // 设置故障时间float glitchStrength = sin(glitchTime) + sin(glitchTime * 3.45) + sin(glitchTime * 8.76); // 改变频率glitchStrength /= 3.0;glitchStrength = smoothstep(0.3,1.0,glitchStrength);glitchStrength *= 0.25;modelPosition.x += (random2D(modelPosition.xz + uTime) - 0.5) * glitchStrength;modelPosition.z += (random2D(modelPosition.zx + uTime) - 0.5) * glitchStrength;gl_Position = projectionMatrix * viewMatrix * modelPosition;// Model normal/* 当第四个值为1.0时,向量为“同质”,所有3个变换(翻译、旋转、比例)都将被应用。当第四个值为0.0时,向量不是“同质的”,因此不会应用转换在正常情况下是理想的,因为正常不是一个职位,而是一个*/vec4 modelNormal = modelMatrix * vec4(normal,0.0); // 为什么设置0.0 就是不希望正常,保持法线向上vPosition = modelPosition.xyz;vNormal = modelNormal.xyz;
}
6.random2D.glsl 随机数方法
float random2D(vec2 value)
{return fract(sin(dot(value.xy, vec2(12.9898,78.233))) * 43758.5453123);
}
二、效果
Hologram Shader
总结
全息影像显示,可以加到自己个人的项目中。感觉还不错!
相关文章:

【Three.js基础学习】29.Hologram Shader
前言 three.js 通过着色器如何实现全息影像,以及一些动态的效果。 一些难点的思维,代码目录 下面图是摄像机视角观看影响上的时候,如何实现光影的渐变,透视以及叠加等。 一、代码 1.index.html <!DOCTYPE html> <html …...

文件包含进阶玩法以及绕过姿态
前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理文件包含漏洞的进阶玩法与绕过姿态 不涉及基础原理了 特殊玩法汇总 本地包含 文件包含上传文件 原理: php的文件包含有着把其他文件类型当做php代码执行的功效,文件上传一般会限制后缀&am…...

Markdown编辑器工具--Typora
下载链接...
PyTorch 的 torch.unbind 函数详解与进阶应用:中英双语
中文版 PyTorch 的 torch.unbind 函数详解与进阶应用 在深度学习中,张量的维度操作是基础又重要的内容。PyTorch 提供了许多方便的工具来完成这些操作,其中之一便是 torch.unbind。与常见的堆叠函数(如 torch.stack)相辅相成&am…...
四十六:如何使用Wireshark解密TLS/SSL报文?
TLS/SSL是保护网络通信的重要协议,其加密机制可以有效地防止敏感信息被窃取。然而,在调试网络应用或分析安全问题时,解密TLS/SSL流量是不可避免的需求。本文将介绍如何使用Wireshark解密TLS/SSL报文。 前提条件 在解密TLS/SSL报文之前&…...

【人工智能】OpenAI O1模型:超越GPT-4的长上下文RAG性能详解与优化指南
在人工智能(AI)领域,长上下文生成与检索(RAG) 已成为提升自然语言处理(NLP)模型性能的关键技术之一。随着数据规模与应用场景的不断扩展,如何高效地处理海量上下文信息,成…...

Ubuntu22.04搭建FTP服务器保姆级教程
在网络环境中,文件传输是一项至关重要的任务。FTP(文件传输协议)是一种基于客户端/服务器模式的协议,广泛用于在互联网上传输文件。Ubuntu作为一款流行的Linux发行版,因其稳定性和易用性而广受开发者和系统管理员的喜爱…...

操作系统(4)操作系统的结构
一、无序结构(整体结构或模块组合结构) 1.特点: 以大型表格和队列为中心,操作系统的各部分程序围绕着这些表格进行。操作系统由许多标准的、可兼容的基本单位(称为模块)构成,模块之间通过规定的…...
Python数据分析(OpenCV视频处理)
处理视频我们引入的还是numpy 和 OpenCV 的包 引入方式如下: import numpy as np import cv2 我们使用OpenCV来加载本地视频,参数就是你视频的路径就可以 #加载视频 cap cv2.VideoCapture(./1.mp4) 下面我们进行读取视频 #读取视频 flag,frame cap.re…...
跨域 Cookie 共享
跨域请求经常遇到需要携带 cookie 的场景,为了确保跨域请求能够携带用户的认证信息或其他状态,浏览器提供了 withCredentials 这个属性。 如何在 Axios 中使用 withCredentials 为了在跨域请求中携带 cookie,需要在 Axios 配置中设置 withCr…...

【视频异常检测】Real-Time Anomaly Detection and Localization in Crowded Scenes 论文阅读
文章信息: 发表于:CVPR2015(workshop) 原文链接:https://www.cv-foundation.org/openaccess/content_cvpr_workshops_2015/W04/papers/Sabokrou_Real-Time_Anomaly_Detection_2015_CVPR_paper.pdf Real-Time Anomaly D…...
设计模式12:抽象工厂模式
系列总链接:《大话设计模式》学习记录_net 大话设计-CSDN博客 参考: C设计模式:抽象工厂模式(风格切换案例)_c 抽象工厂-CSDN博客 1.概念 抽象工厂模式(Abstract Factory Pattern)是软件设计…...

论文学习——多种变化环境下基于多种群进化的动态约束多目标优化
论文题目:Multipopulation Evolution-Based Dynamic Constrained Multiobjective Optimization Under Diverse Changing Environments 多种变化环境下基于多种群进化的动态约束多目标优化(Qingda Chen , Member, IEEE, Jinliang Ding , Senior Member, …...

Jenkins参数化构建详解(This project is parameterized)
本文详细介绍了Jenkins中不同类型的参数化构建方法,包括字符串、选项、多行文本、布尔值和git分支参数的配置,以及如何使用ActiveChoiceParameter实现动态获取参数选项。通过示例展示了传统方法和声明式pipeline的语法 文章目录 1. Jenkins的参数化构建1…...

Cerebras 推出 CePO,填补推理与规划能力的关键空白
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
广东省食品销售中高级题库及答案
1.有关食品安全标准的说法正确的是(C)。 A.鼓励性标准 B.推荐性标准 C.强制性标准 D.引导性标准 2.食品经营许可证载明的许可事项发生变化的,食品经营者应当在变化后(D)个工作日内向原发证的食品药品监督管理部门申请变更经营许可。 A.3 B.5 C.7 D.10 3.食品销售经营者对食品…...

JAVA基础-深入理解Java内存模型(一)-- 重排序与先行发生原则(happens-before)
深入理解Java内存模型(一)-- 重排序 很棒的一个关于Java内存模型系列文章,首先感谢作者,转载自深入理解java内存模型系列文章 ,为了方便阅读,做了一些内容整合和重排版。 提纲 Java线程之间的通信对程序…...

【Lambda】java之lambda表达式stream流式编程操作集合
java之lambda表达式&stream流式编程操作集合 1 stream流概念1.1 中间操作1.1.1 无状态操作1.1.2 有状态操作 1.2 终端操作1.2.1 非短路操作1.2.2 短路操作 2 steam流的生成2.1 方式一:数组转为stream流2.2 方式二:集合转为steam流2.3 方式三…...

家具购物小程序+php
基于微信小程序的家具购物小程序的设计与实现 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的家具购物小程序的设计与实现的开发全过程。通过分析基于微信小程序的家具购物小程序的设计与实…...

【GIS教程】使用GDAL-Python将tif转为COG并在ArcGIS Js前端加载-附完整代码
目录 一、数据格式 二、COG特点 三、使用GDAL生成COG格式的数据 四、使用ArcGIS Maps SDK for JavaScript加载COG格式数据 一、数据格式 COG(Cloud optimized GeoTIFF)是一种GeoTiff格式的数据。托管在 HTTP 文件服务器上,可以代替geose…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...