# CustomShader

#### new Cesium.CustomShader(options)
MapGIS/Material/CustomShader.js 351

自定义着色器对象，允许自定义M3D缓存图层的顶点着色器和片元着色器代码

Name | Type | Description
--- | --- | ---
`options` | Object | optional 初始化参数
Name | Type | Default | Description
--- | --- | --- | ---
`uniforms` | Array | `{}` | optional 传入的uniform变量，类型必须为Cesium.WebGLConstants里的类型， 建议如果是非纹理类型的数据不要使用uniform变量传入，因为uniform变量必须在模型加载时赋值，后面无法修改，如果是想要实时变化， 可以在shader里面实时赋值；注意这里说的uniform变量必须在模型加载时赋值是因为，uniform变量是随着顶点传入webgl中的， 如果要修改必须将模型重新加载，并将数据传入webgl，使用这种方式会导致性能会下降很多；
`varyings` | Array | `{}` | optional 传入的varying变量
`vertexShaderText` | String | `''` | optional 传入的顶点着色器代码，必须重写fragmentMain方法
`fragmentShaderText` | String | `''` | optional 传入的片元着色器代码，必须重写vertexMain方法

##### Example:

    -------------使用viewer.scene.layers.appendM3DLayer添加图层---------------------------
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/2.0/武汉建筑轮廓白/武汉建筑轮廓白.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({})
    });
    -------------使用viewer.scene.layers.appendSceneLayer添加图层---------------------------
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendSceneLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({})
    })
    -------------当数据被切块时，在callback函数中实时更新shader---------------------------
    //M3DServer服务
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //在callback中更新shader
        callback: function() {
            //根据index获取M3D对象
            var tileSet = viewer.scene.layers.getM3DLayer(index);
            //确保对象存在
            if(tileSet) {
                 //更新你的shader
                 tileSet.customShader = new Cesium.CustomShader({})
            }
        }
    });
    //SceneServer服务或G3DServer服务
    var tileSet;
    viewer.scene.layers.appendSceneLayer('http://webclient.smaryun.com:8089/igs/rest/g3d/Scene:DaYanTa-M3D', {
        //在loaded中获取M3D对像
        loaded: function (layer) {
            layerScene = layer;
        },
        //在callback中更新shader
        callback: function() {
            //确保对象存在
            if(layerScene) {
                //更新你的shader
                layerScene.customShader = new Cesium.CustomShader({});
            }
         }
    });
    -------------传入uniform变量---------------------------
    //加载M3D模型
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    //必须在模型初始化时，给uniform变量赋值
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
            //传入uniform变量
            uniforms: {
                //第一个变量
                u_uniform1: {
                    //类型，必须为Cesium.WebGLConstants里的类型
                    type: Cesium.WebGLConstants.FLOAT,
                    //值
                    value: -100.0
                },
                //第二个变量
                u_uniform2: {
                    //类型，必须为Cesium.WebGLConstants里的类型
                    type: Cesium.WebGLConstants.FLOAT,
                    //值
                    value: -100.0
                }
            }
        })
    });
    -------------传入varying变量，并在顶点和片元着色器中使用---------------------------
    //加载M3D模型
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
         //设置自定义着色器
         customShader: new Cesium.CustomShader({
             //传入varying变量
             varyings: {
                 //设置一个变量，注意varying变量仅用于顶点着色器像片元着色器传值，因此没有初始值
                 u_test: {
                     //类型，必须为Cesium.WebGLConstants里的类型
                     type: Cesium.WebGLConstants.FLOAT
                 }
             },
             //顶点着色器代码
             vertexShaderText:
             //在顶点着色器中，将当前顶点的y值赋给u_test
             'void vertexMain(float frameNumber, vec4 oid, inout vec4 position){\n' +
             '  u_test = position.y;\n' +
             '}\n',
             //片元着色器代码
             fragmentShaderText:
             //在片元着色器中，使用u_test的值
             'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //设置渐变颜色
             '   vec4 gradiantColor = vec4(0.0, 0.0, 1.0, 0.0);\n' +
             //获取当前顶点高度，注意这里的高度是相对于模型原点的，具体高度范围请从外包盒中获取
             //该模型地下有34米，为方便计算，抬高34米
             //在这里使用了varying变量
             '   float currentHeight = u_test + 34.0;\n' +
             //颜色从140到0进行渐变
             '   if(currentHeight > 0.0) {\n' +
             '       gradiantColor *= currentHeight / 140.0;\n' +
             //注意改变颜色是加法/减法，改变亮度是乘法
             '       fragColor += gradiantColor;\n' +
             '   }\n' +
             '}\n'
         })
    });
    -------------传入顶点着色器代码---------------------------
    //加载M3D模型
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             //顶点着色器代码
             vertexShaderText:
             //参考1.87以上版本写法，必须重写vertexMain方法
             //frameNumber：帧时间，顶点的oid，position：顶点坐标
             'void vertexMain(float frameNumber, vec4 oid, inout vec4 position){\n' +
              //如果高度超过0米，抬高100米
              '  if(position.y > 0.0) {\n' +
              //抬高100米
              '    position.y += 100.0;\n' +
              '  }\n' +
             '}\n'
        })
    });
    -------------传入片元着色器代码---------------------------
    //加载M3D模型
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             //设置片元着色器代码
             fragmentShaderText:
             //参考1.87以上版本写法，必须重写fragmentMain方法
             //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
             'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //给一个蓝色的覆盖物颜色
             '  fragColor += vec4(0.0, 0.0, 0.3, 0.0);\n' +
             '}\n',
        })
    });
    -------------动态修改着色器---------------------------
    //添加M3D数据
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    //在初始化时，传入uniform变量
    index = viewer.scene.layers.appendM3DLayer(url, {
        duration: 1,
        customShader: new Cesium.CustomShader({
            uniforms: {
                u_testHeight: {
                    type: Cesium.WebGLConstants.FLOAT,
                    value: -100.0
                }
            }
        })
    });
    //获取M3D对象
    var tileSet = viewer.scene.layers.getM3DLayer(index);
    //动态修改片元着色器
    tileSet.customShader = new Cesium.CustomShader({
       fragmentShaderText:
       //参考1.87以上版本写法，必须重写fragmentMain方法
       //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
       'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
        //给一个蓝色的覆盖物颜色
         '  fragColor += vec4(0.0, 0.0, 0.3, 0.0);\n' +
       '}\n'
    });
    //动态修顶点着色器
    tileSet.customShader = new Cesium.CustomShader({
        //顶点着色器代码
        vertexShaderText:
        //参考1.87以上版本写法，必须重写vertexMain方法
        //frameNumber：帧时间，顶点的oid，position：顶点坐标
        'void vertexMain(float frameNumber, vec4 oid, inout vec4 position){\n' +
        //抬高100米
        'position.y += 100.0;\n' +
        '}\n'
    });
    -------------按高度进行颜色渐变---------------------------
    //加载M3D模型
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             fragmentShaderText:
             //参考1.87以上版本写法，必须重写fragmentMain方法
             //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
             'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //设置渐变颜色
             '   vec4 gradiantColor = vec4(0.0, 0.0, 1.0, 0.0);\n' +
             //获取当前顶点高度，注意这里的高度是相对于模型原点的，具体高度范围，请从模型的外包盒中获取
             //此处的最大高度为110，也是从外包盒里获取的
             '   float maxHeight = 110.0;\n' +
              //颜色从maxHeight到0进行渐变
              '   if(position.y > 0.0) {\n' +
              '       gradiantColor *= position.y / maxHeight;\n' +
             //注意改变颜色是加法/减法，改变亮度是乘法
             '       fragColor += gradiantColor;\n' +
             '   }\n' +
             '}\n'
        })
    });
    -------------呼吸灯效果---------------------------
    //加载M3D模型
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             fragmentShaderText:
             //参考1.87以上版本写法，必须重写fragmentMain方法
             //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
             'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //根据当前帧时间(czm_frameNumber)获取周期变化的亮度值，fract即webgl里面的取小数函数
             '   float currentLight = fract(frameNumber / 120.0) * 3.14159265;\n' +
             //根据亮度和高度过去呼吸灯颜色
             '   float breathLampColor = position.y / 320.0 / 2.0 + sin(currentLight) * 0.1;\n' +
             //修改当前颜色
             '   fragColor += vec4(51.0 / 255.0 * breathLampColor, 153.0 / 255.0 * breathLampColor, breathLampColor, 0.0);\n' +
             '}\n'
        })
    });
    -------------光圈效果---------------------------
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/1.0/ZondyFaceModels/ZondyFaceModels.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             fragmentShaderText:
             //参考1.87以上版本写法，必须重写fragmentMain方法
             //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
             'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //获取当前顶点高度，注意这里的高度是相对于模型原点的，具体高度范围，请从模型的外包盒中获取
             //此处的最大高度为110米，最小高度为-34米，也是从外包盒里获取的
             '   float currentHeight = position.y + 34.0;\n' +
             //根据当前帧时间(czm_frameNumber)，获取当前顶点所处的周期
             '   float time = fract(frameNumber / 360.0);\n' +
             //获取当前高度占整体高度的百分比，0到1之间的值
             //clamp参考https://learn.microsoft.com/zh-cn/previous-versions/hh308289(v=vs.120)
             '   currentHeight = clamp(currentHeight / (110.0 + 34.0), 0.0, 1.0);\n' +
             //处理周期
             '   time = abs(time - 0.5) * 2.0;\n' +
             //根据高度和周期计算光圈
             '   float circle = step(0.005, abs(currentHeight - time));\n' +
             //更新颜色
             '   fragColor.rgb += fragColor.rgb * (1.0 - circle);\n' +
             '}\n'
        })
    });
    -------------渐变+光圈+高亮---------------------------
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/2.0/武汉建筑轮廓白/武汉建筑轮廓白.mcj';
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             fragmentShaderText:
             //参考1.87以上版本写法，必须重写fragmentMain方法
             //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
             'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //获取当前顶点高度，注意这里的高度是相对于模型原点的，具体高度范围，请从模型的外包盒中获取
             //这份数据最低点距离制图原点有180米，最高点离原点有140米，因此加上180，使最小值为0
             '   float currentHeight = position.y + 180.0;\n' +
             //更新渐变颜色
             '   fragColor += vec4(51.0 / 255.0, 153.0 / 255.0, 1.0, 1.0) * currentHeight / 320.0;\n' +
             //高度在260到320之间，增加高亮
             '   if(currentHeight > 260.0) {\n' +
             '       fragColor *= 1.0 + 0.75 * (currentHeight - 260.0) / 60.0;\n' +
             '   }\n' +
             //根据当前帧时间(czm_frameNumber)，获取当前顶点所处的周期
             '   float time = fract(frameNumber / 360.0);\n' +
             //获取当前高度占整体高度的百分比，0到1之间的值
             //clamp参考https://learn.microsoft.com/zh-cn/previous-versions/hh308289(v=vs.120)
             '   currentHeight = clamp(currentHeight / 320.0, 0.0, 1.0);\n' +
             //处理周期
             '   time = abs(time - 0.5) * 2.0;\n' +
             //根据高度和周期计算光圈
             '   float circle = step(0.005, abs(currentHeight - time));\n' +
             //更新颜色
             '   fragColor.rgb += fragColor .rgb * (1.0 - circle);\n' +
             '}\n'
        })
    });
    -------------通过OID进行高亮---------------------------
    //注意必须是M3D2.0数据，且带有OID
    var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D//2.0/M3DAttributeTest_BIN/zondy.mcj';
    //指定一个OID，并将其转为颜色
    var id = Cesium.Color.fromRgba(511);
    //拼装相关shader代码，数值为float类型
    var OIDToColor = "";
    if(id.red.toString().indexOf('.') < 0) {
        OIDToColor += id.red + '.0';
    }else {
        OIDToColor += id.red;
    }
    OIDToColor += ',';
    if(id.green.toString().indexOf('.') < 0) {
        OIDToColor += id.green + '.0';
    }else {
        OIDToColor += id.green;
    }
    OIDToColor += ',';
    if(id.blue.toString().indexOf('.') < 0) {
        OIDToColor += id.blue + '.0';
    }else {
        OIDToColor += id.blue;
    }
    OIDToColor += ',';
    if(id.alpha.toString().indexOf('.') < 0) {
        OIDToColor += id.alpha + '.0';
    }else {
        OIDToColor += id.alpha;
    }
    index = viewer.scene.layers.appendM3DLayer(url, {
        //设置自定义着色器
        customShader: new Cesium.CustomShader({
             fragmentShaderText:
             //参考1.87以上版本写法，必须重写fragmentMain方法
             //position：顶点坐标，frameNumber：帧时间，顶点的oid，fragColor：顶点颜色
              'void fragmentMain(vec4 position, float frameNumber, vec4 oid, inout vec4 fragColor){\n' +
             //设置外部传入的OID
             '   vec4 outOID = vec4(' + OIDToColor + ');\n' +
             //与当前OID相减
             '   vec4 oidResult =  oid.rgba - outOID.rgba; \n' +
             //相减后的rgba值小于0.0039(相当于1/255)，就认为是一样的id
             '   if(abs(oidResult).r < 0.0039 && abs(oidResult).g < 0.0039 && abs(oidResult).b < 0.0039 && abs(oidResult).a < 0.0039){' +
             //oid相同，改变颜色
             '       fragColor.r += 1.0;' +
             '   }' +
             '}\n'
        })
    });