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. 将剪裁平面数据打包成浮点数的数组 _float32ViewpackPlanesAsFloats()// 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 Formfloat 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 pixelfloat 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;}
}