Cesium中的BoxGeometry渲染流程,及模型本地坐标
通过BoxGeometry探索Cesium中的坐标变换Cesium中有两种对象可以添加到场景中,Entity、Primitive。Entity对用户更友好,方便使用,但是灵活性和性能差一些。Primitive,支持自定义几何形状和几何对象的材质,可以实现更复杂的效果。添加Primitive为了减少需要阅读的代码量,方便调试,将primitive的asynchronous,translucent设置
通过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,但是仍有混合现象。留个坑后面再看看吧。
更新
Sandcastle中粘贴如下代码可运行查看效果:
var viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
selectionIndicator: true,
shadows: true,
shouldAnimate: true,
scene3DOnly:true
});
viewer.scene.logarithmicDepthBuffer = true;
var geometry = Cesium.BoxGeometry.fromDimensions({
vertexFormat: Cesium.VertexFormat.POSITION_AND_NORMAL,
dimensions: new Cesium.Cartesian3(20.0, 15.0, 10.0),
});
var instance = new Cesium.GeometryInstance({
geometry: geometry,
modelMatrix: Cesium.Matrix4.multiplyByTranslation(
Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(
124.21936679679918,
45.85136872098397
)
),
new Cesium.Cartesian3(0.0, 0.0, 80.0),
new Cesium.Matrix4()
),
id: "lsh",
});
var material=new Cesium.Material({
fabric:{
uniforms:{
u_time:0.0
}
},
translucent:true
});
var aper = new Cesium.MaterialAppearance({
fragmentShaderSource: `
varying vec3 v_positionEC;
varying vec3 v_normalEC;
varying vec2 v_st;
varying vec3 wc_p;
void main()
{
vec3 positionToEyeEC = -v_positionEC;
vec3 normalEC = normalize(v_normalEC);
#ifdef FACE_FORWARD
normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);
#endif
vec3 wc_p_lxs=wc_p/vec3(10.0,7.5,5.0);
wc_p_lxs=(wc_p_lxs+1.0)/2.0;
float lxs_z=fract(wc_p_lxs.z-u_time_0);
gl_FragColor = vec4(vec3(0.,0.5,.9),lxs_z);
}
`,
vertexShaderSource: `
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;
}`,
closed:false
});
var lxs=viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instance,
appearance: aper,
asynchronous:true,
})
);
lxs.appearance.material=material;
viewer.camera.lookAt(new Cesium.Cartesian3.fromDegrees(124.21936679679918,
45.85136872098397, 80),new Cesium.Cartesian3(-115,12,0));
viewer.scene.preRender.addEventListener(function(s,t){
var elaspTime=Cesium.JulianDate.now().secondsOfDay/10.0;
lxs.appearance.material.uniforms.u_time=elaspTime;
});
之后发现,破面应该是shader中写的不对,有时间再改改。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)