Cesium 中的Shader解析1

20 篇文章 0 订阅
18 篇文章 6 订阅

一、简介

Cesium中在创建点、线、面、球等Geometry的时候,可以动态指定材质。材质用于设置物体的外观。通常修改材质的片元着色器来改变外观。

在Cesium源码中有许多内置材质,比如最常用的Color和Image等。

材质的创建有两种方式,快捷方式和原始方式。下面的例子为多边形设置颜色材质,两种写法具有相同效果。

polygon.material = Material.fromType('Image');
polygon.material.uniforms.image = 'image.png';

或者:

polygon.material = new Cesium.Material({
  fabric : {
    type : 'Image',
    uniforms : {
      image : 'image.png'
    }
  }
});

fabric是Cesium自己定义的一种写材质的一种语法,就是个json,不具体说这个,这个可以去查文档。

二、GLSL

 最灵活的一中定义材质的方式是写GLSL,为Fabric指定source属性,在cesium源码中会读取source并加工合并到最终的着色器中进行图形绘制。

struct czm_materialInput
{
  float s;
  vec2 st;
  vec3 str;
  mat3 tangentToEyeMatrix;
  vec3 positionToEyeEC;
  vec3 normalEC;
};

struct czm_material
{
  vec3 diffuse;
  float specular;
  float shininess;
  vec3 normal;
  vec3 emission;
  float alpha;
};

czm_material czm_getMaterial(czm_materialInput materialInput);

最简单的定义如下,这是直接返回默认的材质属性,这也是我们写shader的切入点,可以传入uniforms变量,可以从纹理中获取原色,也结合时间变化来动态修改材质等等。

在source中我们可以使用webgl的内置函数,比如step,fract等等,也可直接使用cesium内置函数、变量、结构体等,比如czm_xxxx等。

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

三、一个面

下面的代码是大家都熟悉的内容,就是定义个primitive,在三维球上添加一个矩形rectangle。

function createPrimitives(scene) {
            rectangle = scene.primitives.add(
                new Cesium.Primitive({
                    geometryInstances: new Cesium.GeometryInstance({
                        geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(116, 39, 117, 39.7),

                // EllipsoidSurfaceAppearance.VERTEX_FORMAT = Cesium.VertexFormat.POSITION_AND_ST;
                            vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
                        })
                    }),
                    appearance: new Cesium.EllipsoidSurfaceAppearance({
                        aboveGround: false
                    })
                })
            )
        }

 尝试修改其材质,为这个矩形贴上一个图片纹理。

其中一句关键代码如下,texture2D函数是webgl内置函数,传入两个参数,一个是图片,一个是纹理坐标。

图片是在uniforms中定义的变量【image: './sky.JPG'】。纹理坐标是二维的平面坐标,s轴和t轴垂直大小在0到1之间,(0,0)在左下角。

material.diffuse=texture2D(image,materialInput.st).rgb;

这句代码就是获取图片纹素颜色,然后把颜色值给材质的漫反射分量,漫反射代表了材质的颜色,类型是vec3。除了漫反射,还有镜面反射、自发光、高光系数等等,

这些都属于光照系统,用于最终确定材质颜色,具体可以了解一下phong模型,是一种局部光照模型。

rectangle.appearance.material = new Cesium.Material({
                fabric: {
                    uniforms: {
                        image: './sky.JPG',
                        alpha: 1.0,
                    },
                    source: /* glsl */ `
                        czm_material czm_getMaterial(czm_materialInput materialInput){
                            czm_material material=czm_getDefaultMaterial(materialInput);
                            material.diffuse=texture2D(image,materialInput.st).rgb;
                            return material;
                        }
                    `
                }
            })

 四、再修改面

把中间的和外面的挖掉,就成了下面的样子。关键代码

float dis=distance(center,materialInput.st);

distance是webgl内置函数,用于计算距离。知道这一点,代码就很容易理解了。
rectangle.appearance.material = new Cesium.Material({
                fabric: {
                    uniforms: {
                        image: './sky.JPG',
                        alpha: 1.0,
                    },
                    source: /* glsl */ `
                        czm_material czm_getMaterial(czm_materialInput materialInput){
                            czm_material material=czm_getDefaultMaterial(materialInput);
                            material.diffuse=texture2D(image,materialInput.st).rgb;
                            material.alpha=alpha;
                            vec2 center=vec2(0.5,0.5);            
                            float dis=distance(center,materialInput.st);
                            if(dis>0.25){
                                material.diffuse=vec3(1.0,0.0,0.0);
                            }
                            if(dis<0.1){
                                material.diffuse=vec3(1.0);
                            }
                            return material;
                        }
                    `
                }
            })

五、动态墙

没有什么新知识,主要是给uniforms传入了时间t,用于生成动态效果,这不是最优雅的一种方式,后续再说。

wall = new Cesium.Primitive({
                geometryInstances: [
                    greenWallInstance,
                ],
                appearance: new Cesium.MaterialAppearance({
                        material: Cesium.Material.fromType('Color'),
                        faceForward: true
                    })
            })
            wall.appearance.material = new Cesium.Material({
                fabric: {
                    uniforms: {
                        color: 'vec3(1.0,1.0,0.0)',
                        alpha: 1.0,
                        image: './abc.png',
                        image2: './sky.JPG',
                        t: 0.0
                    },
                    source: /* glsl */ `
                    czm_material czm_getMaterial(czm_materialInput materialInput){
                        czm_material material=czm_getDefaultMaterial(materialInput);
                        material.diffuse=vec3(1.0,1.0,0.0);                                              
                        // material.alpha=fract(1.0-materialInput.st.s+t);
                        material.alpha=mod(1.0-materialInput.st.s+t,1.0);
                        return material;
                    }
                    `
                }
            })
            setInterval(() => {

                wall.appearance.material.uniforms.t += 0.1;

                if (wall.appearance.material.uniforms.t > 1.0) {

                    wall.appearance.material.uniforms.t = 0.0;

                }



            }, 200);
 

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苹果园dog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值