Cesium Model 中的剪裁平面 (ClippingPlane)

Cesium Model 中的剪裁平面 (ClippingPlane)

在这里插入图片描述

参考: https://www.cnblogs.com/webgl-angela/p/9197672.html

Cesium Model 中的剪裁平面 (ClippingPlane)

// 相关类:
class ClippingPlaneCollection {}
class ClippingPlane {}

// 剪裁的整体流程:
Model.prototype.update = () => {
  //...

  // 1.剪裁纹理的构建
  updateClippingPlanes()

  // 2.Shader 的构建
  buildDrawCommands()

  // 3.剪裁矩阵的构建
  updateReferenceMatrices();

  //...
}
1、剪裁纹理的构建
ClippingPlaneCollection.prototype.update = () => {
  //...

  // 1. 计算纹理的分辨率, { x: 剪裁平面的数量, y: 2 }
  computeTextureResolution()

  // 2. 创建纹理
  clippingPlanesTexture = new Texture()

  // 3. 将剪裁平面数据打包成浮点数的数组 _float32View
  packPlanesAsFloats()

  // 4.拷贝图片数据 _float32View 到纹理中
  clippingPlanesTexture.copyFrom()

  //...
}
2、Shader 的构建
ModelClippingPlanesPipelineStage.process = () => {
  const uniformMap = {
    model_clippingPlanes: function () {
      return clippingPlanes.texture;
    },
    model_clippingPlanesEdgeStyle: function () {
      const style = Color.clone(clippingPlanes.edgeColor);
      style.alpha = clippingPlanes.edgeWidth;
      return style;
    },
    model_clippingPlanesMatrix: function () {
      return model._clippingPlanesMatrix;
    },
  };
};
3、剪裁矩阵的构建
functin updateReferenceMatrices() {
  // ...

  // 模型空间 转换到 世界空间
  const referenceMatrix = model.modelMatrix;

  // 模型空间 转换到 裁剪平面空间
  const clippingPlanesModelMatrix = model._clippingPlanes.modelMatrix;

  // 世界空间 转换到 视图空间
  clippingPlanesMatrix = Matrix4.multiply(
    context.uniformState.view3D,
    referenceMatrix,
    clippingPlanesMatrix
  );

  // 视图空间 转换到 裁剪平面空间, 在视图空间中调整模型的裁剪平面
  // 由于裁剪平面的定义与模型空间无关,因此即使在视图空间中调整,裁剪平面的功能仍然相同:定义哪些模型部分应该被渲染、哪些部分应该被剔除。
  clippingPlanesMatrix = Matrix4.multiply(
    clippingPlanesMatrix,
    clippingPlanesModelMatrix,
    clippingPlanesMatrix
  );

 // 裁剪平面空间 转换到 视图空间
  model._clippingPlanesMatrix = Matrix4.inverseTranspose(
    clippingPlanesMatrix,
    model._clippingPlanesMatrix
  );

  // ...
}

4、Shader 赏析
/**
 * Transforms a plane.
 *
 * @name czm_transformPlane
 * @glslFunction
 *
 * @param {vec4} plane The plane in Hessian Normal Form.
 * @param {mat4} transform The inverse-transpose of a transformation matrix.
 */
vec4 czm_transformPlane(vec4 plane, mat4 transform) {
    vec4 transformedPlane = transform * plane;
    // Convert the transformed plane to Hessian Normal Form
    float normalMagnitude = length(transformedPlane.xyz);
    return transformedPlane / normalMagnitude;
}

vec4 getClippingPlane(
    highp sampler2D packedClippingPlanes,
    int clippingPlaneNumber,
    mat4 transform
) {
    int pixY = clippingPlaneNumber / CLIPPING_PLANES_TEXTURE_WIDTH;
    int pixX = clippingPlaneNumber - (pixY * CLIPPING_PLANES_TEXTURE_WIDTH);
    float pixelWidth = 1.0 / float(CLIPPING_PLANES_TEXTURE_WIDTH);
    float pixelHeight = 1.0 / float(CLIPPING_PLANES_TEXTURE_HEIGHT);
    float u = (float(pixX) + 0.5) * pixelWidth; // sample from center of pixel
    float v = (float(pixY) + 0.5) * pixelHeight;
    vec4 plane = texture(packedClippingPlanes, vec2(u, v));
    return czm_transformPlane(plane, transform);
}

