4. 顶点位置插值(设置片元颜色)
# 顶点位置插值(设置片元颜色)
这节课讲解一个onBeforeCompile
修改材质shader的案例,具体就是对顶点的位置坐标xyz进行插值计算,然后根据片元对应的顶点插值坐标,设置片元颜色。
顶点插值这个知识点其实在前面1.9. 顶点位置插值(实现渐变色) (opens new window)讲解过,可以去回顾下。
# 任务:在网格y方向增加一条光带
# 修改顶点着色器:增加顶点位置插值计算代码
你可以通过浏览器控制台log打印,查看顶点着色器代码。
material.onBeforeCompile = function (shader) {
console.log('vertexShader', shader.vertexShader);
};
// 浏览器控制台打印顶点着色器代码(提醒不同版本不一定相同)
#include <common>
...
void main(){
...
#include <fog_vertex>
}
这时候你可以思考一个问题,怎么给顶点着色器代码main函数之前插入一行插值计算的相关代码varying vec3 vPosition;
#include <common>
...
varying vec3 vPosition;//表示顶点位置插值后的坐标
void main(){
...
#include <fog_vertex>
}
.replace()
查询关键词void main() {
进行如下替换。
material.onBeforeCompile = function (shader) {
shader.vertexShader = shader.vertexShader.replace(
'void main() {',
`
varying vec3 vPosition;//顶点位置插值后的坐标
void main(){
`
);
};
在main
函数里面,增加顶点位置插值计算的代码。
position
表示几何体的顶点位置坐标,modelMatrix
表示网格模型的旋转缩放平移。
material.onBeforeCompile = function (shader) {
shader.vertexShader = shader.vertexShader.replace(
'void main() {',
`
varying vec3 vPosition;//顶点位置插值后的坐标
void main(){
// 顶点位置坐标模型矩阵变换后,进行插值计算
vPosition = vec3(modelMatrix * vec4( position, 1.0 ));
`
);
};
# 片元着色器增加varying vec3 vPosition;
查看片元着色器代码,在main函数前面增加代码varying vec3 vPosition;
,与上面顶点着色器代码思路相似。
material.onBeforeCompile = function (shader) {
console.log('fragmentShader', shader.fragmentShader);
};
片元着色器增加varying vec3 vPosition;
,获取顶点位置插值之后的坐标值vPosition
。
shader.fragmentShader = shader.fragmentShader.replace(
'void main() {',
`
varying vec3 vPosition;
void main() {
`
);
# 根据片元对应顶点位置设置片元颜色
回顾下前面shader知识点,大家都知道,网格模型Mesh经过图元装配和光栅化以后,会生成一个一个的片元,这些片元会构成Mesh的3D轮廓。
同时顶点位置数据插值计算之后,会生成每个片元对应的xyz坐标。这时候我们就可以跟片元的坐标vPosition
控制自身的颜色值。
// 顶点着色器
varying vec3 vPosition;//顶点位置插值后的坐标
void main(){
// 顶点位置坐标模型矩阵变换后,进行插值计算
vPosition = vec3(modelMatrix * vec4( position, 1.0 ));
}
// 片元着色器
varying vec3 vPosition;//顶点位置插值后的坐标
void main(){
// 根据y坐标控制片元颜色
if(vPosition.y > 20.0 && vPosition.y < 21.0 ){
gl_FragColor = vec4(1.0,1.0,0.0,1.0);
}
}
# 修改片元着色器字符串
浏览器控制打印的片元着色器代码,复制main
函数里面最后一行代码(提醒:不同版本可能不同,以你自己版本为准)
material.onBeforeCompile = function (shader) {
console.log('fragmentShader', shader.fragmentShader);
};
网格材质shader代码中gl_FragColor
已经有默认设置的颜色,我们可以在片元着色器主函数main
里面最后一行增加下面代码,在网格模型上生成一条光带。
shader.fragmentShader = shader.fragmentShader.replace(
'#include <dithering_fragment>',
`
#include <dithering_fragment>
if(vPosition.y > 20.0 && vPosition.y < 21.0 ){
gl_FragColor = vec4(1.0,1.0,0.0,1.0);
}
`
);
# 多条光带
网格模型上面等间距设置多条光带。
shader.fragmentShader = shader.fragmentShader.replace(
'#include <dithering_fragment>',
`
#include <dithering_fragment>
float y0 = 0.0;
for (int i = 0; i < 4; i++) {
y0 += 20.0;
if(vPosition.y > y0 && vPosition.y < y0+1.0 ){
gl_FragColor = vec4(1.0,1.0,0.0,1.0);
}
}
`
);
# 总结
静态不动的模型,使用最方便
运动的