threejs中通过在material中设置clippingPlanes:[]这个数组来实现局部裁剪,这其中的实现过程不是很清楚。通过解读源码,简单分析实现一下threejs中的裁剪。
场景中添加实体
//这里采用normal(0,-1,0) constant = 2 带代替THREE.Plane();
//...
geometry = new THREE.BoxGeometry(5,5,5)
material = new THREE.RawShaderMaterial({
vertexShader:document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
side:THREE.DoubleSide,
transparent:true,
uniforms:{
u_initNormalValue:{value:new THREE.Vector3(0,-1,0)},
u_originPoint:{value:new THREE.Vector3()},
u_viewNormalMatrix:{value:new THREE.Matrix3()},
u_modelViewMatrix:{value:new THREE.Matrix4()}
}
})
mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
scene.add(mesh1)
requestAnimationFrame中传入法向量和距离
function coplanarPoint( target ) {
// 这里的normal 和contant 分别使用固定值(0,-1,0)和2
return target.copy( normal ).multiplyScalar( - constant );
}
// 获取视图矩阵
const viewMatrix = camera.matrixWorldInverse;
// 获取视图坐标系下的法向量转换矩阵
const viewNormalMatrix = new THREE.Matrix3();
viewNormalMatrix.getNormalMatrix( viewMatrix );
// 获取共面点坐标
const originPoint = material.uniforms.u_originPoint.value;
// 计算视图坐标系下的共面点坐标
const referencePoint = coplanarPoint( originPoint ).applyMatrix4( viewMatrix );
// 获取法向量矩阵在视图坐标系下的值
const normal_ = new THREE.Vector3(0,-1,0);
const normal = normal_.applyMatrix3( viewNormalMatrix ).normalize();
// 计算视图空间下,共面点在该方向上的投影距离
const constant_ = -referencePoint.dot(normal);
// 将值传递给到material
material.uniforms.u_transformedNormal.value = normal;
material.uniforms.u_transformedDistance.value = constant_;
renderer.render(scene,camera);
requestAnimationFrame(animate);
shader处理
//顶点着色器
varying vec3 clippingPosition;
vec4 modelPosition = modelMatrix *vec4(position,1.0);
vec4 viewPosition = viewMatrix * modelPosition;
// 所有计算是在视图空间下进行
clippingPosition =viewPosition.xyz;
//片段着色器
varying vec3 clippingPosition;
uniform vec3 u_transformedNormal;
uniform float u_transformedDistance;
void main(){
vec3 color = vec3(0.0,1.0,0.0);
// 视图空间下,如果mesh片段在该方向上的投影距离大于constant = 2,则丢弃该片段
if(dot( clippingPosition, -u_transformedNormal ) > u_transformedDistance){
discard;
}else{
gl_FragColor = vec4(color,1.0);
}
}