- 作者:老汪软件技巧
- 发表时间:2024-09-04 21:02
- 浏览量:
前言
之前我们用three.js做过一个汽车展厅的案例,只是用到了一些three.js封装好的一些api,实现的也就是一些普通的效果,想要做出来一些比较炫酷的效果的话还是需要用到着色器,例如做一些智慧工厂,智慧城市,智慧水利等项目,一些比较酷炫高级的效果,基本上都是使用到着色器(OpenGL)的。本章我们就简单讲解一下着色器,带大家进行简单的入门
渲染管线
我们在学习着色器前了解一下浏览器的渲染过程,我们的渲染大致可以分为三个阶段,主要为应用阶段,几何阶段(顶点着色器,曲面细分着色器,几何着色器,投影,剪裁,屏幕映射),光栅化阶段(图元组装,三角形遍历,片元着色器,逐片元操作)、几何阶段呢会计算每个像素点和顶点的位置,光栅华阶段就是对每个像素点的颜色进行处理。
初始着色器
OpenGL着色器语言类似于C语言(写法上有些相似),主要是为了做出来一些更高级的颜色和效果,他主要就是在顶点着色器和片元着色器上来写相应的代码,影响图形的渲染形状和颜色。three呢也提供了对应的材质ShaderMaterial我们可以在内部进行编写,来影响图形的颜色和形状。
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.ShaderMaterial({
vertexShader: `
void main(){
gl_Position = projectionMatrix * viewMatrix *modelMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `
void main(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
上面我们就是使用了three的着色器材质创建了一个物体,其中vertexShader为顶点着色器,主要是控制像素点的位置,内部有一个gl_Position用来控制像素点的顶点坐标,vec4是内部的一个函数,主要接受一个四维空间坐标点(x,y,z,w),计算方式就是x/w,y/w,z/w,w其实就是一个数字比例,position呢是几何图像geometry的position,是ShaderMaterial内部默认声明和赋值的一个变量,但是你如果直接使用vec4( position, 1.0 ) 会出现问题,是因为你只是将物体的局部坐标直接传递给了 gl_Position,这意味着顶点的位置没有经过任何的变换矩阵(比如模型矩阵、视图矩阵、投影矩阵)的转换,转换过程为modelMatrix * vec4(position, 1.0)首先将顶点从局部坐标系转换到世界坐标系viewMatrix * (modelMatrix * vec4(position, 1.0))然后将顶点从世界坐标系转换到相机坐标系projectionMatrix * (viewMatrix * (modelMatrix * vec4(position, 1.0)))最后将顶点从相机坐标系转换到裁剪坐标系,准备投影到屏幕上,通过以上计算我们就可以确保每个顶点都进行了正确的坐标转换(每个像素点渲染都会执行一次)。fragmentShader为片元着色器,主要是修改物体的颜色和渲染效果,gl_FragColor用控制像素的颜色,也是vec4函数,接受rgb三原色值
attribure
attribure是内部用来接受值的一个变量,主要用于向顶点着色器传输几何图形的各种属性
const geometry = new THREE.PlaneGeometry(1, 1);
geometry.setAttribute("position2",geometry.attributes.position)
const material = new THREE.ShaderMaterial({
vertexShader: `
attribute vec3 position2;
void main(){
gl_Position = projectionMatrix * viewMatrix *modelMatrix * vec4( position2, 1.0 );
}
`,
fragmentShader: `
void main(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
如上,我们往geometry添加了一个position2的属性,然后再顶点着色器内接收到,然后使用position2进行渲染,的到的效果还是一样的
uniform
uniform可以再顶点或者片元着色器接受全局参数来进行使用
const material = new THREE.ShaderMaterial({
vertexShader: `
attribute vec3 position2;
uniform float pox;
void main(){
vec4 v = vec4(position2, 1.0);
v.x += pox;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
}
`,
fragmentShader: `
void main(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
uniforms: {
pox: {
value: 2.0, //初始值
},
},
});
比如我们声明了一个浮点数,2,我们想要图像再X轴偏移两个单位,那么只需要再顶点着色器声明接受,然后让每个像素点的偏移量都有加上pox就可以实现了
varying
varying是将顶点着色器中的数据传递给片元着色器进行使用。
const material = new THREE.ShaderMaterial({
vertexShader: `
attribute vec3 position2;
uniform float pox;
varying vec2 myUV;
void main(){
myUV = uv;
vec4 v = vec4(position2, 1.0);
v.x += pox;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
}
`,
fragmentShader: `
varying vec2 myUV;
void main(){
gl_FragColor = vec4(myUV.x, myUV.y, 0, 1.0);
}
`,
uniforms: {
pox: {
value: 2.0, //初始值
},
},
});
我们只需要再顶点着色器声明这个变量对其进行赋值然后再片元着色器进行声明就可以接收到此值。uv也是ShaderMaterial内默认赋值定义的
波浪效果
我们用上面了解到的顶点着色器和偏远着色器来实现一个渐变的波浪效果
const material = new THREE.ShaderMaterial({
vertexShader: `
attribute vec3 position2;
uniform float pox;
varying vec2 myUV;
void main(){
myUV = uv;
vec4 v = vec4(position2, 1.0);
v.x += pox;
v.z = sin(v.x * 10.0) * 0.1;
v.z += sin(v.y * 10.0) * 0.1;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * v;
}
`,
fragmentShader: `
varying vec2 myUV;
void main(){
gl_FragColor = vec4(myUV.y, myUV.y, myUV.y, 1.0);
}
`,
uniforms: {
pox: {
value: 2.0, //初始值
},
},
});
其实还是使用的上面的代码,只是修改改了每个像素点位的z坐标,sin(v.x * 10.0) 生成了一个基于顶点 x 坐标的正弦波, v.z 的基础上再次叠加了一个基于顶点 y 坐标的正弦波,产生的效果是二维的波浪。
结尾
以上只是介绍了GLSL的一些基本用法写法,以及内部的一些变量及怎么使用。只作为入门了解的一个基本,如果是真正的学习着色器还是少不了一些图形学的知识的