【Threejs进阶教程-着色器篇】8. Shadertoy如何使用到Threejs-基础版

news2024/11/18 14:01:26

【Threejs进阶教程-着色器篇】8. Shadertoy如何使用到Threejs - 基础版

  • 前七篇地址,建议按顺序学习
  • 致谢带我入门的[X01动力装甲]大佬
  • 本文适用范围
  • 怎么样在Shadertoy中画出正圆形
    • shadertoy中的坐标系比例转换
    • 理解Shadertoy的fragCoord
    • 理解Shadertoy中的iResolution
  • 转移Shadertoy 2D效果到片元着色器
    • 处理mainImage和fragColor
  • 全部源码

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

【Threejs进阶教程-着色器篇】1. Shader入门(ShadertoyShader和ThreejsShader入门)
【Threejs进阶教程-着色器篇】2. Uniform的基本用法与Uniform的调试
【Threejs进阶教程-着色器篇】3. Uniform的基本用法2与基本地球昼夜效果
【Threejs进阶教程-着色器篇】4. 2D SDF(一) SDF的基本用法
【Threejs进阶教程-着色器篇】5. 2D SDF(二)圆形波纹效果
【Threejs进阶教程-着色器篇】6. 2D SDF(三) 移动图形,限制图形,绘制多个图形
【Threejs进阶教程-着色器篇】7. 2D SDF 其他SDF介绍与图形边界绘制

致谢带我入门的[X01动力装甲]大佬

首先感谢X01动力装甲 大佬提供的文章
three.js使用Shadertoy的着色器

我的shader入门的一大半功劳,都要归功于X01动力装甲大佬的这篇文章,通过搬运Shadertoy,强化对片元着色器的理解
基本的Shadertoy到Three的使用,已经由装甲大佬讲清楚了,这里本文则是以个人理解的角度,对上述文章做一些补充式的教程

本文适用范围

大多数的2D Shadertoy的案例,到 Threejs的ShaderMaterial的片元着色器
注意是2D效果 到 片元着色器

怎么样在Shadertoy中画出正圆形

在这里插入图片描述


float sdCircle( in vec2 p, in float r ) 
{
    return length(p)-r;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;
    
    uv -= 0.5;//平移坐标系

    float red = sdCircle(uv,0.1);//使用2d圆形sdf计算红色区域
    
    red = red>0.0?0.0:1.0;//值大于0.0时取无色,否则取红色

    // Output to screen
    fragColor = vec4(red,0.0,0.0,1.0);
}

我们在Shadertoy中新建一个demo,然后使用sdCircle来绘制一个圆形,但是,我们发现,这里我们的圆形是一个椭圆,而在Threejs的片元着色器中,是一个正圆

这里的原因是,Shadertoy中,左侧的这个窗口,并不是一个正方形,而我们之前做的Threejs的片元着色器,是一个正方形plane,这里各位可以尝试修改一下之前的案例,把plane的宽高改成不相等,来看看实际效果

shadertoy中的坐标系比例转换

shadertoy的窗口是 800 * 450
所以我们可以直接用 uv.x *= 800/450uv.y *= 450/800来让uv比例一致

在这里插入图片描述
虽然这样可以解决正圆的问题,但是我们却无法保证绘制的圆在中心了

我们需要一种更完美的方式,来重新计算uv

IQ大佬这里提供了一种算法

	vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.y;

在这里插入图片描述
这样我们绘制出来的圆就正常的放在了中心,大小上略有改变,但是整体影响不大,改成这样就可以与之前保持一致了

	vec2 uv = (fragCoord-iResolution.xy/2.0)/iResolution.y;

因为IQ大佬的算法,是将整个画面处理成u = -1 ~1,v = -1 ~1 这个数值区间,而我们之前的算法,uv-=0.5的数值区间为 -0.5 ~ 0.5,所以当扩大一倍时,自然最终显示的图像就会缩小一倍

理解Shadertoy的fragCoord

我们可以另开一个ShadertoyDemo来试一下fragCoord

在这里插入图片描述

