百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

Three.js着色器开发基础

connygpt 2024-11-18 10:42 12 浏览

着色器(Shader)是在 GPU 上运行的程序。它们被称为着色器的原因是,最初它们只处理3D对象的着色,但后来扩展到了3D对象之外。它们需要与传统编程不同的思维方式,因为程序是针对每个顶点或像素并行运行的。

WebGL和OpenGL使用一种名为 GLSL 的语言,它代表OpenGL 着色器语言,类似于 C 语言。在 Three.js 中添加着色器的最简单方法是使用ShaderMaterial。还有一些RawShaderMaterial,它没有包括一些three.js GLSL代码。

1、顶点着色器和片段着色器

在 WebGL 中有顶点(Vertex)着色器和片段(Fragment)着色器。在顶点着色器中,你可以操作几何图形的顶点,在片段着色器中,你可以操作渲染的三角形的像素。在实时图形中,一切都被简化为三角形。顶点着色器返回 2D 位置,因此它使用投影矩阵从 3D 投影到 2D。基本顶点着色器将如下所示:

void main() {
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

该函数必须命名为 main,并且你必须设置内置变量gl_Position 。projectionMatrix、modelViewMatrix和position由three.js提供。从右到左查看矩阵乘法。 modelViewMatrix是视图矩阵要相乘的模型矩阵。视图矩阵是相机的反变换 - 移动相机和反方向移动模型等效。模型矩阵是在模型上完成的转换。projectionMatrix 负责从3D到2D的投影。

基本片段着色器将如下所示:

void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

同样,该函数需要命名为main,并且需要设置内置变量gl_FragColor 。在上例中,我们将每个像素设置为红色。要创建着色器材料,请将顶点着色器和片段着色器指定为字符串,否则three.js将使用默认着色器。

const vertexShader = /*glsl*/`
void main() {
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;

const fragmentShader = /*glsl*/`
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

const material = new ShaderMaterial({
  fragmentShader: fragmentShader,
  vertexShader: vertexShader
});

如果你在 VS Code 中安装了标记Comment tagged templates和 Shader language support插件,则在上面的代码中字符串前面的/*glsl*/注释会添加语法突出显示。使用模板文本,即反引号,可以在字符串中包含多行。你还可以在 HTML 文件的脚本标记中包含 GLSL:

<script id="fragment-shader" type="x-shader/x-fragment">
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
</script>

并访问脚本中的 DOM 元素:

const material = new ShaderMaterial({
  fragmentShader: document.getElementById('fragment-shader').textContent
});

或者,你可以将着色器保存在单独的文件中,并在使用 Webpack 或 Parcel 等打包工具时导入它们。对于Webpack,你需要安装raw loader,对于Parcel,你需要安装@parcel/transformer-glsl插件。

信息从顶点着色器传递到片段着色器,在片段着色器中,根据像素相对于顶点的位置对值进行插值。例如,如果为每个顶点指定一种颜色并将其向下传递到片段着色器,则像素颜色将从顶点颜色中插值。

2、着色器变量

着色器具有几种不同类型的变量:

  • Uniforms:这些在所有GPU线程中都是相同的,例如当前时间。你可以在ShaderMaterial中设置这些设置。
  • Varyings:这些因每个 GPU 线程而异。你可以使用它们将值从顶点着色器传递到片段着色器,例如UV(纹理映射坐标)。可以在顶点着色器中设置这些设置。
  • Attributes:这是加载到顶点着色器中的数据,例如顶点的位置。three.js通常会处理这些内容,除非我们要添加自定义属性或想要手动指定顶点。可以在几何图形上设置这些值。

3、GLSL Uniforms

Uniforms是将数据从 JavaScript 传递到着色器的一种方法。

this.material = new ShaderMaterial({
  uniforms: {
    uTime: { value: 0 }
  },
  fragmentShader: fragmentShader
});

然后在渲染函数中,我们可以更新Uniforms值:

render() {
  this.material.uniforms.uTime.value++;
  this.renderer.render(this.scene, this.camera);
}

在顶点或片段着色器中,可以像这样访问它:

uniform float uTime

void main() {
  gl_FragColor = vec4(vec3(abs(sin(uTime))), 1.0);
}

4、GLSL Varyings

Varyings对于将值从顶点着色器传递到片段着色器非常有用。下面,我将一个Varying设置为three.js内置变量:

varying vec2 vUv;

void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

在片段着色器中访问它:

varying vec2 vUv;
uniform sampler2D uImage;

void main() {
  gl_FragColor = texture2D(uImage, vUv);
}

在脚本中设置纹理:

const image = new Image();
image.onload = function() {
  const texture = new Texture(image);
  const material = new ShaderMaterial({
    uniforms: {
      uTexture: { value: texture }
    },
    fragmentShader
  });
}
image.src = '/images/some_image.jpg';

我通常用 u 作为 uniform 的前缀,用 v 作为 varying 的前缀,但这不是必需的。

5、GLSL Attributes

设置属性时,Three.js 要求一个类型化数组。类型化数组就是由于WebGL的需要而被添加到了JavaScript中。 默认情况下,BufferGeometry提供position 、normal 和uv属性。如果要使用顶点颜色,则需要在材质的选项中设置一个称为color 的属性并将vertexColors设置为 true。

const geometry = new BufferGeometry();
const displacement = new Float32Array([0, 0.5, 1]);
geometry.setAttribute('displacement', new BufferAttribute(displacement, 1));

可以添加一个标准的 JavaScript 数组,并用three.js将其转换为类型化数组。如果以编程方式构造数组,则可能需要执行此操作:

const vertices = [];
for (let i = 0; i < 3; i++) {
  vertices.push(Math.cos(i), Math.sin(i), 0);
}
geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));

