1、定义与功能
顶点着色器
javascript
顶点着色器,是图形渲染管线中的第一个可编程阶段,
它的主要任务是,
处理从CPU发送到GPU的顶点数据,包括:
1、顶点位置的变换(如:模型空间 -> 世界空间 -> 视图控件 -> 投影空间的转换)
2、光照计算
3、传递数据到后续的渲染阶段(`传递数据到片元着色器`)
片元着色器
javascript
片元着色器,是图形渲染管线中处理像素级渲染的阶段,
它接收由`顶点着色器插值得到的片元`(即:屏幕上的像素或像素的候选者),
并生成最终的颜色和其他与像素相关的数据
2、顶点/片元之间的数据传递
javascript
1、顶点数据传递:
顶点着色器处理完顶点数据后,会将结果(包括位置、颜色、纹理坐标等)传递给片元着色器,
这通常是通过 `varying` 变量来实现的,
这些变量,在光栅化阶段被线性插值,以生成每个片元对应的值
2、光照与纹理:
在某些情况下,顶点着色器会执行初步的光照计算,并将结果作为输入,传递给片元着色器,
片元着色器则负责执行更详细的光照计算,如:计算每个像素上的光照强度和颜色,
同时,片元着色器还负责纹理映射,即:从纹理中读取颜色信息,并应用到相应的像素上
3、渲染流程
javascript
在渲染流程中,顶点着色器首先处理顶点数据,然后将处理后的数据传递给光栅化器,
光栅化器将顶点数据转换为片元数据,并将这些数据,以及顶点着色器输出的varying变量,传递给片元着色器,
最后,片元着色器处理这些数据,生成最终的颜色值,并将其写入帧缓冲区以供显示
4、关系总结
javascript
依赖关系:
1、
片元着色器,依赖于,顶点着色器的输出数据,来进行进一步的计算和处理,
没有顶点着色器提供的顶点数据、varying变量插值结果,片元着色器就无法正常工作。
2、
顶点着色器和片元着色器共同协作,完成了从顶点数据到像素颜色的整个渲染过程。
码子
vertex.glsl
顶点着色器
javascript
`precision关键字:设置着色器中使用的浮点数精度为lowp(低精度),有助于在不影响视觉效果的情况下提高渲染性能
precision lowp float; // 后续,所有浮点数的精度,为lowp(低精度:-2^8 - 2^8)
precision lowp mediump; // 后续,所有浮点数的精度,为mediump(中精度:-2^10 - 2^10)
precision lowp highp; // 后续,所有浮点数的精度,为highp(高精度:-2^16 - 2^16)`
precision lowp float;
`attribute:在顶点着色器中声明变量(在较新的GLSL版本中,attribute已经被in关键字所取代)
vec3:一个数据类型,代表一个三维向量 `
attribute vec3 position;
uniform mat4 modelMatrix; `modelMatrix模型矩阵:用于将顶点,从模型空间 -> 世界空间`
uniform mat4 viewMatrix; `viewMatrix视图矩阵:用于将顶点,从世界空间 -> 观察空间`
uniform mat4 projectionMatrix; `projectionMatrix投影矩阵:用于将顶点,从观察空间 -> 裁剪空间,并最终映射到屏幕坐标上`
attribute vec2 uv; `uv:每个顶点的纹理坐标(u, v)`
varying vec2 vUv; `vUv:传递给片段着色器的纹理坐标`
// 获取时间
uniform float uTime; `uTime:一个统一变量,用于传递时间信息,可以用于动画效果`
varying float vElevation;
void main() {
`将输入的纹理坐标传递给片段着色器`
vUv = uv;
`用于,将顶点的位置,从模型空间 -> 世界空间`
vec4 modelPosition = modelMatrix*vec4(position, 1.0);
`顶点着色器,处理的每个顶点都有一个位置(position),这个位置是一个三维向量(vec3),包含x、y、z三个坐标`
// modelPosition.x += 1.0;
// modelPosition.z += 1.0;
// modelPosition.z += modelPosition.x;
` 1、
通过,正弦函数,动态地调整顶点的z坐标,创建了一种基于时间和顶点位置的波动效果
基于顶点x坐标和时间的正弦波值,并将其幅度缩放为原始值的5%,
意味着,
随着uTime(时间)的增加,顶点的z坐标,将根据其在x轴上的位置以正弦波的形式变化。
2、
sin((modelPosition.x + uTime) * 10.0),为什么乘以10呢?
因为,正弦函数sin的周期是2π,
意味着,它完成一个完整的波形(从0到1,再到0)需要2π个单位
但是,
对(modelPosition.x + uTime)乘以10之后,
实际上,是在对,正弦函数sin的周期,进行缩放,
使得原本需要2π单位才能完成的波形,现在只需要(2π / 10) = 0.2π单位,就能完成一次完整的周期,
所以,乘以10.0,
意味着,
波形在相同的空间或时间范围内,完成了更多的周期,从而增加了波形的频率 `
modelPosition.z = sin((modelPosition.x+uTime)*10.0)*0.05;
modelPosition.z += sin((modelPosition.y+uTime)*10.0)*0.05;
vElevation = modelPosition.z; `将调整后的z值传递给片段着色器`
`计算顶点在裁剪空间中的位置`
gl_Position = projectionMatrix*viewMatrix*modelPosition;
}
码子
fragment.glsl
文件 片元着色器
javascript
precision lowp float; `设置着色器中使用的浮点数精度为lowp(低精度),有助于在不影响视觉效果的情况下提高渲染性能`
varying vec2 vUv; `顶点着色器传过来的,表示,每个片段(像素)在纹理图像上的UV坐标`
varying float vElevation; `顶点着色器传过来的,表示,每个顶点的高度信息,这里用它来影响片段的颜色`
uniform sampler2D uTexture; `这是一个统一变量,指向一个二维纹理图像`
void main() {
// gl_FragColor = vec4(vUv, 0.0, 1.0);
// float height = vElevation + 0.05 * 10.0;
// gl_FragColor = vec4(1.0*height,0.0, 0.0, 1.0);
// 根据UV,取出对应的颜色
float height = vElevation+0.05*20.0; `将顶点的高度vElevation,增加了一个固定值`
`使用texture2D函数,根据UV坐标,从uTexture纹理中采样颜色,
texture2D函数,返回的是一个包含RGBA四个分量的vec4向量`
vec4 textureColor = texture2D(uTexture, vUv);
`将采样得到的纹理颜色(仅RGB部分)与计算出的高度值相乘,
意味着,高度越高,纹理颜色会越亮(或越深,取决于纹理颜色的初始亮度)
这是一个简单的,颜色调制过程,用于,根据高度信息,改变纹理的视觉效果`
textureColor.rgb *= height;
`设置片段颜色,gl_FragColor就是,片段着色器输出的颜色,将用于渲染到屏幕上`
gl_FragColor = textureColor;
}