我们让uv 直接使用fragCoord的值,并且修改sdCircle的半径,这时我们发现,我们依然可以绘制出我们想要的图像,但是半径要达到300才行,依此类推,我们在半径450时,理论上来说,圆的上面会顶到窗口顶部

在这里插入图片描述
可以看出,刚好顶部就是圆形的切线
也就是说,在Shadertoy中,fragCoord,其实可以理解为每个画布上像素点的坐标

理解Shadertoy中的iResolution

在新建的Shadertoy的demo中,官方给出了这样的计算uv的公式

	vec2 uv = fragCoord/iResolution.xy;

这样可以把整个Shadertoy的画布,变成咱们常规理解的uv的坐标系公式,就是从左到右,u的值从0变化到1,从下到上,v的值从0到1

基本上,通过上述公式推导,在shadertoy中,iResolution的xy值与fragCoord的xy值是相等的

这样我们再回头看IQ大佬的uv转换公式,

	vec2 uv = (2.0 *fragCoord-iResolution.xy)/iResolution.y;

我们带入IQ大佬计算出来的最终坐标系的uv坐标的[0,0]点反推像素点位置

0 = (2.0 * x - 800) / 450 => x = 400
0 = (2.0 * y - 450) / 450 => y = 225

刚好得到的像素点坐标,就在屏幕的正中心处

转移Shadertoy 2D效果到片元着色器

使用iResolution和fragCoord方法的转移,在上面X01动力装甲大佬的文章中已经写明白了,这里我们主要讲,基于uv的一种代码转移方式

我们以IQ大佬的圆形SDF的案例为准,本篇暂不讲解此案例,仅讲述如何搬运

第一步,我们先观察能否做搬运
在这里插入图片描述
本次讲解的搬运方法,搬运Shadertoy的前提是:这个效果必须是2D的

另一个前提是,尽可能的找到比较干净的,使用的内置变量比较少的,没有交互的,shadertoy中有很多内置变量,如上图,如果使用了大量的内置变量,则这种的基本上很难直接搬运,必须要熟悉其代码后才可搬运

如上图中的IQ大佬的代码,他加入了iMouse,就是鼠标点击上去后,会生成一个圆的效果
在这里插入图片描述
这里我们先删掉,在后面的阶段中会讲解关于iMouse如何搬运的问题

删掉这部分代码后,变量m变成了无用变量,则变量m也可以随之删除
在这里插入图片描述
这里的p,其实就是uv

接下来,我们拿一个Shader的模板代码
【模板代码】用于编写Threejs Demo的模板代码

并直接将这里的代码全部复制到片元着色器中(注释可要可不要)

处理mainImage和fragColor

这两处我们在之前就已经讲过了,只需要把mainImage和fragColor,以及uv改成Threejs的命名即可

	//旧代码
	varying vec2 vUv;
    float sdCircle( in vec2 p, in float r )
    {
        return length(p)-r;
    }


    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
        vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;

        float d = sdCircle(p,0.5);

        // coloring
        vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
        col *= 1.0 - exp(-6.0*abs(d));
        col *= 0.8 + 0.2*cos(150.0*d);
        col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );

        fragColor = vec4(col,1.0);
    }
	//新代码
	
    varying vec2 vUv;

    float sdCircle( in vec2 p, in float r )
    {
        return length(p)-r;
    }

    void main()
    {
        vec2 p = vUv;
        float d = sdCircle(p,0.5);
        // coloring
        vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
        col *= 1.0 - exp(-6.0*abs(d));
        col *= 0.8 + 0.2*cos(150.0*d);
        col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );

        gl_FragColor = vec4(col,1.0);
    }

Threejs中的最终效果

在这里插入图片描述
因为我们对uv的处理不同,所以这里我们也需要把uv挪动一下,挪动到我们需要的位置,直接p = vUv - 0.5即可

在这里插入图片描述
后面这个demo的效果各位可以改改参数玩一玩,
各位也可以自行尝试着去改一些Shadertoy效果到Threejs中

全部源码

<!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;
    }

