Shadertoy着色器移植到Three.js经验总结

news2025/5/13 13:00:18

Shadertoy是一个流行的在线平台,用于创建和分享WebGL片段着色器。里面有很多令人惊叹的画面,甚至3D场景。本人也移植了几个ShaderToy上的着色器。本文将详细介绍移植过程中需要注意的关键点。

1. 基本结构差异

想要移植ShaderToy的shader到three.js,需要先了解他们直接的差异。他们之间的差异主要在以下几个方面:

  1. ShaderToy没有顶点着色器
    ShaderTory上面的shader只有片元着色器,没有几何,移植到three.js上需要构造一个默认的顶点着色器,同时提供几何信息。这个也比较简单,使用两个三角形铺面整个视口即可。其实用其他的方式也可以,例如用一个大的三角形,只要有个物体几何能充满整个视口即可。

  2. ShaderToy提供了很多内置变量
    ShaderToy提供了不少内置变量,,在three.js中需要咱们自己用uniform来传入。ShaderToy内置变量处理方法如下:

全局变量含义three.js修改方案核心代码
uniform vec3 iResolution;视口大小,单位像素uniforms.iResolution = { value: new THREE.Vector2(options.width, options.hieght) }
uniform float iTime;从开始运行到现在的时间,单位秒var clock = new THREE.Clock();
this.uniforms.iTime.value = this.clock.getElapsedTime();
uniform float iTimeDelta;上一帧渲染到现在的时间,单位秒var clock = new THREE.Clock();
this.uniforms.iTimeDelta.value = this.clock.getDelta();
uniform int iFrame;第几帧this.uniforms.iFrame.value = this.uniforms.iFrame.value + 1;
uniform float iChannelTime[4];//
uniform vec3 iChannelResolution[4];每个通道的分辨率,单位像素uniforms[“iChannelResolution”] = { type: “v3v”, value: [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), ] };
uniform vec4 iMouse;是vec4类型,xy是鼠标当前位置与单击位置,zw是单击位置document.addEventListener(‘mousemove’, (e) => { material.uniforms.iMouse.value.x = e.clientX; material.uniforms.iMouse.value.y = window.innerHeight - e.clientY; }); document.addEventListener(‘mousedown’, (e) => { material.uniforms.iMouse.value.z = e.clientX; material.uniforms.iMouse.value.w = window.innerHeight - e.clientY; });
uniform samplerXX iChanneli;通道的纹理uniforms[“iChannel” + i] = { type: “t”, value: texture }
  1. ShaderToy语法的差异

ShaderToy语法核心都是 GLSL,只是在在变量命名、输入输出方式、内置函数/变量等方面存在区别。以下是关键语法差异的对比:

ShaderToythree.js
入口函数是:mainImage(out vec4 fragColor, in vec2 fragCoord)入口函数是:void main()
fragCoord当前像素的坐标用的是gl_FragCoord
用变量fragColor作为输出通过 gl_FragColor 变量输出
不需要定义变量精度需定义精度:precision highp float; precision highp int;precision highp sampler2D;precision highp samplerCube;

移植基本模版

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Shadertoy to Three.js</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            display: block;
        }
    </style>
</head>

<body>
    <script src="./three.min.js"></script>
    <script>
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        console.log(renderer.capabilities.isWebGL2)

        const geometry = new THREE.BufferGeometry();
        geometry.setAttribute("position", new THREE.Float32BufferAttribute([-1, -1, 0,
            1, -1, 0,
            1, 1, 0,
        -1, 1, 0], 3))
        geometry.setIndex([0, 1, 2, 0, 2, 3]);

        const material = new THREE.RawShaderMaterial({
            uniforms: {
                iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
                iTime: { value: 0 },
                mouse: { value: new THREE.Vector4(0, 0, 0, 0) },
            },
            // glslVersion: THREE.GLSL3,
            vertexShader: `#version 300 es
                in vec3 position;
                void main() {
                    gl_Position = vec4(position, 1.0);
                }
            `,
            fragmentShader: `#version 300 es
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp samplerCube;
out vec4 fragColor;

uniform vec2 iResolution;
uniform float iTime;

void main(  )
{
     vec2 uv = gl_FragCoord.xy/iResolution.xy;// [0,1]
    
    uv -= 0.5;
    uv.x *= iResolution.x / iResolution.y;
    
    float d = length(uv);
    float r = 0.3;
    float c = smoothstep(r, r + 0.002, d);

    fragColor = vec4(vec3(c), 1.);
}
`
        });
        const plane = new THREE.Mesh(geometry, material);
        scene.add(plane);

        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
            material.uniforms.iResolution.value.set(window.innerWidth, window.innerHeight);
        });

        document.addEventListener('mousemove', (e) => {
            material.uniforms.iMouse.value.x = e.clientX;
            material.uniforms.iMouse.value.y = window.innerHeight - e.clientY;
        });
        document.addEventListener('mousedown', (e) => {
            material.uniforms.iMouse.value.z = e.clientX;
            material.uniforms.iMouse.value.w = window.innerHeight - e.clientY;
        });

        function animate() {
            requestAnimationFrame(animate);
            material.uniforms.iTime.value = performance.now() / 1000; // 秒为单位
            renderer.render(scene, camera);
        }
        animate();
    </script>
