当前位置:   article > 正文

Three.js-Shaders着色器_threejs 着色器

threejs 着色器

目录

1.什么是着色器

2.什么是GLSL

3.顶点着色器和片元着色器

3.1 顶点着色器Vertex shaders

3.2 片元着色器fragment shaders

4.着色器材质

4.1 什么是着色器材质

4.2 着色器材质的变量

4.3 着色器材质的简单使用

4.4 VScode配置着色器插件

 5. 使用原始着色器(rawShaderMaterial)实现旗帜飘动效果


1.什么是着色器

着色器(Shaders )是一种使用GLSL(OpenGL Shading Language)编写并在GPU上运行的程序。它们被用于定位几何体的每个顶点,并为该几何体的每个可见像素着色。使用“像素Pixel”来描述其实并不准确,因为渲染的每个点不一定与屏幕上的每个像素相匹配,因此我们更倾向于使用术语“片元fragment”。
之后我们会向着色器发送大量数据,如顶点坐标、网格变换、摄像机及其视野范围的信息、颜色、纹理、灯光、雾等参数。然后,GPU会按照着色器的指示处理所有的这些数据,接着几何体便出现在渲染中。

Shaders 也是一系列的指令,但是这些指令会对屏幕上的每个像素同时下达。也就是说,你的代码必须根据像素在屏幕上的不同位置执行不同的操作。就像活字印刷,你的程序就像一个 function(函数),输入位置信息,输出颜色信息,当它编译完之后会以相当快的速度运行。

下面一起来看“Hello world!”示例:

  1. #ifdef GL_ES
  2. precision mediump float;
  3. #endif
  4. uniform float u_time;
  5. void main() {
  6. gl_FragColor = vec4(0.533,0.650,1.000,1.000);
  7. }

 实现效果:

 尽管这几行简单的代码看起来不像有很多内容,我们还是可以据此推测出一些知识点:

  1. shader 语言 有一个 main 函数,会在最后返回颜色值。这点和 C 语言很像。

  2. 最终的像素颜色取决于预设的全局变量 gl_FragColor

  3. 这个类 C 语言有内建的变量(像gl_FragColor),函数数据类型。在本例中我们刚刚介绍了vec4(四分量浮点向量)。之后我们会见到更多的类型,像 vec3 (三分量浮点向量)和 vec2 (二分量浮点向量),还有非常著名的:float(单精度浮点型), int(整型) 和 bool(布尔型)。

  4. 如果我们仔细观察 vec4 类型,可以推测这四个变元分别响应红,绿,蓝和透明度通道。同时我们也可以看到这些变量是规范化的,意思是它们的值是从0到1的。之后我们会学习如何规范化变量,使得在变量间map(映射)数值更加容易。

  5. 另一个可以从本例看出来的很重要的类 C 语言特征是,预处理程序的宏指令。宏指令是预编译的一部分。有了宏才可以 #define (定义)全局变量和进行一些基础的条件运算(通过使用 #ifdef 和 #endif)。所有的宏都以 # 开头。预编译会在编译前一刻发生,把所有的命令复制到 #defines 里,检查#ifdef 条件句是否已被定义, #ifndef 条件句是否没有被定义。在我们刚刚的“hello world!”的例子中,我们在第2行检查了 GL_ES 是否被定义,这个通常用在移动端或浏览器的编译中。

  6. float类型在 shaders 中非常重要,所以精度非常重要。更低的精度会有更快的渲染速度,但是会以质量为代价。你可以选择每一个浮点值的精度。在第一行(precision mediump float;)我们就是设定了所有的浮点值都是中等精度。但我们也可以选择把这个值设为“低”(precision lowp float;)或者“高”(precision highp float;)。

  7. 最后可能也是最重要的细节是,GLSL 语言规范并不保证变量会被自动转换类别。

2.什么是GLSL

 OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。比如:视图转换、投影转换等。GLSL(GL Shading Language)的着色器代码分成2个部分:Vertex Shader(顶点着色器)和Fragment(片断着色器),有时还会有Geometry Shader(几何着色器)。负责运行顶点着色的是顶点着色器。它可以得到当前OpenGL 中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。

GLSL的变量命名方式与C语言类似。变量的名称可以使用字母,数字以及下划线,但变量名不能以数字开头,还有变量名不能以gl_作为前缀,这个是GLSL保留的前缀,用于GLSL的内部变量。当然还有一些GLSL保留的名称是不能够作为变量的名称的。

