共计 1955 个字符,预计需要花费 5 分钟才能阅读完成。
在线预览
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; | |
} | |
} |
最初能够加上一些路线流光,使城市显得更加古代,就是文章结尾的成果了。