之前要编辑3DTiles 的shader来实现一些例如压平之类的操作 还需要更改源码
Cesium新版本更新了3Dtiles的自定义着色器 可以直接定义两个着色器并往里面传uniform
新版本添加3dtiles的方式发生了改变 原有的方式不能用了
新版本必须通过fromurl函数进行异步添加
即
async function addTileset(url) {
try {
let tileset = await Cesium.Cesium3DTileset.fromUrl(
url,
{
maximumCacheOverflowBytes: 9368709120,
},
);
return tileset;
} catch (error) {
console.error(`Error creating tileset: ${error}`);
}
}
然后在promise.then 里对tiles进行操作
let tilesetpromise = addTileset(mainJson.RECORDS[i].ModelUrl);
tilesetpromise.then(tileset=> {
tileset.customShader=getShader(tileset)
viewer.zoomTo(tileset);
viewer.scene.primitives.add(tileset);
})
也可以在fromUrl里直接指定customShader 但是我这里要用tiles加载完成之后的一些参数设置uniform 所有在加载完后再指定
getShader函数作用是创建一个customshader
在顶点着色器对点的坐标进行修改时 要转换到相对坐标系下
否则会是一个很大的坐标 精度问题不说 增加z值时也不是垂直向上的
所以要转换到以tiles包围盒中心的相对坐标系下
其实这个点可以自己指定 只要在tiles附近就行
function getShader(tileset) {
let str = getVs();
let center = tileset.boundingSphere.center.clone();
let matrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
let localMatrix = Cesium.Matrix4.inverse(matrix, new Cesium.Matrix4());
console.log(localMatrix, tileset.modelMatrix);
let CustomShader = new Cesium.CustomShader({
uniforms: {
M_LocaltoWorld: {
type: Cesium.UniformType.MAT4,
value: matrix,
},
M_WorldtoLocal: {
type: Cesium.UniformType.MAT4,
value: localMatrix,
},
center: {
type: Cesium.UniformType.VEC3,
value: center,
},
height: {
type: Cesium.UniformType.FLOAT,
value: height,
},
},
vertexShaderText: str,
});
return CustomShader;
}
着色器 对点坐标的操作都要在局部坐标系进行
function getVs() {
let str= `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
vec3 positionMC = vsInput.attributes.positionMC;
//世界坐标转局部
vec4 positionInLocal=M_LocaltoWorld*vec4(positionMC,1.0);
positionInLocal=positionInLocal/positionInLocal.w;
positionInLocal.z+=height;
//转回世界坐标
vec4 positionInWorld=M_WorldtoLocal*positionInLocal;
positionInWorld=positionInWorld/positionInWorld.w;
vsOutput.positionMC=positionInWorld.xyz;
return;
}
`
return str;
}
然后是动态更新uniform的问题了
我尝试直接对height的值进行修改 但是没有用
所以要不用字符串拼凑的方式 要不生成一个新的customshader
我用第二种方式 由于我的场景不止添加了一个tiles 所以要遍历
function addHeight() {
height += 10;
for (let i =0;i<viewer.scene.primitives.length;i++)
{
if(viewer.scene.primitives.get(i) instanceof Cesium.Cesium3DTileset)
{
let tile=viewer.scene.primitives.get(i);
let shader=getShader(tile);
shader.setUniform("height", height);
tile.customShader=shader;
}
}
然后增加高度
有问题 随着height值的增加 模型竟然做的是水平运动 或者高度增加的很少 这与预期完全不符
检查了一下才发现两个变换矩阵写反了 正确的应该是
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
vec3 positionMC = vsInput.attributes.positionMC;
//世界坐标转局部 //这里和下面的写反了
vec4 positionInLocal=M_WorldtoLocal*vec4(positionMC,1.0);
positionInLocal=positionInLocal/positionInLocal.w;
positionInLocal.z+=height;
//转回世界坐标
vec4 positionInWorld=M_LocaltoWorld*positionInLocal;
positionInWorld=positionInWorld/positionInWorld.w;
vsOutput.positionMC=positionInWorld.xyz;
return;
}
改正之后确实高度增加了 但是还是不只是垂直方向的运动 还是有水平方向的运动
发现问题了
vsInput.attributes.positionMC; 并不是直接是世界坐标 这个坐标是做了模型变换的
要把模型坐标转化为世界坐标 增加一个矩阵相乘即可
vec4 positionInLocal=M_WorldtoLocal*czm_model*vec4(positionMC,1.0);
最后转回去的时候要转回模型坐标
vec4 positionInWorld=czm_inverseModel*M_LocaltoWorld*positionInLocal;
着色器为
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
vec3 positionMC = vsInput.attributes.positionMC;
//世界坐标转局部 要将模型坐标转为世界坐标
vec4 positionInLocal=M_WorldtoLocal*czm_model*vec4(positionMC,1.0);
positionInLocal=positionInLocal/positionInLocal.w;
positionInLocal.z+=height;
//转回世界坐标 乘逆矩阵
vec4 positionInWorld=czm_inverseModel*M_LocaltoWorld*positionInLocal;
positionInWorld=positionInWorld/positionInWorld.w;
vsOutput.positionMC=positionInWorld.xyz;
return;
}
`
这样就正确了 只有垂直方向的运动
标签:tileset,positionMC,vec4,positionInWorld,positionInLocal,3DTiles,Cesium,customsha From: https://blog.csdn.net/qq_52254412/article/details/140144775