3.顶点着色器和片元着色器

WebGL的着色器代码分为顶点着色器代码和片元着色器代码两部分,顶点着色器代码会在GPU的顶点着色器单元执行,片元着色器代码会在GPU的片元着色器单元执行,在WebGL渲染管线流程中,或者说GPU的渲染流程中,顶点着色器代码先执行处理顶点,得到一系列片元,然后再执行片元着色器代码处理片元。

3.1 顶点着色器Vertex shaders

顶点着色器(Vertex Shader)的作用是定位几何体的顶点。其思想是发送顶点位置、网格变换(如定位position、旋转rotation和缩放scale)、摄影机信息(如定位position、旋转rotation和视野fov)。然后,GPU将按照顶点着色器中的指示处理所有这些信息,以便将顶点投影到2D空间,该空间将成为我们的渲染render,也就是我们的画布canvas。

  • 顶点着色器首先运行; 它接收attributes, 计算/操纵每个单独顶点的位置,并将其他数据(varyings)传递给片元着色器。

3.2 片元着色器fragment shaders

片元着色器的作用是为几何体的每个可见片元(像素)进行着色。
我们会创建片元着色器,可以通过使用uniform将数据(像是颜色)和着色器发送至GPU,之后GPU就会按照指令对每个片元进行着色。

  • 片元(或像素)着色器后运行; 它设置渲染到屏幕的每个单独的“片元”(像素)的颜色。

 参考:

three.js学习笔记(十四)——Shaders着色器_hongsir_12的博客-CSDN博客_threejs着色器什么是着色器?实际上着色器是WebGL的主要组件之一。如果我们在没接触Three.js情况下开始学习WebGL,着色器将是我们首先且必须要学的知识,这也是为什么原生WebGL很难入门。着色器是一种使用GLSL(OpenGL Shading Language)编写并在GPU上运行的程序。它们被用于定位几何体的每个顶点,并为该几何体的每个可见像素着色。使用“像素Pixel”来描述其实并不准确,因为渲染的每个点不一定与屏幕上的每个像素相匹配,因此我们更倾向于使用术语“片元fragment”。之后我们会向着色https://blog.csdn.net/weixin_43990650/article/details/1220265693.3 shaders着色器主要工作流程

1)顶点着色器收到系统传递给它的模型数据。

2)顶点着色器把模型数据处理成我们后续需要的数据进行输出(这些数据还包括纹理的UV坐标以及其他需要传递给片元着色器的数据)。

3)系统对顶点着色器输出的顶点数据进行插值,并将插值结果传递给片元着色器。

4)片元着色器根据这些插值结果计算最后屏幕上的像素颜色。

4.着色器材质

4.1 什么是着色器材质

着色器材质(ShaderMaterial)是一个用GLSL编写的小程序 ,在GPU上运行。它能够提供 materials 之外的效果,也可以将许多对象组合成单个Geometry或BufferGeometry以提高性能。

4.2 着色器材质的变量

每个着色器材质都可以指定两种不同类型的shaders,他们是顶点着色器和片元着色器(Vertex shaders and fragment shaders)。

  • 顶点着色器首先运行; 它接收attributes, 计算/操纵每个单独顶点的位置,并将其他数据(varyings)传递给片元着色器。
  • 片元(或像素)着色器后运行; 它设置渲染到屏幕的每个单独的“片元”(像素)的颜色。

shader中有三种类型的变量: uniforms, attributes, 和 varyings

关键字(变量类型)数据传递声明变量
attributejavascript——>顶点着色器声明顶点数据变量
uniformjavascript——>顶点、片元着色器声明非顶点数据变量
varying顶点着色器——>片元着色器声明需要插值计算的顶点变量
  • Uniforms是所有顶点都具有相同的值的变量。 比如灯光,雾,和阴影贴图就是被储存在uniforms中的数据。 uniforms可以通过顶点着色器和片元着色器来访问。
  • Attributes 与每个顶点关联的变量。例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes 只 可以在顶点着色器中访问。
  • Varyings 是从顶点着色器传递到片元着色器的变量。对于每一个片元,每一个varying的值将是相邻顶点值的平滑插值。

注意:在shader 内部,uniforms和attributes就像常量;你只能使用JavaScript代码通过缓冲区来修改它们的值。