</body>

</html>

这个模版是画圆的实例,效果如下:

有以下几点需要注意:

  1. 两个三角形面片的坐标已经在[-1, 1]之间,不需要在VertexShader进行坐标变换,所有顶点着色器代码没有MVP矩阵:
#version 300 es
in vec3 position;
void main() {
    gl_Position = vec4(position, 1.0);
}
  1. 使用了RawShaderMaterial而不是ShaderMaterial,这样可对Shader代码进行完全掌控
  2. 语法上使用了WebGL2.0的语法,如果使用1.0的语法,需去掉版本声明、一些关键字

最后展示一个稍微复杂点的Shader效果:

结语

将Shadertoy着色器移植到Three.js需要对两者之间的差异有清晰理解。正确处理全局变量、语法、渲染管线等关方面的差异,可将绝大多数Shadertoy效果成功移植到Three.js项目中。

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

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

相关文章

电脑端音乐播放器推荐:提升你的听歌体验!

在快节奏的职场环境中&#xff0c;许多上班族都喜欢用音乐为工作时光增添色彩。今天要分享的这款音乐工具&#xff0c;或许能为你的办公时光带来意想不到的惊喜。 一、软件介绍-澎湃 澎湃音乐看似是个普通的播放器&#xff0c;实则藏着强大的资源整合能力。左侧功能栏清晰陈列着…

VIC-2D 7.0 为平面样件机械试验提供全视野位移及应变数据软件

The VIC-2D系统是一个完全集成的解决方案&#xff0c;它基于优化的相关算法为平面试样的力学测试提供非接触、全场的二维位移和应变数据&#xff0c;可测量关注区域内的每个像素子集的面内位移&#xff0c;并通过多种张量选项计算全场应变。The VIC-2D 系统可测量超过 2000%变形…

一周学完计算机网络之三:1、数据链路层概述

简单的概述 数据链路层是计算机网络体系结构中的第二层&#xff0c;它在物理层提供的基本服务基础上&#xff0c;负责将数据从一个节点可靠地传输到相邻节点。可以将其想象成一个负责在两个相邻的网络设备之间进行数据 “搬运” 和 “整理” 的 “快递中转站”。 几个重要概念…

单片机-STM32部分:13-1、蜂鸣器

飞书文档https://x509p6c8to.feishu.cn/wiki/V8rpwIlYIiEuXLkUljTcXWiKnSc 一、应用场景 大部分的电子产品、家电&#xff08;风扇、空调、电水壶&#xff09;都会有蜂鸣器&#xff0c;用于提示设备的工作状态 二、原理 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0…

动态IP技术赋能业务创新:解锁企业数字化转型新维度

在数字经济高速发展的今天&#xff0c;IP地址已不再是简单的网络标识符&#xff0c;而是演变为支撑企业数字化转型的核心基础设施之一。动态IP技术凭借其灵活、高效、安全的特性&#xff0c;正在重塑传统业务模式&#xff0c;催生出诸多创新应用场景。本文将深入剖析动态IP的技…

TDengine 在金融领域的应用

简介 金融行业正处于数据处理能力革新的关键时期。随着市场数据量的爆炸式增长和复杂性的日益加深&#xff0c;金融机构面临着寻找能够高效处理大规模、高频次以及多样化时序数据的大数据处理系统的迫切需求。这一选择将成为金融机构提高数据处理效率、优化交易响应时间、提高…

OSCP - Hack The Box - Sau

主要知识点 CVE-2023-27163漏洞利用systemd提权 具体步骤 执行nmap扫描&#xff0c;可以先看一下55555端口 Nmap scan report for 10.10.11.224 Host is up (0.58s latency). Not shown: 65531 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp o…

QT6 源(93)篇三:阅读与注释共用体类 QVariant 及其源代码,本类支持比较运算符 ==、!=。

&#xff08;9&#xff09; 本类支持比较运算符 、! &#xff1a; 可见&#xff0c; QString 类型里可存储多个 unicode 字符&#xff0c;即使只存储一个 unicode 字符也不等于 QChar。 &#xff08;10&#xff09;本源代码来自于头文件 qvariant . h &#xff1a; #ifndef Q…

