Cesium自定义材质

材质是用于描述多边形、折线、椭球等对象的外观特征,材质可以是几何对象表面的任一一种着色,可以是贴在其表面的一张图片、也可以是一个纹理或图案。cesium中也提供了一些材质,比如颜色图片棋盘虚线箭头线等。但这些基本是不会满足我们实际开发中的需求,需要自定义材质。使用FabricGLSL可以写脚本新建材质,也可以从现在的材质中派生。

1. Material

Material是用于修改几何对象材质的一个类,在添加几何图形的时候,将设置material属于,用于设置几何对象的材质。如给绘制的线条设置一个颜色,可以使用颜色材质,如下所示:

let line = new Cesium.Entity({
            polyline:new Cesium.PolylineGraphics({
                positions : positions,
                material:Cesium.Color.RED.withAlpha(0.5),
                width:5,
            })
        });

Cesium为我们提供了23种现成的Material类型,可通过Material.fromType方法和Fabric两种方式去获取并设置几何对象材质。如下是通过Material类的两种方式实现着色的示例:

polygon.material = Cesium.Material.fromType('Color');
polygon.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
//Fabric
polygon.material = new Cesium.Material({
    fabric : {
        type : 'Color',
        uniforms : {
            color : new Cesium.Color(1.0, 1.0, 0.0, 1.0)
        }
    }
});

2. Fabric

FabricCesium中用于描述材质的一种JSON规定,使用FabricGLSL可以方便的定义材质。定义一个简单的Fabric对象,需要配置typeuniforms,两个属性,如果需要自定义着色器,需要添加source属性。如下为创建一个简单的Fabric对象:

polygon.appearance.material = new Cesium.Material({
  fabric: {
    type: 'Color',
    uniforms: {
      color: new Cesium.Color(1.0, 0.0, 0.0, 0.5)
    }
  }
})

// 修改颜色
polygon.appearance.material.uniforms.color = Cesium.Color.WHITE

type:用于定义材质的类型,使用的时候可以直接通过Cesium.Material.fromType('type');来指定定义好的材质。设置该参数,可以复用材质,传入一个不存在的 type类型之后,这个材质将被缓存下来。下次调用 new Cesium.Material或者 Material.fromType 就会引用缓存里的材质,不需要再传入Fabric对象。
uniforms:用于定义变量,每个 Material 均可以有 0 ~ N 个 uniform,这个参数在建立时指定,也能够在渲染后修改。其中有一个repeat属性,用于控制图片在水平和垂直方向重复的次数。
components: 该属性包含了 定义了材质外观的子属性。每个子属性是一个GLSL的代码段。该属性值包含了以下几个子属性:

1. diffuse:材质的散射光通道,使用vec3定义了光在所有方向的散射值 。
2. specular:材质的高光属性,定个定义了材质的反射强度。
3. shininess:高反射的锐度,值 越大创建一个更小的高亮光斑。
4. normal:材质的法向属性,使用vec3定义了在视点空间的表面法向量,一般在法向贴图上使用,默认是表面法向量。
5. emission:材质的自发光属性,使用vec3定义了所有方向上灯光发出的颜色。
6. alpha:材质的透明度,使用一个float值 定义。

2.1创建新的材质

创建一个新的材质,只需要设置Fabric,再加上一点点GLSL或者其他材质就可以了。通过source可以指定glsl的代码,如下是返回每个分量的默认值:

czm_material czm_getMaterial(czm_materialInput materialInput)
{
    return czm_getDefaultMaterial(materialInput);
}

Fabric这么定义:

{
  source : 'czm_material czm_getMaterial(czm_materialInput materialInput) { return czm_getDefaultMaterial(materialInput); }'
}

2.2 材质输入

czm_getMaterial函数中有一个czm_materialInput类型的属性,用于设置材质的输入,materialInput 变量在sourcecomponents属性中都可以配置,主要包括以下几个属性:
1.s:一维纹理坐标。
2.st:二维纹理坐标。
3.str:三维纹理坐标。
4. tangentToEyeMatrix:从片元的切线空间转到视点空间的转换矩阵,在法向贴图和凹凸贴图时使用。
5. positionToEyeEC:从片元到视点之间的向量,为了反射和折射计算。向量的模表示了从片元到视点的距离。
6. normalEC:片元在视点空间的单位化后的法向量,在凹凸贴图、反射、折射的时候使用。