炫彩蛋示例:

  1. var geom = new THREE.SphereGeometry(10, 30, 20);
  2. var mate = new THREE.ShaderMaterial({
  3. vertexShader: `
  4. varying vec3 vNormal;
  5. void main() {
  6. //将attributes的normal通过varying赋值给了向量vNormal
  7. vNormal = normal;
  8. //projectionMatrix是投影变换矩阵 modelViewMatrix是相机坐标系的变换矩阵 最后我们将y值乘以1.4得到了一个形如鸡蛋的几何体
  9. gl_Position = projectionMatrix * modelViewMatrix * vec4( position.x, position.y * 1.4, position.z, 1.0 );
  10. }
  11. `,
  12. fragmentShader: `
  13. //片元着色器同样需要定义varying vec3 vNormal;
  14. varying vec3 vNormal;
  15. void main() {
  16. //vNormal是一个已经归一化的三维向量
  17. float pr = (vNormal.x + 1.0) / 2.0; //pr红色通道值范围为0~1
  18. float pg = (vNormal.y + 1.0) / 2.0; //pg绿色通道值范围为0~1
  19. float pb = (vNormal.z + 1.0) / 2.0; //pb蓝色通道值范围为0~1
  20. gl_FragColor=vec4(pr, pg, pb, 1.0); //最后设置顶点颜色,点与点之间会自动插值
  21. }
  22. `
  23. })
  24. var mesh = new THREE.Mesh(geom, mate);
  25. scene.add(mesh)

实现效果:

 

4.3 着色器材质的简单使用

  1. // 创建着色器材质
  2. const shaderMaterial = new THREE.ShaderMaterial({
  3. //顶点着色器
  4. vertexShader: `
  5. void main(){
  6. gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
  7. }
  8. `,
  9. //片元着色器
  10. fragmentShader: `
  11. void main(){
  12. gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);//rgba
  13. }
  14. `,
  15. });
  16. // 创建平面
  17. const floor = new THREE.Mesh(
  18. new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  19. shaderMaterial
  20. );
  21. console.log(floor);
  22. scene.add(floor);

 实现效果:

 此外,在进行项目构建时,由于涉及较多着色器编写,建议对着色器文件单独进行编写,例如:

 并在js文件中通过import导入使用

  1. // 顶点着色器
  2. import basicVertexShader from "../shader/basic/vertex.glsl";
  3. // 片元着色器
  4. import basicFragmentShader from "../shader/basic/fragment.glsl";

在shaderMaterial中调用着色器:

  1. // 创建着色器材质
  2. const shaderMaterial = new THREE.ShaderMaterial({
  3. vertexShader: basicVertexShader,
  4. fragmentShader: basicFragmentShader,
  5. });

4.4 VScode配置着色器插件

在插件商店中搜索Shader languages support for VS Code插件,可以对glsl等着色器语言进行语法支持。

 5. 使用原始着色器(rawShaderMaterial)实现旗帜飘动效果

fragment.glsl:

  1. precision lowp float;精度
  2. // highp -2^16 - 2^16
  3. // mediump -2^10 - 2^10
  4. // lowp -2^8 - 2^8
  5. varying vec2 vUv;
  6. varying float vElevation;
  7. //导入采样纹理
  8. uniform sampler2D uTexture;
  9. void main(){
  10. // gl_FragColor = vec4(vUv, 0.0, 1.0);//由uv渲染颜色(01
  11. // float height = vElevation + 0.05 * 10.0;
  12. // gl_FragColor = vec4(1.0*height,0.0, 0.0, 1.0);
  13. float height = vElevation + 0.05 * 20.0;//0~2
  14. // 根据UV,取出对应的颜色
  15. //根据uv进行采样
  16. vec4 textureColor = texture2D(uTexture,vUv);
  17. textureColor.rgb*=height;
  18. gl_FragColor = textureColor;
  19. }

