书接上文,前面说修改白膜渐变需要知道模型位置PositionMC,那这个是片元着色器内部属性,可以直接访问,还有一种是需要手动传递的,所以下面介绍片元着色器的数据来源:
片元着色器中数据的两种来源
1. 通过 Varying 从顶点着色器传递(需要手动设置)
ini
let customShader = new Cesium.CustomShader({
varyings: {
v_customPosition: Cesium.VaryingType.VEC3, // 自定义传递变量
v_customNormal: Cesium.VaryingType.VEC3
},
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
// 手动传递数据到片元着色器
v_customPosition = vsInput.attributes.positionMC * 2.0; // 自定义计算
v_customNormal = normalize(vsInput.attributes.normalMC);
}`,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
// 使用通过varying传递的数据
vec3 customPos = v_customPosition;
vec3 customNorm = v_customNormal;
material.diffuse = customNorm * 0.5 + 0.5; // 法线可视化
}`
});
2. 直接通过 fsInput.attributes 访问(内置可用,无需传递)
ini
let customShader = new Cesium.CustomShader({
// 注意:这里没有定义varyings!
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
// 顶点着色器可以为空,或者处理其他逻辑
}`,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
// 直接访问内置属性,无需通过varying传递
vec3 positionMC = fsInput.attributes.positionMC;
vec3 normalEC = fsInput.attributes.normalEC;
vec2 texCoord = fsInput.attributes.texCoord_0;
material.diffuse = vec3(texCoord, 0.0); // UV坐标可视化
}`
});
内置可用的 fsInput.attributes
Cesium 自动提供以下内置属性:
几何属性:
arduino
// 位置相关
vec3 positionMC; // 模型坐标系位置
vec3 positionEC; // 眼坐标系位置
vec3 positionWC; // 世界坐标系位置
// 法线相关
vec3 normalMC; // 模型坐标系法线
vec3 normalEC; // 眼坐标系法线
// 纹理坐标
vec2 texCoord_0; // 第一套UV坐标
vec2 texCoord_1; // 第二套UV坐标
其他属性:
arduino
// 切线空间
vec3 tangentMC; // 模型坐标系切线
vec3 bitangentMC; // 模型坐标系副切线
// 颜色
vec3 color_0; // 顶点颜色
什么时候需要用 Varying?
需要手动传递的情况:
1. 自定义计算的结果
arduino
// 顶点着色器
v_customHeight = positionMC.y * 10.0; // 自定义高度计算
// 片元着色器
float height = v_customHeight; // 使用自定义计算值
2. 修改后的数据
ini
// 顶点着色器
v_modifiedNormal = normalMC * 2.0; // 修改法线
// 片元着色器
vec3 normal = v_modifiedNormal; // 使用修改后的法线
3. 复杂数据结构
scss
// 需要传递多个相关数据时
v_customData = vec4(positionMC, normalMC.x); // 打包数据
实际示例对比
方案A:使用内置属性(推荐,简单)
ini
// 直接使用内置的positionMC,不需要varying
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
vec3 positionMC = fsInput.attributes.positionMC;
material.diffuse = vec3(0.0, 1.0 - positionMC.z * 0.005, 1.0);
}`
方案B:使用Varying传递(复杂,不必要)
ini
varyings: {
v_positionMC: Cesium.VaryingType.VEC3
},
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
v_positionMC = vsInput.attributes.positionMC; // 只是简单传递
}`,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
vec3 positionMC = v_positionMC; // 通过varying获取
material.diffuse = vec3(0.0, 1.0 - positionMC.z * 0.005, 1.0);
}`
总结
- 内置属性 :直接使用
fsInput.attributes.xxx,无需varying - 自定义数据:需要通过varying手动传递
- 最佳实践:优先使用内置属性,除非需要传递自定义计算结果