float clip(vec4 fragCoord, sampler2D clippingPlanes, mat4 clippingPlanesMatrix) {
  // 视图空间的位置
    vec4 position = czm_windowToEyeCoordinates(fragCoord);
    vec3 clipNormal = vec3(0.0);

    // 视图空间的剪裁平面位置
    vec3 clipPosition = vec3(0.0);
    float pixelWidth = czm_metersPerPixel(position);

    float clipAmount = 0.0;
    bool clipped = true;

    for (int i = 0; i < CLIPPING_PLANES_LENGTH; ++i) {
        vec4 clippingPlane = getClippingPlane(clippingPlanes, i, clippingPlanesMatrix);
        clipNormal = clippingPlane.xyz;
        clipPosition = -clippingPlane.w * clipNormal;

        // 计算当前像素位置到裁剪平面的投影距离。这个距离是沿着裁剪平面法线的距离。如果这个距离小于等于0,则意味着像素位于裁剪平面的内部。
        float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;

        clipAmount = max(amount, clipAmount);
        clipped = clipped && (amount <= 0.0);
    }

    if (clipped) {
        discard;
    }
    return clipAmount;
}

void modelClippingPlanesStage(inout vec4 color)
{
    float clipDistance = clip(gl_FragCoord, model_clippingPlanes, model_clippingPlanesMatrix);
    vec4 clippingPlanesEdgeColor = vec4(1.0);
    clippingPlanesEdgeColor.rgb = model_clippingPlanesEdgeStyle.rgb;
    float clippingPlanesEdgeWidth = model_clippingPlanesEdgeStyle.a;

    if (clipDistance > 0.0 && clipDistance < clippingPlanesEdgeWidth) {
        color = clippingPlanesEdgeColor;
    }
}
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cesium,可以使用三种方式来修改模型节点组件的属性,包括比例、旋转、移动等。这三种方式分别是CZML、nodeTransformations和自定义属性。 1. 使用CZML:CZML是一种用于描述Cesium场景的JSON格式。通过使用CZML,可以在模型节点组件定义自定义属性。以下是一个示例代码: ```javascript var czml = [{ "id": "model", "model": { "gltf": "path/to/model.gltf", "nodeTransformations": [{ "node": "nodeName", "scale": { "cartesian": [2.0, 2.0, 2.0] }, "rotation": { "unitQuaternion": [0.0, 0.0, 0.0, 1.0] }, "translation": { "cartesian": [10.0, 10.0, 10.0] } }] } }]; viewer.dataSources.add(Cesium.CzmlDataSource.load(czml)); ``` 2. 使用nodeTransformations:nodeTransformations是Cesium模型节点组件的属性之一,可以通过它来修改模型节点的比例、旋转和移动等属性。以下是一个示例代码: ```javascript var model = viewer.scene.primitives.add(Cesium.Model.fromGltf({ url: 'path/to/model.gltf', modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(0.0, 0.0, 0.0)), nodeTransformations: { 'nodeName': { scale: new Cesium.Cartesian3(2.0, 2.0, 2.0), rotation: Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, Cesium.Math.toRadians(45)), translation: new Cesium.Cartesian3(10.0, 10.0, 10.0) } } })); ``` 3. 使用自定义属性:除了CZML和nodeTransformations,还可以通过自定义属性来修改模型节点组件的属性。以下是一个示例代码: ```javascript var model = viewer.scene.primitives.add(Cesium.Model.fromGltf({ url: 'path/to/model.gltf', modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(0.0, 0.0, 0.0)), customProperties: { 'nodeName': { scale: new Cesium.Cartesian3(2.0, 2.0, 2.0), rotation: Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, Cesium.Math.toRadians(45)), translation: new Cesium.Cartesian3(10.0, 10.0, 10.0) } } })); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值