</script>
<script type="x-shader/x-fragment" id="fragmentShader">

    varying vec2 vUv;

    float sdCircle( in vec2 p, in float r )
    {
        return length(p)-r;
    }

    void main()
    {
        vec2 p = vUv - 0.5;
        float d = sdCircle(p,0.5);
        // coloring
        vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
        col *= 1.0 - exp(-6.0*abs(d));
        col *= 0.8 + 0.2*cos(150.0*d);
        col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );

        gl_FragColor = vec4(col,1.0);
    }
</script>

<script type="module">

    import * as THREE from "../three/build/three.module.js";
    import {OrbitControls} from "../three/examples/jsm/controls/OrbitControls.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(10,10,10);
        scene.add(camera);

        orbit = new OrbitControls(camera,renderer.domElement);
        orbit.enableDamping = true;

        scene.add(new THREE.GridHelper(10,10));
    }

    let uniforms = {
        iTime:{value:0}
    }

    function addMesh() {
        let geometry = new THREE.PlaneGeometry(10,10);
        let material = new THREE.ShaderMaterial({
            uniforms,
            vertexShader:document.getElementById('vertexShader').textContent,
            fragmentShader:document.getElementById('fragmentShader').textContent,
        })
        let mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);
    }


    function render() {
        renderer.render(scene,camera);
        orbit.update();
        requestAnimationFrame(render);
    }

</script>
</body>
</html>

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

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

相关文章

SigmaStudio淡入淡出增益控件(Single SW slew vol(adjustable))延时分析

斜率范围1~23&#xff0c;参考12khz正弦波&#xff08;-17.99db,调减15.2db&#xff09;作为分析依据 一、淡入时间与斜率关系 斜率1-----淡入延时时间大概0.08毫秒 斜率2—淡入延时时间大概0.2毫秒 斜率3–淡入延时时间按大概0.5毫秒 斜率4–淡入延时时间大概1毫秒 斜率5–淡…

C++学习笔记之结构体

C学习笔记之结构体 https://www.runoob.com/cplusplus/cpp-struct.html 结构体是C中一种由用户自定义的数据类型&#xff0c;允许存储不同类型的数据项 1、定义结构体 使用struct语句定义结构体 结构体与C中的类看起来结构相似&#xff0c;同样是可以在其中定义成员变量和成员…

picgo + typora + gitee图床

Picgo打造个人图床&#xff0c;稳定又安全 解决Typora笔记上传到CSDN图片无法显示的问题 typora中

完全二叉树的节点个数 C++ 简单问题

完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层&#xff0c;则该层包含 1~ 2h 个节点。 示例 1&#xff…

蓝桥杯—STM32G431RBT6(RTC时钟获取时间和日期)

一、RTC是什么&#xff0c;有什么用&#xff1f; 在 STM32 中&#xff0c;RTC&#xff08;Real-Time Clock&#xff0c;实时时钟&#xff09;主要有以下作用&#xff1a; 时间保持&#xff1a;即使在系统断电情况下&#xff0c;也能持续记录时间。&#xff08;需要纽扣电池供电…

解决银河麒麟V10密码过期无法登录的问题

解决银河麒麟V10密码过期无法登录的问题 1、问题描述2、 解决方法步骤一&#xff1a;更改密码步骤二&#xff1a;调整密码策略&#xff08;可选&#xff09; 3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在使用银河麒麟桌面操作系…

Java:选择排序

目录 直接选择排序 堆排序 基本思想&#xff1a; 每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完。 直接选择排序 思路1&#xff1a; 在元素集合array[i]--array[n-1]中选择关键码最大(小…

【论文阅读】视觉里程计攻击

Adversary is on the Road: Attacks on Visual SLAM using Unnoticeable Adversarial Patch 一、视觉SLAM的不安全因素 根据论文的分析&#xff0c;视觉SLAM由于完全依赖于特征&#xff0c;缺少验证机制导致算法不安全。前端在受到干扰的情况下&#xff0c;会导致误匹配增加&…

算法工程师重生之第十八天(修剪二叉搜索树 将有序数组转换为二叉搜索树 把二叉搜索树转换为累加树 总结篇 )

