7️⃣threejs学习笔记(七)
2026-3-12
| 2026-3-17
字数 10427阅读时长 27 分钟
type
Post
status
Published
date
Mar 12, 2026
slug
summary
提高渲染真实性 着色器
tags
Three.js
category
技术学习笔记
icon
password

提高渲染真实性

色调映射Tone Mapping

色调映射,直接作用于
渲染器,意在将低画质的贴图效果模拟成高画质贴图效果,官方文档的描述如下:
在这里插入图片描述
通常来说,如果我们使用HDR材质的环境贴图,会导致加载慢等问题,但是使用 LDR(Low Dynamic Range) 的贴图(比如使用 jpg 格式柱状全景图),又会觉得其效果不够好,所以 threejs 贴心的准备了这一选项
默认情况下, webGL 渲染器的色调映射模式为 NoToneMapping ,通过 gui 来控制每一种 toneMapping 的值方便我们测试其效果:
在这里插入图片描述
在这里插入图片描述
经过测试大致可以得到以下结论:
  • THREE.NoToneMapping
描述:禁用色调映射。 特点:直接输出场景的颜色值,不进行任何调整或压缩。 应用场景:适用于不需要HDR效果的情况。
  • THREE.LinearToneMapping
描述:线性色调映射。 特点:简单地将颜色值从线性空间转换到sRGB空间。 应用场景:基础的色彩管理,适合于不需要复杂HDR处理的场合。
  • THREE.ReinhardToneMapping
描述:基于Reinhard的色调映射算法。 特点:能够有效地处理非常亮的区域,同时保持暗部细节。 应用场景:广泛应用于游戏和CGI中,因为它能够很好地平衡亮度和对比度。
  • THREE.CineonToneMapping
描述:模仿电影胶片的效果。 特点:提供了更柔和的过渡效果,适合追求电影感的画面。 应用场景:电影制作和高端视觉特效项目。
  • THREE.ACESFilmicToneMapping
描述:基于Academy Color Encoding System (ACES) 的色调映射。 特点:模拟了现代数字电影摄影机的响应曲线,提供了非常自然的视觉效果。 应用场景:专业级视频制作和要求极高的图形应用。
  • THREE.AgXToneMapping
描述:一种模拟胶片感光特性的算法。 特点:提供了类似于传统黑白胶片的效果。 应用场景:艺术创作和特定风格化的项目。 THREE.NeutralToneMapping
描述:中性色调映射。 特点:尽量保持颜色的真实性,减少过度处理带来的失真。 应用场景:需要真实色彩再现的应用。
  • THREE.CustomToneMapping
描述:自定义色调映射。 特点:允许开发者实现自己的色调映射逻辑。 应用场景:当上述预设不能满足特定需求时,可以使用此选项来实现个性化的色调处理。
此外,我们还可以使用 toneMappingExposure 来控制色调的曝光程度,画面的体现上来看就是对于亮度的调节而已

抗锯齿(Anti-Aliasing)

首先要明白为什么会有锯齿
,计算机的渲染是按像素进行的,像素的最小单位就是1x1的矩形,假如要渲染一个非矩形的形状,计算机就可能会因为计算有误导致某个像素没有出来,进而形成阶梯状的边缘,比如:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以,为了提高画质,避免这些边缘的阶梯状效果,就需要抗锯齿技术来对画面进行优化

SSAA

超采样抗锯齿,全名为 Super-Sampling-Anti-Aliasing ,它的原理简单粗暴,就是将原本要渲染的分辨率放大一倍,渲染后再进行缩放;比如要将场景渲染到1920 * 1080的画面上,开启抗锯齿后就是先将场景渲染到3840 * 2160的画面上后再缩放至1920 * 1080,这样子的抗锯齿效果显著,但是性能开销显然就非常大了
2X SSAA,就代表渲染到2倍于原始分辨率的场景,每一个像素相当于放大了 2 x 2 = 4倍,渲染的像素总数就是原来的4倍
4X SSAA,则代表每个像素变为原来的 4 * 4 = 16倍,渲染的像素总数就是原来的16倍
优点:
  • 提供高质量的抗锯齿效果。
  • 能够消除几乎所有的锯齿现象。