2.3 合并材质

Fabric 有个materials属性,它的每个子属性也是Fabric材质。他们的材质可以可以在components或者source中引用。比如一个塑料材质可以通过 DiffuseMapSpecularMap两个材质的合并来模拟。

{
  type : 'OurMappedPlastic',
  materials : {
    diffuseMaterial : {
      type : 'DiffuseMap'
    },
    specularMaterial : {
      type : 'SpecularMap'
    }
  },
  components : {
      diffuse : 'diffuseMaterial.diffuse',
      specular : 'specularMaterial.specular'
  }
};

3自定义Material类

在实际开发中,为了使用方便,往往将一些常用的材质一个一个的封装,需要将其定义成Material类,以方便代码的复用。如下为封装的一个扩散回的代码:

import  * as Cesium from '@/Cesium/Source/Cesium';
import createPropertyDescriptor from "@/Cesium/Source/DataSources/createPropertyDescriptor.js";
import Property from "@/Cesium/Source/DataSources/Property.js";
const source =  "czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
                "{\n" +
                "czm_material material = czm_getDefaultMaterial(materialInput);\n" +
                "material.diffuse = 1.5 * color.rgb;\n" +
                "vec2 st = materialInput.st;\n" +
                "float dis = distance(st, vec2(0.5, 0.5));\n" +
                "float per = fract(time);\n" +
                "if(dis > per * 0.5){\n" +
                "material.alpha = 0.0;\n"+
                "discard;\n" +
                "}else {\n" +
                "material.alpha = color.a  * dis / per / 1.0;\n" +
                "}\n" +
                "return material;\n" +
                "}";
function AnimationPointMaterialProperty(color,duration) {
    Cesium.PolylineTrailLinkMaterialProperty = AnimationPointMaterialProperty;
    Cesium.Material.AnimationPointMaterialType = 'AnimationPoint';
    Cesium.Material.AnimationPointMaterialSource = source;
    Cesium.Material._materialCache.addMaterial(Cesium.Material.AnimationPointMaterialType, {
        fabric: {
            type: Cesium.Material.AnimationPointMaterialType,
            uniforms: {
                color: new Cesium.Color(1.0, 0.0, 0.0, 1),
                time: 0
            },
            source: Cesium.Material.AnimationPointMaterialSource
        },
        translucent: function (material) {
            return true;
        }
    })
    this._definitionChanged = new Cesium.Event();
    this._color = undefined;
    this._colorSubscription = undefined;
    this.color = color;
    this.duration = duration;
    this._time = (new Date()).getTime();
}

Object.defineProperties(AnimationPointMaterialProperty.prototype, {
    isConstant: {
        get: function () {
            return Property.isConstant(this._color);
        },
    },

    definitionChanged: {
        get: function () {
            return this._definitionChanged;
        },
    },

    color: createPropertyDescriptor("color"),
});

AnimationPointMaterialProperty.prototype.getType = function () {
    return "AnimationPoint";
};

AnimationPointMaterialProperty.prototype.getValue = function (time, result) {
    if (!Cesium.defined(result)) {
        result = {};
    }
    result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
    result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
};

AnimationPointMaterialProperty.prototype.equals = function (other) {
    return (
        this === other ||
        (other instanceof AnimationPointMaterialProperty &&
            Property.equals(this._color, other._color))
    );
};
export default AnimationPointMaterialProperty;

3.1 公共方法

在定义自己的AnimationPointMaterialProperty时,需要设置几个公共的方法,分别是:getValue,isConstant,definitionChanged,equals
1.getValue:用来获取某个时间点的特定属性值,包括两个参数:typeresult,分别是用于传递时间点和存储属性值。
2.isConstant:用来判断该属性是否会随时间变化,是一个bool类型。Cesium会通过这个变量来决定是否需要在场景更新的每一帧中都获取该属性的数值,从而来更新三维场景中的物体。如果isConstanttrue,则只会获取一次数值,除非definitionChanged事件被触发。
3.definitionChanged:是一个事件,可以通过该事件,来监听该Property自身所发生的变化,比如数值发生修改。
4.equals:用来检测属性值是否相等。
具体的实例可以在。cgis中预览,后期将添加更多的自定义材质。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容