在线预览
Demo 源码
在新版本的 Cesium(1.87.0),反对了 CustomShader,能够为 Cesium3DTileset 编写自定义的 GLSL 代码。在此之前,要批改 3D Tileset 的款式,只能通过 style 属性,能做的最多也就是依据高度使不同修建展现不同色彩这种水平。
CustomShader 的根底用法能够查看官网文档,这里不再赘述,次要是介绍如何利用 CustomShader 实现修建贴图。
楼顶着色
首先,楼顶不会和周围贴一样的图,先对立解决成深色。
并没有间接的属性表明以后点位于哪块墙上,但浏览文档能够发现,Cesium 提供了 normalMC 属性,也就是这个点所在立体的单位法向量。而楼顶个别是于高空平行的,将其法向量与高空的法向量比拟,如果夹角较小,就能够把它看作楼顶。
FragmentShader 代码如下(normalMC 在片段着色器不可用,须要在顶点着色器中通过 varying 传递过去,这里省略了过程):
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {if (dot(vec3(0.0, 0.0, 1.0), v_normalMC) > 0.95) {material.diffuse = vec3(0.079, 0.107, 0.111);
}
}
对两个向量做 dot(点积),能够失去这两个向量夹角的余弦值,再做反余弦,即可失去夹角,但反余弦操作比较慢,并且这里不须要准确的夹角值,所以对余弦值的大小做判断就行了
楼顶着色残缺代码
周围贴图
解决完楼顶,再解决四个侧面。贴图的要害是确定一个二维坐标,而后间接调用 texture2D 办法获取图片上对应色彩。从视觉上看,Shader 中的 Z 坐标必定是对应图片的纵坐标,问题在于 Shader 中的 X,Y 坐标如何对应到图片的横坐标
其实这里不能应用繁多的 X,Y 坐标,这样做会有很多修建的某个侧面是繁多的色彩,达不到贴图的成果。我最初还是利用了法向量属性,计算他们与 vec3(1.0, 0.0, 0.0) & vec3(0.0, 1.0, 0.0) 的夹角,如果与 vec3(1.0, 0.0, 0.0) 的夹角较小,就应用它的 Y 坐标,反之亦然。
修建 Shader 代码:
const createBuildingShader = () => {
return new Cesium.CustomShader({
lightingModel: Cesium.LightingModel.UNLIT,
varyings: {v_normalMC: Cesium.VaryingType.VEC3},
uniforms: {
u_texture: {
value: new Cesium.TextureUniform({url: '/demos/buildings/wall.png'}),
type: Cesium.UniformType.SAMPLER_2D
}
},
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout vec3 positionMC) {v_normalMC = vsInput.attributes.normalMC;}`,
fragmentShaderText: /* 见下 */ ``
})
}
片段着色器代码:
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
vec3 positionMC = fsInput.attributes.positionMC;
float width = 75.0;
float height = 75.0;
if (dot(vec3(0.0, 0.0, 1.0), v_normalMC) > 0.95) {material.diffuse = vec3(0.079, 0.107, 0.111);
} else {
float textureX = 0.0;
float dotYAxis = dot(vec3(0.0, 1.0, 0.0), v_normalMC);
// cos(45deg) 约等于 0.71
if (dotYAxis > 0.71 || dotYAxis < -0.71) {textureX = mod(positionMC.x, width) / width;
} else {textureX = mod(positionMC.y, width) / width;
}
float textureY = mod(positionMC.z, height) / height;
vec3 rgb = texture2D(u_texture, vec2(textureX, textureY)).rgb;
material.diffuse = rgb;
}
}
最初能够加上一些路线流光,使城市显得更加古代,就是文章结尾的成果了。