缺点:
  • 计算成本非常高,渲染时间显著增加。
  • 不适用于性能要求较高的场景。

MSAA

Multi-Sample Anti-Aliasing ,多重采样抗锯齿,原理是在每个像素周围进行多次采样来减少锯齿现象,实现上相对简单,但是因为只在像素中心附近进行采样,所以无法完全消除所有锯齿
在这里插入图片描述
在这里插入图片描述
引用自 https://zhuanlan.zhihu.com/p/133511752
如图,红框框起的绿色像素就是MSAA会额外处理的像素部分
在这里插入图片描述
优点:
  • 相对简单且易于实现。
  • 对于线性和边缘锯齿效果较好。
缺点:
  • 对于点状和纹理锯齿效果较差。
  • 只能在像素中心附近进行采样,无法完全消除所有锯齿。

FXAA

自适应抗锯齿 Fast Approximate Anti-Aliasing ,一种后处理技术,原理是通过检测边缘并对其进行模糊处理来减少锯齿,它不需要额外的采样,而是在最终图像上进行处理。
优点:
  • 实现简单且计算成本低。
  • 对于大多数情况下的抗锯齿效果较好。
缺点:
  • 效果不如 MSAA 和 SSAA 高质量。
  • 可能会出现轻微的模糊效果。

阴影投射

添加阴影也是让渲染更真实的一种方案,但是之前说的环境贴图是无法投射阴影的,要实现阴影需要额外的外部光源,下面尝试给这个场景添加阴影:
在这里插入图片描述
首先,要通过给渲染器设置 shadowMap.enabled 来开启场景中的阴影效果:
的性价比较高,设置阴影时可以优先考虑
在这里插入图片描述
然后,需要对场景中能投射阴影的物体和接收阴影的物体进行设置,对于当前场景而言,接收和投射阴影的物体都是导入的模型,模型经过 threejsloader 解析后会转成 threejs 中内置的 Object3D L类,所以可以通过 traverse 快速遍历整个模型的场景,给场景里的所有组成模型的物体设置阴影:
接着,往场景中添加一个平行光源,并为其添加辅助器 helpergui 控制面板,方便我们调整光的投射位置、强度等属性
现在的效果:
在这里插入图片描述
现在场景中添加了两个 helperDirectionalLightHelper 用于标识平行光的位置(目前它被模型挡住了), THREE.CameraHelper 用于标识阴影投射的方向
现在移动灯光的位置,就可以看到灯光的照射方向以及阴影的投射方向了:
在这里插入图片描述
在这里插入图片描述
默认情况下
是从上往下照射的,如果要修改光照的方向,按照官方文档中的说法,就得这么操作:
在这里插入图片描述
下面是修改了灯光投射的方向后的结果
在这里插入图片描述
这里只是演示,进行下一步之前请先把修改灯光位置的代码删掉
阴影的投射也要考虑性能,通常其出发点有两个,一个是修改阴影投射摄影机的远距,使其恰好涵盖物体本身即可;一个是修改投射出的阴影质量
在这里插入图片描述
在这里插入图片描述
512 * 512 的分辨率下,阴影边缘会比较模糊,把解析度改为 4096 ,效果会好很多:
在这里插入图片描述
在这里插入图片描述
最后,根据环境贴图的样子,我们需要把光调整到一个正确的位置,毕竟总不能出现“太阳在左上角,光从左下角打过来”的情况吧
比如在当前场景中,光是从天上打下来的,大概设置光的位置为
在这里插入图片描述
在这里插入图片描述
当然,过高的解析度也意味着更大的性能开销,在不同的场景下需要有不同的取舍(通常低解析度的阴影也够用了,因为用户通常不会刻意去观察这些细节)

伪影