参考文献 代码随想录 一、修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除…

【Sentinel-2简介】

Sentinel-2简介 Sentinel-2是欧洲空间局&#xff08;European Space Agency, ESA&#xff09;全球环境和安全监视&#xff08;即哥白尼计划&#xff09;系列卫星的重要组成部分&#xff0c;由Sentinel-2A和Sentinel-2B两颗卫星组成。以下是关于Sentinel-2的详细介绍&#xff1…

信息安全工程师(27)环境安全分析与防护

前言 环境安全分析与防护是一个综合性的议题&#xff0c;涉及多个方面&#xff0c;包括环境安全的概念、分析方法、存在的安全隐患以及相应的防护措施。 一、环境安全的概念 环境安全是指人类赖以生存发展的环境&#xff0c;处于一种不受污染和破坏的安全状态&#xff0c;或者说…

828华为云征文 | 华为云X实例CPU性能测试详解与优化策略

目录 引言 1. 测试环境搭建 1.1 测试实例的选择 1.2 CPU性能测试工具介绍 1.3 安装和配置Sysbench 2. CPU性能测试方法 2.1 测试场景设定 2.2 Sysbench单线程CPU性能测试 2.3 Sysbench多线程CPU性能测试&#xff08;4线程&#xff09; 2.4 高强度多线程CPU性能测试&a…

【QT 开发日志】QT 基础控件详解:按钮、文本框与标签的使用

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 博主简介 博主致力于嵌入式、Python、人工智能、C/C领域和各种前沿技术的优质博客分享&#xff0c;用最优质的内容带来最舒适的…

努比亚 Z17 NX563J Root 教程三方REC刷写工具教程

教程&#xff1a;1&#xff0c;自用成功 正常链接列表 adb devices 检查fastboot链接列表 fastboot devices 解锁设备fastboot oem nubia_unlock NUBIA_NX563J 我用的解锁设备是&#xff1a;fastboot flashing unlock 1.打开开发者选项。将OEM解锁的按钮打开 2.下载附件努…

【刷点笔试面试题试试水】不使用任何中间变量如何将a、b的值进行交换?

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> using namespace std;void swap1(int&am…

Cpp::STL—string类的使用与理解(下)(9)

文章目录 前言一、string类对象的修改operator (重点)assigninserterasereplacec_str 二、string类对象的查找findrfindsubstr 三、string类非成员函数operatorrelational operatorgetline 四、VS和g下string结构说明vs下string的结构g下string结构 总结 前言 我认为要想详尽认…

Json 在线可视化工具,分享几个

文章目录 1.json.cn2.json4u.cn3.jsonvisual.com4.jsoncrack5.altearius.github.io6.json.wanvb.com 前序&#xff1a;本文是对多种 Json 在线可视化工具 的介绍、分享。Json官网 https://www.json.org/json-en.html 个人比较中意第四款&#xff1a; https://jsoncrack.com/ed…

数据仓库简介(一)

数据仓库概述 1. 什么是数据仓库&#xff1f; 数据仓库&#xff08;Data Warehouse&#xff0c;简称 DW&#xff09;是由 Bill Inmon 于 1990 年提出的一种用于数据分析和挖掘的系统。它的主要目标是通过分析和挖掘数据&#xff0c;为不同层级的决策提供支持&#xff0c;构成…

Vector不清晰点学习易错点

什么是迭代器 是一个广义指针它可以是指针&#xff0c;也可以是一个可对其执行类似指针得操作-如解除引用&#xff08;如operator*()&#xff09;和递增&#xff08;operator()&#xff09;STL中每个容器类都定义了一个合适的迭代器&#xff0c;该迭代器的类型是一个名为itera…

解决iPhone无法有效响应问题的指南

当您触摸、滑动和点击屏幕时&#xff0c;iPhone 没有响应或屏幕冻结是很烦人的。不可否认&#xff0c;iPhone 是最好的智能手机之一&#xff0c;但它并不完美。触摸屏冻结是 iPhone 用户面临的最常见问题之一。 好消息是&#xff0c;这个问题通常是由软件错误而不是硬件损坏引…