通过BoxGeometry探索Cesium中的坐标变换
Cesium中有两种对象可以添加到场景中,Entity
、Primitive
。Entity
对用户更友好,方便使用,但是灵活性和性能差一些。Primitive
,支持自定义几何形状和几何对象的材质,可以实现更复杂的效果。
添加Primitive
为了减少需要阅读的代码量,方便调试,将primitive的asynchronous
,translucent
设置为false
,即同步方式加载Box,几何材质为不透明。
viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances:instance,
appearance:aper,
asynchronous:false,
translucent:false
})
)
Cesium中内置的几何体需要通过GeometryInstance
方式代理,进行渲染。下面从BoxGeometry
开始查看坐标变换流程。
BoxGeometry.fromDimensions
通过fromDimensions
方法创建BoxGeometry
。创建的Box默认原点在立方体中心,且该立方体为轴对称,BoxGeometry实例对象通过记录立方体的最大坐标,最小坐标用来计算每个顶点的坐标位置。如,当Dimensions为Cesium.Cartesian3(20,15,10)
时,BoxGeometry记录两个坐标minimum,maximum
,依次为(-10,-7.5,-5),(10,7.5,5)
。
Primitive
几何对象和材质创建好后,接下来创建Primitvie
对象。Primitvie
构造函数中,设置该实例的相关属性。几何对象的顶点构造在update
方法中实现。
Primitive.update
方法
update方法中实现每个顶点位置的计算。上面为了调试看代码方便,异步加载设置为false
。这里重点看loadSynchronous
方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfWeP1UV-1644028669557)(images\image-20220203110048744.png)]
loadSynchronous
方法中,当几何体第一次更新时,调用geometry.constructor.createGeometry(geometry)
,对于BoxGeometry
来说就是调用BoxGeometry.createGeometry
方法来计算几何体的顶点、索引、包围球等。
之后调用PrimitivePipeline.combineGeometry
方法。其中针对scene3DOnly
分两种情况
scene3DOnly == true
当只渲染三维场景时,几何体的顶点坐标为几何体的本地坐标,即几何体中心为坐标原点,东北上指定坐标轴,同时modelMatrix
将本地坐标变换为世界坐标。
scene3DOnly == false
当渲染二、三维场景时,通过调用GeometryPipeline.transformToWorldCoordinates()
方法,将模型本地坐标变换为世界坐标,同时将geometryInstance
的modelMatrix
设置为单位矩阵,此时已经无法访问模型本地坐标。
设置attributes
模型坐标变换完成后,后续设置geometry
的attribute
,对position
来说,通过将double拆分为高低位两个部分,来保证数据在GPU中的计算精度,即将position
替换为position3DHigh
和position3DLow
两个varying变量。其他浮点类型也类似进行拆分,替换。
使用模型本地坐标
通过将scene3DOnly
设置为true
即可通过position3DHigh
、position3DLow
访问模型本地坐标。
通过构造MaterialAppearance
,在vertexShaderSource
中即可访问到模型本地坐标,如下代码中的wc_p
为模型本地坐标。
attribute vec3 position3DHigh;
attribute vec3 position3DLow;
attribute vec3 normal;
attribute vec2 st;
attribute float batchId;
varying vec3 v_positionEC;
varying vec3 v_normalEC;
varying vec2 v_st;
varying vec3 wc_p;
void main()
{
vec4 p = czm_computePosition();
wc_p=position3DHigh+position3DLow; //模型本地坐标
v_positionEC = (czm_modelViewRelativeToEye * p).xyz; // position in eye coordinates
v_normalEC = czm_normal * normal; // normal in eye coordinates
v_st = st;
vec3 cameraPos=czm_encodedCameraPositionMCHigh+czm_encodedCameraPositionMCLow;
gl_Position = czm_modelViewProjectionRelativeToEye * p;
}
通过将模型本地坐标归一化后,就可以得到如下效果,可以明显看到沿对角线,从黑色过渡到白色:
其他效果
拿到本地坐标后,就可以开始做一些效果了:
坑
最后一个效果中,发现部分面有破面情况,看起来是一个面有多个三角形的样子,设置appearance
的close
属性也没有解决,貌似没也有剔除背面。
看下图,shader中alpha分量设置为1.0,而且translucent也设置为了false,但是仍有混合现象。留个坑后面再看看吧。