Shadow Acne ,伪影是一种在计算机图形学中常见的渲染问题,特别是在使用阴影贴图(shadowmapping)技术时。
原因:光源和物体表面之间的采样不精确导致。
导入项目中的另一个汉堡包模型,同时调整模型的缩放比例使其符合画面缩放程度:
乍一看似乎没什么问题:
在这里插入图片描述
但是放大看,会发现其表面出现了一些不对劲的噪点和波纹
在这里插入图片描述
当把场景亮度调低后,这些问题就更明显了:
notion image
大致的原理就是模型本身既能接收阴影,又能投射阴影,所以它的表面也会有覆盖上自己产生的阴影,因此影响了其表面的形状,产生波纹和噪点,别忘了GPU是按照像素去渲染的:
在这里插入图片描述
要解决这个问题,
提供了一个最简单的办法,设置
的阴影贴图偏差属性
在这里插入图片描述
现在再看,波纹效果明显减少了很多,但多少还存在一些
在这里插入图片描述
并且还导致了一个新的问题,芝士的阴影也没了:
在这里插入图片描述
这是因为我们给阴影贴图移动了错误的方向,应该把
设置为
,设置成
,芝士的阴影就回来了
在这里插入图片描述
就接下来继续解决剩下的可见的“波纹”,除了 bias 外,还有另一个 normalBias 属性可以配合一起调整, normalBias 参数用于定义查询阴影贴图的位置沿物体法线方向的偏移量。增加这个值可以减少 shadow acne ,尤其是在光线以较小角度照射到几何体上的大场景中
使用 gui 控制 directionalLightnormalBias 属性,直到找到一个合适的值即可:
设置到0.007就差不多了:
在这里插入图片描述
另外可以看到模型的边缘有锯齿,这就要通过之前所说的抗锯齿来解决了, threejs 里直接通过给 renderer 开启抗锯齿即可:
抗锯齿ON:
在这里插入图片描述
抗锯齿OFF:
在这里插入图片描述

纹理

一个获取纹理的网址: https://polyhaven.com ,不过需要注册 patreon 和付费才能下载,但是纹理的质量确实高,而且格式选择上足够丰富

视觉疲劳问题

长时间专注于渲染一个场景过久必然会出现视觉疲劳的问题,也许会影响你对于空间中物体的位置、颜色渲染的判断,此时最好是切换场景,去看一下看其他的有色物体来调整自己的视觉,之后再回来调整可能会发现自己原本调色不合理的地方

着色器

Web3D 的范畴内来说,着色器是一种程序,由 WebGL 运行,需要使用 GLSL 语言去编写;
threeJs 中,我们编写好着色器程序之后, threeJs 将其传给 WebGL 解析, WebGL 将他解析成二进制代码给 GPU 进行计算,最后GPU就可以将图像等渲染出来
所以,着色器是用来”绘制“(实际上是记录,然后交给GPU去绘制)几何体顶点的位置和每个像素的颜色
ThreeJs 着色器的代码中,我们可以向其发送如以下信息:
  • 顶点位置
  • 几何体的变换信息(旋转、缩放等)
  • 摄像机的信息
  • 颜色、纹理、灯光、雾等
