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

【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 screenfragColor = 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);// coloringvec3 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);// coloringvec3 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);// coloringvec3 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.rhkb.cn/news/434059.html

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

相关文章

【YOLO目标检测输电线路异物数据集】共4516张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;4516 标注数量(txt文件个数)&#xff1a;4516 标注类别数&#xff1a;4 标注类别名称&#xff1a;nest、kite、balloon、trash 数据集下载&#xff1a;输电线路异物数据集 图片示例 数据集…

react 状态管理

Redux Redux是React中常用的状态管理组件&#xff0c;类似于Vue中的Pinia(Vuex)&#xff0c;可以独立于框架运行 作用&#xff1a; 通过集中管理的方式管理应用的状态 配套工具 在react中使用redux&#xff0c;官方要求按照两个插件&#xff0c;Redux Toolkit 和 react-red…

c++(AVL树及其实现)

一、AVL树的概念 AVL树是最先发明的自平衡⼆叉查找树&#xff0c;AVL是⼀颗空树&#xff0c;或者具备下列性质的⼆叉搜索树&#xff1a;它的 左右子树都是AV树&#xff0c;且左右子树的高度差的绝对值不超过1。AVL树是⼀颗高度平衡搜索⼆叉树&#xff0c; 通过控制高度差去控…

星辰计划04-深入理解kafka的消息存储和索引设计

消息存储 提到存储不得不说消息的读写&#xff0c;那么kafka他是如何读写数据的呢&#xff1f; 读取消息 1.通过debug(如何debug) 我们可以得到下面的调用栈&#xff0c;最终通过FileRecords来读取保存的数据 写入消息 1.通过debug(如何debug) 我们可以得到下面的调用栈&am…

在LLMs模型中发现人类的记忆特征

论文地址&#xff1a;https://arxiv.org/abs/2311.03839 介绍 大型语言模型&#xff08;LLM&#xff09;&#xff0c;如 ChatGPT&#xff0c;为语言建模和生成人类水平的文本输出带来了质的飞跃。 这些模型在庞大的文本库中进行训练&#xff0c;有效地建立了高度复杂和准确的…

标准 I/O

标准 I/O 引言 I/O 是一切实现的基础&#xff0c;其分为标准 I/O 和文件 I/O。 文件 I/O 依赖操作系统&#xff0c;因系统的实现方式而定&#xff0c;对于程序员来说会造成很大困扰。如打开文件&#xff0c;Linux 系统调用为 open() 函数&#xff0c;而 Windows 的系统调用为…

【锁住精华】MySQL锁机制全攻略:从行锁到表锁,共享锁到排他锁,悲观锁到乐观锁

MySQL有哪些锁 1、按照锁的粒度划分 行锁 是最低粒度的的锁&#xff0c;锁住指定行的数据&#xff0c;加锁的开销较大&#xff0c;加锁较慢&#xff0c;可能会出现死锁的情况&#xff0c;锁的竞争度会较低&#xff0c;并发度相对较高。但是如果where条件里的字段没有加索引&…

OpenCV 形态学相关函数详解及用法示例

OpenCV形态学相关的运算包含腐蚀(MORPH_ERODE)&#xff0c;膨胀(MORPH_DILATE)&#xff0c;开运算(MORPH_OPEN)&#xff0c;闭运算(MORPH_CLOSE)&#xff0c;梯度运算(MORPH_GRADIENT)&#xff0c;顶帽运算(MORPH_TOPHAT)&#xff0c;黑帽运算(MORPH_BLACKHAT)&#xff0c;击中…

AI产品经理:基于大模型Agent的客服实践,更低的成本与更大的收益

现在AI客服已经在各行业普遍使用了&#xff0c;但是实际效果并不如意——用户宁愿等人工客服&#xff0c;也不愿意找AI客服解决问题。如果给当前的AI客服换成大模型&#xff0c;效果会不会更好一些&#xff1f;这篇文章&#xff0c;我们来看看作者的思考。 一、为什么要用大模型…

Python 从入门到实战30(高级文件的操作)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了操作目录的相关知识。今天我们将学习一下高级文…

一文学会 Java 8 的Predicates

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 前言 在这份详细的指南中&#xff0c;您将了解 Java Predicates&#xff0c;这是 Java 8 中一个新颖且有用的特性。本文解释了 Java Predicates 是什么以及如何在各种情况下使用它们。 在这份详尽的指南中…

游戏开发2025年最新版——八股文面试题(unity,虚幻,cocos都适用)

1.静态合批与动态合批的原理是什么&#xff1f;有什么限制条件&#xff1f;为什么&#xff1f;对CPU和GPU产生的影响分别是什么&#xff1f; 原理&#xff1a;Unity运行时可以将一些物体进行合并&#xff0c;从而用一个描绘调用来渲染他们&#xff0c;就是一个drawcall批次。 限…

信安 实验1 用Wireshark分析典型TCP/IP体系中的协议

我发现了有些人喜欢静静看博客不聊天呐&#xff0c; 但是ta会点赞。 这样的人呢帅气低调有内涵&#xff0c; 美丽大方很优雅。 说的就是你&#xff0c; 不用再怀疑哦 实验1 用Wireshark分析典型TCP/IP体系中的协议 实验目的 通过Wireshark软件分析典型网络协议数据包&a…

javaweb 实验3

我发现了有些人喜欢静静看博客不聊天呐&#xff0c; 但是ta会点赞。 这样的人呢帅气低调有内涵&#xff0c; 美丽大方很优雅。 说的就是你&#xff0c; 不用再怀疑哦 实验三 Web基础-JavaScript 目的&#xff1a; 1、 理解和掌握Javascript基本语法 2、 掌握JavaScr…

html+css+js实现Pagination 分页

效果图 HTML部分 <body><div class"pagination"><button class"prev"><</button><ul><li class"active">1</li><li>2</li><li>3</li><li>4</li><li>5…

敏捷开发与DevOps的有机结合

在当今快速变化的技术环境中&#xff0c;软件开发团队面临着前所未有的挑战。客户需求不断变化&#xff0c;市场竞争激烈&#xff0c;技术更新速度加快&#xff0c;这些因素都要求开发团队具备高度的敏捷性和高效的运营能力。为了应对这些挑战&#xff0c;越来越多的企业选择将…

024.PL-SQL进阶—游标

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

JAVA红娘婚恋相亲交友系统源码全面解析

在数字化时代&#xff0c;红娘婚恋相亲交友系统成为了连接单身男女的重要桥梁。JAVA作为一种流行的编程语言&#xff0c;为开发这样的系统提供了强大的支持。编辑h17711347205以下是对JAVA红娘婚恋相亲交友系统源码的全面解析&#xff0c;以及三段示例代码的展示。 系统概述 …

【Gitee自动化测试4】本地Git分支的增删查,本地Git分支中文件的增删查,本地文件的暂存/提交,本地分支的推送

一、流程 本地创建分支&#xff0c;设定连接什么云分支本地创建文件&#xff0c;暂存、提交–>本地分支本地分支推送所有修改–>云仓库 二、分支概念 在版本回退里&#xff0c;每次提交&#xff0c;git都把它们串成一条时间线&#xff0c;这条时间线可以理解为是一个分…

Verilog基础:时序调度中的竞争(四)(描述时序逻辑时使用非阻塞赋值)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 作为一个硬件描述语言&#xff0c;Verilog HDL常常需要使用语句描述并行执行的电路&#xff0c;但其实在仿真器的底层&#xff0c;这些并行执行的语句是有先后顺序…