vertex.glsl:

  1. //精度
  2. // highp -2^16 - 2^16
  3. // mediump -2^10 - 2^10
  4. // lowp -2^8 - 2^8
  5. precision lowp float;
  6. attribute vec3 position;
  7. attribute vec2 uv;
  8. uniform mat4 modelMatrix;
  9. uniform mat4 viewMatrix;
  10. uniform mat4 projectionMatrix;
  11. // 获取时间
  12. uniform float uTime;
  13. //传到片元着色器的
  14. varying vec2 vUv;
  15. //高度
  16. varying float vElevation;
  17. void main(){
  18. vUv = uv;
  19. vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
  20. // modelPosition.x += 1.0;
  21. // modelPosition.z += 1.0;
  22. // modelPosition.z += modelPosition.x;
  23. //使用sin函数实现波浪效果
  24. modelPosition.z = sin((modelPosition.x+uTime) * 10.0)*0.05 ;
  25. modelPosition.z += sin((modelPosition.y+uTime) * 10.0)*0.05 ;
  26. //把z的值传过去
  27. vElevation = modelPosition.z;
  28. gl_Position = projectionMatrix * viewMatrix * modelPosition ;
  29. }

main.js:

  1. import * as THREE from "three";
  2. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
  3. // 顶点着色器
  4. import basicVertexShader from "../shader/raw/vertex.glsl";
  5. // 片元着色器
  6. import basicFragmentShader from "../shader/raw/fragment.glsl";
  7. // 目标:认识shader
  8. // 初始化场景
  9. const scene = new THREE.Scene();
  10. // 创建透视相机
  11. const camera = new THREE.PerspectiveCamera(
  12. 90,
  13. window.innerHeight / window.innerHeight,
  14. 0.1,
  15. 1000
  16. );
  17. // 设置相机位置
  18. // object3d具有position,属性是13维的向量
  19. camera.position.set(0, 0, 2);
  20. // 更新摄像头
  21. camera.aspect = window.innerWidth / window.innerHeight;
  22. // 更新摄像机的投影矩阵
  23. camera.updateProjectionMatrix();
  24. scene.add(camera);
  25. // 加入辅助轴,帮助我们查看3维坐标轴
  26. const axesHelper = new THREE.AxesHelper(5);
  27. scene.add(axesHelper);
  28. // 加载纹理
  29. // 创建纹理加载器对象
  30. const textureLoader = new THREE.TextureLoader();
  31. const texture = textureLoader.load("./texture/ca.jpeg");
  32. // 创建原始着色器材质
  33. const rawShaderMaterial = new THREE.RawShaderMaterial({
  34. vertexShader: basicVertexShader,
  35. fragmentShader: basicFragmentShader,
  36. // wireframe: true,
  37. side: THREE.DoubleSide,
  38. //设置传输的数据
  39. uniforms: {
  40. uTime: {
  41. value: 0,
  42. },
  43. uTexture: {
  44. value: texture,
  45. },
  46. },
  47. });
  48. // 创建平面
  49. const floor = new THREE.Mesh(
  50. new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  51. rawShaderMaterial
  52. );
  53. console.log(floor);
  54. scene.add(floor);
  55. // 初始化渲染器
  56. const renderer = new THREE.WebGLRenderer({ alpha: true });
  57. // 设置渲染尺寸大小
  58. renderer.setSize(window.innerWidth, window.innerHeight);
  59. // 监听屏幕大小改变的变化,设置渲染的尺寸
  60. window.addEventListener("resize", () => {
  61. // console.log("resize");
  62. // 更新摄像头
  63. camera.aspect = window.innerWidth / window.innerHeight;
  64. // 更新摄像机的投影矩阵
  65. camera.updateProjectionMatrix();
  66. // 更新渲染器
  67. renderer.setSize(window.innerWidth, window.innerHeight);
  68. // 设置渲染器的像素比例
  69. renderer.setPixelRatio(window.devicePixelRatio);
  70. });
  71. // 将渲染器添加到body
  72. document.body.appendChild(renderer.domElement);
  73. // 初始化控制器
  74. const controls = new OrbitControls(camera, renderer.domElement);
  75. // 设置控制器阻尼
  76. controls.enableDamping = true;
  77. // 设置自动旋转
  78. // controls.autoRotate = true;
  79. const clock = new THREE.Clock();
  80. function animate(t) {
  81. const elapsedTime = clock.getElapsedTime();
  82. // console.log(elapsedTime);
  83. rawShaderMaterial.uniforms.uTime.value = elapsedTime;
  84. requestAnimationFrame(animate);
  85. // 使用渲染器渲染相机看这个场景的内容渲染出来
  86. renderer.render(scene, camera);
  87. }
  88. animate();

实现效果:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/892749
推荐阅读
相关标签
  

闽ICP备14008679号