Maven私服搭建与登录全攻略

目录 1.背景2.简介3.安装4.启动总结参考文献 1.背景 回顾下maven的构建流程&#xff0c;如果没有私服&#xff0c;我们所需的所有jar包都需要通过maven的中央仓库或者第三方的maven仓库下载到本地&#xff0c;当一个公司或者一个团队所有人都重复的从maven仓库下载jar包&#…

力扣210(拓扑排序)

210. 课程表 II - 力扣&#xff08;LeetCode&#xff09; 这是一道拓扑排序的模板题。简单来说&#xff0c;给出一个有向图&#xff0c;把这个有向图转成线性的排序就叫拓扑排序。如果有向图中有环就没有办法进行拓扑排序了。因此&#xff0c;拓扑排序也是图论中判断有向无环图…

C++ asio网络编程(5)简单异步echo服务器

上一篇文章:C asio网络编程(4)异步读写操作及注意事项 文章目录 前言一、Session类1.代码2.代码详解3.实现Session类1.构造函数2.handle_read3.介绍一下boost的封装函数和api4.handle_write 二、Server类1.代码2.代码思路详解 三、客户端四、运行截图与流程图 前言 提示&…

【机器人】复现 UniGoal 具身导航 | 通用零样本目标导航 CVPR 2025

UniGoal的提出了一个通用的零样本目标导航框架&#xff0c;能够统一处理多种类型的导航任务。 支持 对象类别导航、实例图像目标导航和文本目标导航&#xff0c;而无需针对特定任务进行训练或微调。 本文分享UniGoal复现和模型推理的过程&#xff5e; 查找沙发&#xff0c;模…

spring中的@PropertySource注解详解

一、核心功能与作用 PropertySource是Spring框架中用于加载外部配置文件的核心注解&#xff0c;主要作用是将属性文件&#xff08;如.properties、.yml&#xff09;的键值对加载到Spring的Environment环境中&#xff0c;实现配置与代码的解耦。其核心价值包括&#xff1a; 外部…

二极管钳位电路——Multisim电路仿真

目录 二极管钳位电路 2.1 二极管正向钳位电路 二极管压降测试 2.1.1 二极管正向钳位电路图 2.1.2 二极管正向钳位工作原理 2.2 二极管负向钳位电路 2.2.1 二极管负向钳位电路图 2.2.2 二极管负向钳位工作原理 二极管正向反向钳位仿真电路实验结果 2.3 二极管顶部钳位…

suricata增加单元测试编译失败

一、环境 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammysuricata: suricata7.0.5 IDE: vscode 二、背景 在suricata中开发了某个功能后&#xff0c;增加unittest时&#xff0c;…

高并发场景下的BI架构设计:衡石分布式查询引擎与缓存分级策略

在电商大促、金融交易时段或IoT实时监控场景中&#xff0c;企业BI系统常面临瞬时万级并发查询的冲击——运营团队需要实时追踪GMV波动&#xff0c;风控部门需秒级响应欺诈检测&#xff0c;产线监控需毫秒级反馈设备状态。传统单体架构的BI系统在此类场景下极易崩溃&#xff0c;…

鱼眼摄像头(一)多平面格式 单缓冲读取图像并显示

鱼眼摄像头&#xff08;一&#xff09;多平面格式 单缓冲读取图像并显示 1.摄像头格式 1. 单平面格式&#xff08;Single Plane&#xff09;&#xff1a;各通道数据保存在同一个平面&#xff08;缓冲&#xff09;&#xff0c;图像数据按行连续存储a. mjpeg&#xff0c;yuyv等…

机器学习笔记——特征工程

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本笔记介绍机器学习中常见的特征工程方法、正则化方法和简要介绍强化学习。 文章目录 特征工程&#xff08;Fzeature Engineering&#xff09;1. 特征提取&#xff…

A Survey of Learning from Rewards:从训练到应用的全面剖析

A Survey of Learning from Rewards&#xff1a;从训练到应用的全面剖析 你知道大语言模型&#xff08;LLMs&#xff09;如何通过奖励学习变得更智能吗&#xff1f;这篇论文将带你深入探索。从克服预训练局限的新范式&#xff0c;到训练、推理各阶段的策略&#xff0c;再到广泛…

Python爬虫第20节-使用 Selenium 爬取小米商城空调商品

目录 前言 一、 本文目标 二、环境准备 2.1 安装依赖 2.2 配置 ChromeDriver 三、小米商城页面结构分析 3.1 商品列表结构 3.2 分页结构 四、Selenium 自动化爬虫实现 4.1 脚本整体结构 4.2 代码实现 五、关键技术详解 5.1 Selenium 启动与配置 5.2 页面等待与异…