前几篇文章中我们介绍了Primitive的相关内容,我们会发现在Primitive中Appearance是Primitive的重要组成部分。我们已经可以简单的使用Appearance来设置Primitive几何图形的外观。这篇文章,我们来详细的了解一下Appearance。
Appearance分类
Cesium中一共有以下几种Appearance,不同的Appearance适用于不同的场景,如果你在某个场景中,使用错了Appearance,会导致看不见渲染结果的。
还有一个DebugAppearance,我们不说这个,这个是用于测试的。
MaterialAppearance材质外观
对于所有的几何对象都适用,cesium的材质包括颜色,图片,法线贴图,凹凸贴图,网格贴图,棋盘贴图等。支持传入material
EllipsoidSurfaceAppearance椭球体表面外观
支持所有材质,但需要具有法线,切线,副切线属性,是MaterialAppearance的另一个版本,主要用于地球表面平行的几何类型,如我们在前几篇中提到的PolygonGeometry,RectangleGeometry这些不适用与地表垂直的几何类型。使用llipsoidSurfaceAppearance时可以在计算大量顶点属性时节省内存。
PerInstanceColorAppearance实例化材质外观
使用每个GeometryInstance自带的颜色属性,可以实现不同的实例渲染不同颜色。我们在前几篇有提到Primitive通过实例化几何时可以同时显示大量的几何实体,但是一个Primitive只能存在一个Appearance,那么我们想每个几何实体的外观不同的话,就可以通过perInstanceColorAppearance这个类去实现了。
PolylineColorAppearance线几何对象的颜色外观
使用每个GeometryInstance自带的颜色属性,可以实现不同的实例渲染不同颜色。我们提到过PolylineGeometry支持根据顶点颜色进行着色,那么我们此时就需要结合PolylineColorAppearance类一起去实现了。
PolylineMaterialAppearance线几何对象的材质的外观
可以对线几何对象使用各种材质。支持传入material
Material材质
Material我们一般叫作材质,用于表达物体的表面外观。在我们肉眼看到的世界中,每一种物体对光都会产生不同的反应,这就使得不同物体的表面看起来不一样。
Cesium中内置的Material类大概有20多种材质类型,不同的几何应用不同的材质,这样可以使得场景渲染出来的视觉效果更加丰富。
Material的使用
我们可以看看官方API中给的example
// Create a color material with fromType:
polygon.material = Cesium.Material.fromType('Color');
polygon.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
// Create the default material:
polygon.material = new Cesium.Material();
// Create a color material with full Fabric notation:
polygon.material = new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: new Cesium.Color(1.0, 1.0, 0.0, 1.0)
}
}
});
上述的示例中,一共有两种使用Material类的使用方法
1.Cesium.Material.fromType('Color')
let material = Cesium.Material.fromType('Color',{
color:new Cesium.Color(1.0, 1.0, 0.0, 1.0)
})
2.new Cesium.Material()
let material = new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: new Cesium.Color(1.0, 1.0, 0.0, 1.0)
}
}
});
这种方法直接传入一个fabric(fabric 是对材质描述json对象)。此方法适用于创建一个新材质,代码虽然冗长,但是灵活性最高。
Fabric拥有5个属性:
1.type:用于声明fabric对象最终会生成什么材质。若是之前没有指定过,则第一次调用new Cesium.Material(),这个新材质会被缓存,可以之后从缓存中取用
2.uniforms:拥有若干个uniform的全局变量,可以在渲染前传入,也可以在渲染后修改
3.source:glsl 源代码,它主要是对 czm_getMaterial 这个函数(Cesium 内置的 glsl 函数)的实现,返回值是 czm_material,实现自定义渲染效果
4.components:几个基本材质因子的 glsl 代码快捷入口,是 source 的一种简略实现,可以通过修改子因素直接改变材质的渲染结果
5.materials:允许再塞进去子一级的 fabric,构成复合材质
Material内部构成
1.Uniforms
uniforms是传入着色器Source中的一些全局变量,因为Source是GLSL源代码,所以数据类型会有些区别。统一值,用于向着色器内传递数据。
比较常用的比如:
1.float:浮点数
2.vec {2, 3, 4} :长度为2,3,4的float向量
3.sampler2D:访问一个二维纹理,s轴和t轴垂直大小在0到1之间,(0, 0)在左下角
2.Source 材质着色器代码
Source为glsl 源代码,它主要是对 这个Cesium 内置的 glsl 函数的实现,返回值是 czm_material,实现自定义渲染效果
默认情况下,材质Source的默认函数实现为:
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
return material;
}
其中,czm_materialInput
结构体为:
struct czm_materialInput
{
float s;
vec2 st;
vec3 str;
mat3 tangentToEyeMatrix;
vec3 positionToEyeEC;
vec3 normalEC;
};
czm_materialInput
结构体在源码Shaders/Builtin/Structs/materialInput.js中定义,用于存储输入的纹理坐标,法线等数据。它包含了6个属性,分别为:
czm_material
结构体为:
struct czm_material
{
vec3 diffuse;
float specular;
float shininess;
vec3 normal;
vec3 emission;
float alpha;
};
czm_material
结构体在源码Shaders/Builtin/Structs/material.js中定义,用于存储Material着色器计算的结果。它包含了6个属性,其中diffuse为渲染返回的最基本的颜色,其他属性分别为:
Cesium内置材质
Cesium官方网站 可以查看,内置材质共计23种。列举两个比较常用的:
Color材质的Source源码:
uniform vec4 color_0;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
material.diffuse = czm_gammaCorrect(color_0.rgb);
material.alpha = color_0.a;
return material;
}
通过GLSL函数这段代码首先声明变量,用于接收我们上述提到的uniforms传递的数据(这些变量会自动添加一个序号,在Appearance中使用时也要添加这个序号)。
然后定义czm_getMaterial方法,方法的参数materialInput
是一个czm_materialInput 类型
,方法内部通过materialInput
作为输入参数又调用了Cesium内置算法进行计算,将rgb值传给material.diffuse,将alpha值传给material.alpha最终将计算结果存储到czm_material类型的变量material
中作为返回值。
Image材质的Source为:
uniform vec4 color_2;
uniform vec2 repeat_1;
uniform sampler2D image_0;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
material.diffuse = czm_gammaCorrect(texture2D(image_0, fract(repeat_1 * materialInput.st)).rgb * color_2.rgb);
material.alpha = texture2D(image_0, fract(repeat_1 * materialInput.st)).a * color_2.a;
return material;
}
通过GLSL代码可以看出,Image材质的渲染逻辑就是传入一个图片纹理,根据纹理坐标采样图片纹理上的rgb值,还可以混合一个颜色值,将值赋予给material.diffuse,最后返回material
texture2D函数是webgl内置函数,传入两个参数,一个是图片,一个是纹理坐标
动态扩散圆示例
new Cesium.Material({
fabric: {
uniforms: {
color: Cesium.Color.fromCssColorString('#00E8FF'),
time: 10
},
source:`czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
material.diffuse = 1.5 * color.rgb;
vec2 st = materialInput.st;
float dis = distance(st, vec2(0.5, 0.5));
float per = fract(czm_frameNumber * time / 1000.0);
if(dis > per * 0.5) {
material.alpha = 0.0;
discard;
}else{
material.alpha = color.a * dis / per / 1.0;
}
return material;
}`
}
})
分析代码:
material.diffuse = 1.5*color.rgb
:控制的效果是这个颜色的亮度。把1.5改成0.5它会明显变得更暗。如果把1.5改成3或者6,明显可以看到颜色更亮了
materialInput.st
:整个画布的二维纹理坐标,vec2类型,第一个值是水平方向,如果是线,则为沿线方向,第二个值是垂直方向
dis
:扩散中心,从哪个位置开始扩散的。如果改成distance(st, vec2(0.0, 0.5),那么它扩散的中心就变成了下方中点
czm_frameNumber
:这个是当前渲染的帧数
fract()
:获取小数部分
discard
:关键词在opengl中是片段截取的意思,相当于这一块不要了
Appearance构成
我们已MaterialAppearance为例,MaterialAppearance构造函数如下:
1.flat
:平面着色,不考虑光照,当设置为true时,着色器就不使用光照计算,而去使用平面着色。
2.material
:使用Cesium内置的材质进行着色计算。
3.vertexShaderSource
:顶点着色器
4.fragmentShaderSource
:片元着色器
下一篇节我们着重讲解一下vertexShaderSource
顶点着色器与fragmentShaderSource
片元着色器。