WebGL 的范畴内,主要使用的是顶点着色器( Vertex Shaders )和片段着色器( Fragment Shaders

顶点着色器

通过 GLSL 语言,我们可以用顶点位置( position )、几何体的变换( geometry transformation )、摄像机等数据创建出 顶点着色器程序 ,最终GPU运行这个顶点着色器,将这些东西渲染出来:
在这里插入图片描述
在这里插入图片描述
threejs 里, Data 阶段就是我们通过创建 THREE.Geometry 获取到的几何体的坐标、uv等数据,他们会以 attributeuniforms 的形式传到 顶点着色器
这个意思是在GLSL语言中,把几何体的坐标等属性用 attributeuniforms 等关键字来表示和获取,下文的 glsl 语法讲解会说到
总结来说就是:顶点着色器用于处理3D模型中的每个“顶点”,可以改变顶点的位置、颜色、纹理坐标等属性。
将顶点着色器交给GPU运行后,GPU就知道了当前的几何体有哪些顶点、线、面是在画布上”可见的“,然后就可以进行下一个阶段——使用 片段着色器 上色了

片段着色器

Fragment Shaders ,也称为像素着色器,负责计算屏幕上每个像素的颜色值,针对的是一块区域内的上色(毕竟画布是一个一个小方块组成的,最小片段应该是 1px * 1px
顶点着色器的
无法传给片段着色器,只能传
,但是可以通过
关键字将attribute数据传给片段着色器,如图:
在这里插入图片描述
片段着色器通过 uniformsvarying 获取到顶点相关的数据后,将他们进行混合(或者不混合,混合是为了实现渐变等效果);然后我们在片段着色器中声明片段的颜色,此时我们就得到了一个可用的片段着色器了
将片段着色器、顶点着色器交给 WebGL 编译成二进制代码传给GPU,我们的几何体就被渲染出来了
vite-plugin-glsl https://www.npmjs.com/package/vite-plugin-glsl
npm install glslify webpack-glsl-loader --save-dev

编写着色器代码

搭建基本场景

首先搭建一个 demo 环境,在页面中画出一个平面几何体
在这里插入图片描述
在这里插入图片描述

替换材质

threejs 里有两个着色器材质: ShaderMaterialRawShaderMaterial ,两者的区别仅在于 ShaderMaterial 会自动地将一些内置的 attributesuniforms 添加到着色器程序顶部
将代码里的材质替换为 RawShaderMaterial ,然后从头编写着色器代码:
至此,页面上就渲染出了一个红色的平面几何体:
在这里插入图片描述
在这里插入图片描述

配置开发环境

material 里写模板字符串对于我们开发效率和质量都有比较大的影响,不利于我们的开发,所以我们需要类似JS、TS的代码颜色支持
VSCode就有这样的插件,名为
在这里插入图片描述
着色器的代码是用 glsl 语言编写的,现在分别为顶点着色器和片段着色器创建两个单独的文件,并把着色器代码丢到里面,可以看到语法就有正常的高亮了:
在这里插入图片描述
在这里插入图片描述
这里着色器的文件后缀可以是
也可以是
等,如下表:
在这里插入图片描述
主要是 glsl lint 无法对 .glsl 后缀的文件生效,所以文件命名建议以 .vs.fs 命名
除了高亮外,我们还要安装代码格式化和代码检查的插件,来确保代码准确性,所以安装插件
,与
在这里插入图片描述
然后来这里:
,下载
程序:
在这里插入图片描述
找个位置解压后,打开
设置,搜索
定位到bin目录下的
程序即可:
在这里插入图片描述
重启 vscode ,以后我们就有了代码自动格式化( glsl-canvas )、代码语法检查( glsl-lint )以及着色器效果预览( glsl-canvas )了
最后,语法提示的配置,去这个地址:
,把第一篇
代码全部复制下来:
在这里插入图片描述
打开
在这里插入图片描述
搜索 glsl.json ,然后代码复制进去,重启 vscode 即可

glsl文件引入

按照目前的配置,直接引入是不行的,需要对应的文件解析器来解析对应的文件
vite 环境中,需要使用 vite-plugin-glsl ,先安装该插件: npm install vite-plugin-glsl ,然后编辑 vite.config.js
然后我们就可以引入 shader 文件了:
如果是 webpack 环境,需要使用 raw-loader 将着色器代码文件当作 string 引入使用,比如在 umi 项目中要这样配置:
正常的 webpack 环境则直接配置即可:

glsl语言

GLSL: OpenGL Shading Language ,这是一种类型语言,每个变量、表达式或值都有一个明确的数据类型,并且这些类型在编译或运行时会被严格检查的语言,主要有以下特点:
  1. 无法打印,因为代码是由GPU去运行的;比如对于顶点着色器的代码而言,代码定义了每个顶点的位置计算方法,一个几何体有N个顶点需要渲染,那么GPU就会对应运行N次代码来计算出每个顶点的位置
  1. 每一行结尾必须加分号
  1. intfloat 有严格的区分:如 int a = 1; float b = 0.002 ,不能混合运算
  1. 不能缺少 main 函数实现,主入口必定是 main 函数
  1. 运算的顺序是从右往左进行的(下文会有案例演示)
  1. 这个语言没有所谓的官方文档,但有一些民间总结而来的指引网站: https://thebookofshaders.com/https://shaderific.com/glsl/common_functions.html
  1. 另外一个好用的学习openGL的英文网站: https://learnopengl.com/

float类型

即浮点数,和C语言中的 float 类似,可以进行数学运算,但必须加小数点,不能和整形数进行运算

int类型

即整形数据,和C语言中的 int 类似,声明时必须为整数, intfloat 不能混用,如:

vec2

二维向量,由 x,y 组成,可以类比为threejs里的 Vector2 ,一些要点如下:

vec3

三维向量,在x、y的基础上多一个z,类似 threejsVector3 ,与 vec2 的操作类似:
除了可以使用x、y、z,还可以使用r、g、b获取值,这个对于创建一个 rgb 的颜色比较方便
另外,可以快捷通过 vec2 创建一个 vec3

vec4

可以理解为四维向量,多出来的你那个记为 w ,也可以通过 a 访问:
所以 vec4 通常会用来声明 rgba 颜色(带alpha通道即”透明度”的颜色) 与 vec3vec2 类似, vec4 也可以进行类似的一些运算,这里就不做赘述
此外,向量存在一种运算成为 swizzle 操作,它是一种对向量的分量进行操作的运算,支持混合分量与重复分量:

function

即函数,类似于c语言里的函数声明:
当然,也可以进行函数传参等操作:
同时,其内置了很多数学函数如 powmaxmin 等,均与 Math.powMath.max 的作用一致,这里不做赘述

从GLSL代码视角理解顶点着色器

  1. uniformglsl 语言中的关键字,用于定义一个外部传入的不可变的变量,类似于 const 声明
  1. mat4 代表一个4x4的矩阵类型
  1. projectionMatrix 代表”投影矩阵“,用于将场景从相机视图转换到标准化设备坐标系中
  1. viewMatrix 代表”视图矩阵“,用于将场景从像世界坐标系转换到相机坐标系
  1. modelMatrix 代表”模型矩阵“,用于将物体从局部坐标系转换到世界坐标系
  1. attribute 也是 glsl 里的关键字,用于定义一个”属性“,每个顶点调用时 position 的值会自动设置为顶点的位置(以顶点的局部坐标系为准)
  1. gl_Positionglsl 语言里的一个特殊内置变量,用于存储顶点着色器计算后的顶点位置,这个位置会在光栅化阶段(被片段着色器)生成片段,并最终绘制
注意,projectionMatrix、viewMatrix、modelMatrix是 threeJs 内部声明的变量,而不是 glsl 本身定义的变量,在其他3D引擎中名称不一定是这些(比如在Unity引擎中,投影矩阵命名为 UNITY_MATRIX_P
所以整个顶点着色器的代码执行流程如下:
首先我们在 threejs 中创建 GeometryShaderMaterial ,使用这两个要素生成 Mesh
渲染开始前, 投影矩阵视图矩阵模型矩阵 的值已经由 threejs 内部计算完成并以 uniform mat4 xxxMatrix 变量的形式注入完成
矩阵的计算是由threejs通过我们设置的旋转、缩放、位移计算得来的,至于计算公式就请自行查看源码了,这个并不重要
然后渲染开始, webGL 根据几何体的顶点数量,告诉GPU顶点着色器代码需要执行多少次, position 的值等于 threejs 注入的每个几何体的顶点坐标
注意,在 glsl 中,计算是从右往左进行的,也就是说,计算最后的顶点位置时需要:
  1. 首先将顶点的三维坐标转为四维向量,其中第四个分量为1,代表这是一个位置向量
  1. 进行模型矩阵变换,计算 modelMatrix * vec4 ,将局部坐标系的顶点坐标转换到世界坐标系的顶点坐标。
  1. 进行视图矩阵变换,计算 viewMatrix * vec4(上一步计算得来) ,将世界坐标系的顶点坐标转换为相机坐标系的顶点坐标
  1. 进行投影矩阵变换,计算 projectionMatrix * vec4(上一步计算得来) ,将相机坐标系的顶点坐标转换到标准化设备坐标系的顶点坐标
所以实际上代码可以按照执行顺序改写成:
然后 gl_Position 就会被传到片段着色器中进行下一步的上色计算
各种坐标系的讲解可以参考如下文章: 局部坐标系与全局坐标系相机坐标系标准化设备坐标系(NDC) 其实你不需要知道是怎么变换的,你只需要知道其中经历了这些个变换就好

从GLSL代码视角理解片段着色器

片段着色器相对比较简单, gl_FragColorgl_Position 一样,是内置的变量,设置的是每个片段(像素)的颜色, vec4(1.,0,0,1.) 就代表纯红色,不透明
precision 用于声明浮点数的精度,不同的硬件(显卡)对浮点数的处理能力不同,支持的设置有三种:
  • precision lowp float
    • 范围:[-2, 2] 精度:至少10位有效数字 通常用于颜色和纹理坐标,适用于大多数移动设备。
  • precision mediump float
    • 范围:[-2^14, 2^14] 精度:至少16位有效数字 适用于大多数颜色和纹理坐标计算,以及一些简单的数学运算。
  • precision highp float
    • 范围:[-2^62, 2^62] 精度:至少23位有效数字 适用于复杂的数学运算和需要高精度的场景,但可能会降低性能。
lowp 通常用于移动端设备,可以有效地优化移动端的运行性能 mediump 则适用于绝大多数桌面和高端移动设备 highp 则适用于需要复杂的数学运算和高精度的场景,比如物理模拟、高级光照计算的场景
对于大多数WebGL应用, mediump 是一个不错的选择,因为它在性能和精度之间取得了良好的平衡,优化性能时才考虑使用 lowp

在GLSL里操纵几何体的变换

几何体的位置、形状等可以通过顶点着色器来修改,比如之前在顶点着色器里这样子分开每一步来写了:

移动几何体

通过”模型矩阵”计算出来的 modelPosition 是顶点在世界坐标系中的坐标,即此时可以通过修改 modelPosition 的值来移动物体,比如:
就可以把物体往脸上移动0.5个距离:
在这里插入图片描述
要记得:每个顶点都会执行一次着色器代码的计算

创建波浪效果

波浪效果用三角函数可以很轻易地实现,比如对每个顶点的x坐标取正弦值赋给z坐标:(需要增大振幅效果才明显)
就可以得到:
在这里插入图片描述
但是目前因为振幅太大导致点过于靠近,可以通过在外层缩小整体的值来让画面变缓:
在这里插入图片描述
在这里插入图片描述
在glsl里, .0 可以缩写为 .

随机数控制

曾经我们有个操作是自己创建一个 BufferGeometry 并且自定义顶点坐标绘制图形,当时是通过下面的代码实现的:
geometry 里的 attributes 属性都会被 threejs 注入到着色器中,并且以同名变量的方式声明,我们可以打印 geometry.atrributes 查看里面的属性:
在这里插入图片描述
在这里插入图片描述
看到上面的图, BufferAttribute 里有 count 属性,代表顶点的个数,即当前平面几何体的顶点个数是 1089 个,这就意味着顶点着色器代码至少会执行 1089 次;在顶点着色器中,就可以通过 attribute 来访问这些同名的变量,比如:
positionvec3 的形式创建,意味着顶点着色器计算时会自动去 position.array 中3个3个地取值作为顶点的坐标进行计算;对于 uv、normal 也是同理
假设我们需要传一个自定义的值,那么就可以这样写:
我们创建了一个长度为顶点个数的数组,数组值用随机数填充,规定
里取值的步长为1,打印
可以看到我们自己创建的变量
在这里插入图片描述
在顶点着色器中就需要通过 float 进行取值,而不是vec2或vec3,这取决于 attribute 的步长
这样会得到下面的结果,有点”恐怖“
在这里插入图片描述
别忘了我们可以通过比例来控制振幅:
这样就得到还行的效果:
在这里插入图片描述

顶点着色器与片段着色器通信

threejs 的两个着色器间进行数据传递有且仅有一种办法,那就是通过 varying 关键字实现
比如我们可以把上一步的 random 值传到片段着色器中控制颜色:
然后我们就得到了这样的效果:
在这里插入图片描述

threejs与顶点着色器通信

threejs 中, ShaderMaterialRawShaderMaterial 可以通过 unifroms 属性向顶点着色器传参,比如我们可以通过 threejs 来控制平面的波浪效果振幅:
这样我们就可以在 threejs 修改对应的参数来进行调试或构造动画了;另外可以看到 threeJs 中给 uFrequency 设置的值是20,对于着色器而言是整型,但是却可以用 float 接收,因为 threejs 会根据需要进行对应数据的转换
除了传单一的值,还可以传 THREE.Vector2 ,比如同时控制 x、y 方向的振幅就可以这样子写:
在这里插入图片描述
在这里插入图片描述

threejs与片段着色器通信

uniform 创建的变量是可以同时在片段着色器、顶点着色器中通信的,所以也可以通过 uniforms 变量来控制平面的颜色,比如:
这里可以直接传 THREE.Color ,他在着色器中的数据是 vec3 的形式,所以除了用 vec3 直接生成 vec4 ,也可以访问 uColor.ruColor.guColor.b 来设置颜色,这里就不赘述了

着色器加载纹理

比如我们要给平面加上国旗的纹理:
在这里插入图片描述
那么同样的,也是通过 uniforms 将纹理传入到着色器中:
在片段着色器中要使用 sample2D 这个数据类型来获取 texture ,并使用 texture2D 函数来将纹理转换成对应的 vec4 颜色:
sampler2Dglsl 内置的数据类型,主要用于表示2D纹理,他会在着色器中访问纹理的数据,如纹理的引用、采样状态等
texture2Dglsl 内置的函数,用于从2D纹理中采样颜色值,接收一个 sampler2D一个 二维纹理坐标作为参数,最后返回对应坐标的颜色值 vec4
这里的 vUV 来自于顶点着色器,交互的关键代码如下:
虽然
不能在片段着色器中读取,但是可以通过
将其传到片段着色器里,而
对应的就是几何体的
坐标,它会被
自动当成
注入,所以可以直接通过
来读取
在这里插入图片描述
最后,就成功地将颜色换成了国旗纹理图:
在这里插入图片描述
在这里插入图片描述

控制动画

threeJs 的逐帧渲染中,可以通过内置的 Clock 获取 从第一帧运行开始到当前帧经过了多少秒 ,如:
在这里插入图片描述
在这里插入图片描述
所以,如果把这个值传到顶点着色器中,基本的动画就可以实现了;
创建一个 uniforms 变量,在每一帧的渲染函数中更新它:
在顶点着色器中用同名变量获取值,控制z方向的形变:
基本的波浪动画就有了:
在这里插入图片描述
在这里插入图片描述

总结

  1. 顶点着色器的作用是将“顶点坐标”从“局部坐标系”转换到“标准化设备坐标系”来让GPU实现渲染
  1. threejsglsl 的数据交互通过 uniformsattributevarying 关键字来完成, uniform 可以同时被两个着色器读取, attribute 只能在顶点着色器中读取,然后通过 varying 传入片段着色器
  1. ShaderMaterialRawShaderMateral 的区别在于后者需要你自己手动声明 projectionMatrixmodelMatrix 等变量,所以使用后者通常可以节省一定的性能开销(因为不用初始化过多的无用变量)
    1. 在这里插入图片描述
  1. 不要使用 Date.now() 来触发 shaders 的变化计算,因为它的值对于 shader 来说太大了
最后附上一个 shaders 实现案例的社区: https://www.shadertoy.com/

补充

理解 modelMatrix

modelMatrixthreeJs 内置的变换矩阵,它在默认情况下是 单位矩阵
我们在顶点着色器里,需要先经过模型矩阵变换:
对于任一矩阵变换的计算公式是:
所以,假如 position 的值为 (1, 0, 1) ,那么计算出来的 modelPosition 就仍然是 (1,0,1)
当我们在 threejs 里通过 mesh.rotateX()mesh.position.x = 1mesh.scale.y = 2 等操作修改了物体后,在GPU的渲染阶段, threejs 会自动计算出由 缩放矩阵平移矩阵旋转矩阵 相乘得到的 模型矩阵 ,以此来计算出每个顶点实际的位置
 
 
 
threejs学习笔记(七)
  • Three.js
  • threejs学习笔记(六)threejs学习笔记(八)
    Loading...