Cesium高级教程-后处理体积云-后处画一个Box
Box 盒子
前面我们说了,局部体积云一般是在一个Box
内进行渲染,所以我们要先知道如何在后处理中绘制一个Box
。
首先我们回想一下使用Geometry
绘制一个Box
的需要哪些信息,一般需要知道Box
的坐标原点
,然后是Box
的大小信息(长、宽、高
),我们先假定Box
的坐标为(-75.59670696331766, 40.0387958759308, 90.62678445553416
),长宽高都为20
。
let position=Cesium.Cartesian3.fromDegrees(-75.59670696331766, 40.0387958759308, 90.62678445553416);
let entity = new Cesium.Entity({
position:position,
box:{
dimensions: new Cesium.Cartesian3(20.0, 20.0, 20.0),
material:Cesium.Color.BLUE,
}
})
viewer.entities.add(entity);
后处理画一个 Box
在后处理中要绘制一个类型的Box
,我的思路是这样的:首先以Box
中心点建立一个局部坐标系,每个片元还原到世界坐标,然后转到这个局部坐标系,通过判断坐标值的大小就可以判断这个片元是否在该Box
内,如果在Box
内,就设置颜色为蓝色,在外不进行任何处理。
您也可以按照自己的思路先想一下是否有其他方式
我们按照思路编写代码,因为要转坐标系,首先我们通过Box
的原点坐标建立一个局部坐标系
//矩阵
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
//逆矩阵
let inverse = Cesium.Matrix4.inverse(transform, new Cesium.Matrix4());
然后将次坐标系信息传入后处理着色器,着色器中每个片元坐标先还原为世界坐标,然后转到该坐标系下,最后进行坐标数值比较。
let shader=`
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
in vec2 v_textureCoordinates;
uniform mat4 inverse;
void main(){
out_FragColor = texture(colorTexture, v_textureCoordinates);
vec4 rawDepthColor = texture(czm_globeDepthTexture, v_textureCoordinates);
float depth = czm_unpackDepth(rawDepthColor);
if (depth == 0.0) {
depth = 1.0;
}
vec4 eyeCoordinate4 = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
vec3 eyeCoordinate3 = eyeCoordinate4.xyz/eyeCoordinate4.w;
vec4 worldCoordinate4 = czm_inverseView * vec4(eyeCoordinate3,1.) ;
...
if(local.x>-20.&&local.x<20.&&local.y>-20.&&local.y<20.&&local.z>-20.&&local.z<20.){
out_FragColor=vec4(0.,0.,1.,1);
}
}
`;
let stage = new Cesium.PostProcessStage({
fragmentShader: shader,
uniforms: {
inverse: inverse
}
});
在代码中,我们将位于Box
内的片元都设置为蓝色,运行代码看看结果
示例效果可到 xt3d 官网 运行查看
从运行结果中我们可以看到,虽然在Box
范围内的片元被设置成了蓝色,但是并没有出现一个像上面那样立体
的Box
,这是因为后处理就是一副画,这是一个二维的概念,所以肯定没有立体的效果。但是如果又想要立体的效果呢?是不是没有办法呢?您也可以先试想一下,先不着急看下面。
后处理立体Box
要实现立体效果,其实我们只需要将这个Box
所遮蔽的片元设置为蓝色即可,这里就涉及到一个重要的知识,Box
所遮蔽的片元如何求取?
求取方式为:相机到片元(世界坐标)的射线与Box
如果有交点,那么该片元就被遮蔽,所以问题转为相机到片元的射线和Box求交,射线和Box求交有很多算法,这里采用AABB
的方式,shader
代码如下:
//边界框最小值 边界框最大值
float2 rayBoxDst(float3 boundsMin, float3 boundsMax,
//世界相机位置 光线方向倒数
float3 rayOrigin, float3 invRaydir)
{
float3 t0 = (boundsMin - rayOrigin) * invRaydir;
float3 t1 = (boundsMax - rayOrigin) * invRaydir;
float3 tmin = min(t0, t1);
float3 tmax = max(t0, t1);
float dstA = max(max(tmin.x, tmin.y), tmin.z); //进入点
float dstB = min(tmax.x, min(tmax.y, tmax.z)); //出去点
...
return float2(dstToBox, dstInsideBox);
}
如果 distA&&(distA<distB)
则有交点,否则没有交点,加入代码测试
let shader=`
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
in vec2 v_textureCoordinates;
uniform mat4 inverse;
vec4 rayBoxDst(vec3 boundsMin, vec3 boundsMax, vec3 rayOrigin, vec3 invRaydir)
{
vec3 t0 = (boundsMin - rayOrigin) * invRaydir;
vec3 t1 = (boundsMax - rayOrigin) * invRaydir;
vec3 tmin = min(t0, t1);
vec3 tmax = max(t0, t1);
float dstA = max(max(tmin.x, tmin.y), tmin.z); //进入点
float dstB = min(tmax.x, min(tmax.y, tmax.z)); //出去点
...
return vec4(dstToBox, dstInsideBox,dstA,dstB);
}
void main(){
out_FragColor = texture(colorTexture, v_textureCoordinates);
vec4 rawDepthColor = texture(czm_globeDepthTexture, v_textureCoordinates);
float depth = czm_unpackDepth(rawDepthColor);
if (depth == 0.0) {
depth = 1.0;
}
vec4 eyeCoordinate4 = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
vec3 eyeCoordinate3 = eyeCoordinate4.xyz/eyeCoordinate4.w;
vec4 worldCoordinate4 = czm_inverseView * vec4(eyeCoordinate3,1.) ;
vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;
vec4 worldPos= inverse * vec4(worldCoordinate,1.);
vec4 cameraPos= inverse * vec4(czm_viewerPositionWC,1.);
vec3 vDirection=worldPos.xyz-cameraPos.xyz;//方向
vec3 rayDir = normalize( vDirection );
vec3 dim= vec3(20.,20.,20.);//盒子长宽高
vec3 box_min = vec3(0.) - dim / 2.;
vec3 box_max = vec3(0.) + dim / 2.;
vec4 bounds =rayBoxDst(box_min,box_max,cameraPos.xyz,1.0 / rayDir);
...; //盒子外
out_FragColor=vec4(0.,0.,1.,1.);
}
`;
这样看起来Box
就有立体感了
示例效果可到 xt3d 官网 运行查看
移动场景您会发现俩个问题,一是遮蔽关系,二是边界锯齿严重。遮蔽关系是因为我们没有进行任何处理,边界锯齿是因为数据精度问题,此时因为范围很小,所以会比较明显。
更多内容见 Cesium高级教程-教程简介