Cesium中的BoxGeometry渲染流程,及模型本地坐标

5 篇文章 3 订阅
5 篇文章 4 订阅

通过BoxGeometry探索Cesium中的坐标变换

Cesium中有两种对象可以添加到场景中,EntityPrimitiveEntity对用户更友好,方便使用,但是灵活性和性能差一些。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()方法,将模型本地坐标变换为世界坐标,同时将geometryInstancemodelMatrix设置为单位矩阵,此时已经无法访问模型本地坐标。

设置attributes

模型坐标变换完成后,后续设置geometryattribute,对position来说,通过将double拆分为高低位两个部分,来保证数据在GPU中的计算精度,即将position替换为position3DHighposition3DLow两个varying变量。其他浮点类型也类似进行拆分,替换。

使用模型本地坐标

通过将scene3DOnly设置为true即可通过position3DHighposition3DLow访问模型本地坐标。

通过构造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;
  }

通过将模型本地坐标归一化后,就可以得到如下效果,可以明显看到沿对角线,从黑色过渡到白色:

在这里插入图片描述

其他效果

拿到本地坐标后,就可以开始做一些效果了:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

最后一个效果中,发现部分面有破面情况,看起来是一个面有多个三角形的样子,设置appearanceclose属性也没有解决,貌似没也有剔除背面。

看下图,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中写的不对,有时间再改改。

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在Cesium获取模型实时坐标,可以使用以下步骤: 1. 加载模型。可以使用Cesium的Model类加载模型,代码示例如下: ``` var viewer = new Cesium.Viewer('cesiumContainer'); var model = viewer.scene.primitives.add(Cesium.Model.fromGltf({ url : 'path/to/model.gltf' })); ``` 2. 在顶点着色器解算模型坐标。要在顶点着色器获取模型坐标,需要先在JavaScript代码获取模型实例对象,并将其传递给顶点着色器使用。代码示例如下: ``` var modelMatrix = model.modelMatrix; var modelNormalMatrix = Cesium.Matrix3.transpose(Cesium.Matrix3.inverse(modelMatrix, new Cesium.Matrix3()), new Cesium.Matrix3()); model.vertexShaderSource = '\ attribute vec3 position;\ attribute vec3 normal;\ attribute vec2 st;\ varying vec3 v_position;\ varying vec3 v_normal;\ varying vec2 v_st;\ uniform mat4 u_modelMatrix;\ uniform mat3 u_modelNormalMatrix;\ void main() {\ v_position = vec3(u_modelMatrix * vec4(position, 1.0));\ v_normal = normalize(u_modelNormalMatrix * normal);\ v_st = st;\ gl_Position = czm_modelViewProjection * vec4(v_position, 1.0);\ }\ '; model.uniforms = { u_modelMatrix : modelMatrix, u_modelNormalMatrix : modelNormalMatrix }; ``` 在上述代码,使用了Cesium的Matrix3和Matrix4类对模型矩阵进行了处理,然后将处理后的矩阵传递给了顶点着色器的uniform变量。在顶点着色器,使用u_modelMatrix和u_modelNormalMatrix对顶点进行了变换,从而获取了模型坐标。 注意,上述代码使用了Cesium的内置变量czm_modelViewProjection,它是Cesium的一个变换矩阵,用于将模型坐标转换为屏幕坐标。使用该变量可以确保在不同的场景都能正确地显示模型。 希望这些代码示例能够帮助你在Cesium获取模型实时坐标

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值