在着色器中访问属性:

attribute float displacement;

void main() {
  vec3 newPosition = position + normal * vec3(displacement);
  gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}

6、GLSL模块

节点模块在编写JavaScript时非常有用。GLSL没有一个官方的模块系统,但有一个非官方的模块系统,叫做Glslify。首先,需要将Glslify模块与 GLSL 模块一起安装:

npm install glslify glsl-noise

将着色器包装在glsl函数中,并将 GLSL 模块导入着色器中:

import glsl from 'glslify';

const fragmentShader = glsl(`
  #pragma glslify: noise = require('glsl-noise/simplex/3d');

  varying vec3 vPosition;

  void main() {
    gl_FragColor = vec4(noise(vPosition), 1.0);
  }
`);

7、Webpack GLSL加载器

有一个用于webpack的 Glslify 加载器,因此可以在外部着色器文件中使用 Glslify。

npm install raw-loader glslify-loader

Webpack配置看起来像这样:

module: {
  rules: [
    {
      test: /\.(glsl|vs|fs|vert|frag)$/,
      exclude: /node_modules/,
      use: ['raw-loader', 'glslify-loader']
    }
  ]
}

8、Parcel GLSL加载器

Parcel通过@parcel/transformer-glsl插件支持Glslify。

9、GLSL着色器示例

下面是具有顶点着色器和片段着色器的球体示例。顶点着色器使用噪声函数置换顶点,片段着色器使用噪声函数再次混合红色、绿色和蓝色。默认情况下,几何图形中的顶点处于断开连接状态。如果移动顶点,它只会针对它所附着的面移动它,因此面将断开连接。要保持面连接,你必须将顶点转换为索引顶点,即通过索引引用相同的顶点,而不是为每个面复制它。将着色器变量作为uniform的一个优点是,你可以附加 GUI 并对其进行调整。可以在此处查看该示例的源代码。


原文链接:http://www.bimant.com/blog/three-js-shader-fundamentals/

相关推荐

自学Python,写一个挨打的游戏代码来初识While循环

自学Python的第11天。旋转~跳跃~,我~闭着眼!学完循环,沐浴着while的光芒,闲来无事和同事一起扯皮,我说:“编程语言好神奇,一个小小的循环,竟然在生活中也可以找到原理和例子”,同事也...

常用的 Python 工具与资源,你知道几个?

最近几年你会发现,越来越多的人开始学习Python,工欲善其事必先利其器,今天纬软小编就跟大家分享一些常用的Python工具与资源,记得收藏哦!不然下次就找不到我了。1、PycharmPychar...

一张思维导图概括Python的基本语法, 一周的学习成果都在里面了

一周总结不知不觉已经自学Python一周的时间了,这一周,从认识Python到安装Python,再到基本语法和基本数据类型,对于小白的我来说无比艰辛的,充满坎坷。最主要的是每天学习时间有限。只...

三日速成python?打工人,小心钱包,别当韭菜

随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些...

Python自动化软件测试怎么学?路线和方法都在这里了

Python自动化测试是指使用Python编程语言和相关工具,对软件系统进行自动化测试的过程。学习Python自动化测试需要掌握以下技术:Python编程语言:学习Python自动化测试需要先掌握Py...

Python从放弃到入门:公众号历史文章爬取为例谈快速学习技能

这篇文章不谈江流所专研的营销与运营,而聊一聊技能学习之路,聊一聊Python这门最简单的编程语言该如何学习,我完成的第一个Python项目,将任意公众号的所有历史文章导出成PDF电子书。或许我这个Py...

【黑客必会】python学习计划

阅读Python文档从Python官方网站上下载并阅读Python最新版本的文档(中文版),这是学习Python的最好方式。对于每个新概念和想法,请尝试运行一些代码片段,并检查生成的输出。这将帮助您更...

公布了!2025CDA考试安排

CDA数据分析师报考流程数据分析师是指在不同行业中专门从事行业数据搜集、整理、分析依据数据作出行业研究评估的专业人员CDA证书分为1-3级,中英文双证就业面广,含金量高!!?报考条件:满18...

一文搞懂全排列、组合、子集问题(经典回溯递归)

原创公众号:【bigsai】头条号:程序员bigsai前言Hello,大家好,我是bigsai,longtimenosee!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合...

「西法带你学算法」一次搞定前缀和

我花了几天时间,从力扣中精选了五道相同思想的题目,来帮助大家解套,如果觉得文章对你有用,记得点赞分享,让我看到你的认可,有动力继续做下去。467.环绕字符串中唯一的子字符串[1](中等)795.区...

平均数的5种方法,你用过几种方法?

平均数,看似很简单的东西,其实里面包含着很多学问。今天,分享5种经常会用到的平均数方法。1.算术平均法用到最多的莫过于算术平均法,考试平均分、平均工资等等,都是用到这个。=AVERAGE(B2:B11...

【干货收藏】如何最简单、通俗地理解决策树分类算法?

决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法。决策树算法是机器学习中的一种经典算法,它通过一系列的规则...

面试必备:回溯算法详解

我们刷leetcode的时候,经常会遇到回溯算法类型题目。回溯算法是五大基本算法之一,一般大厂也喜欢问。今天跟大家一起来学习回溯算法的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~什么是回溯...

「机器学习」决策树——ID3、C4.5、CART(非常详细)

决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。本文将分三篇介绍决策树,第一篇介绍基本树(包括ID3、C4.5、CART),第二篇介绍Ran...

大话AI算法: 决策树

所谓的决策树算法,通俗的说就是建立一个树形的结构,通过这个结构去一层一层的筛选判断问题是否好坏的算法。比如判断一个西瓜是否好瓜,有20条西瓜的样本提供给你,让你根据这20条(通过机器学习)建立起...