对模型剖切是通过设置scene或者material的clippingPlanes实现的;
如果设置了材质的clippingPlanes,shader的顶点着色器和片元着色器都会加入相应逻辑的代码;
1、首先在顶点着色器里加入以下代码,给vClipPosition赋值,并传入片元着色器,这里用的是相机坐标系里的值,没有用世界坐标系里的值,这可能是因为变换矩阵可能改变法线的朝向,因此要将法线和顶点都统一到相机坐标系里;
#if 1 > 0
vClipPosition = -mvPosition.xyz;
#endif
if语句里的1表示的是clippingPlanes的个数,编译shader之前会被动态替换;
2、到片元着色器里,有如下逻辑:
#if 1 > 0
vec4 plane;
plane = clippingPlanes[ 0 ];
if ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;
#if 1 < 1
bool clipped = true;
if ( clipped ) discard;
#endif
#endif
同样道理,里边有些固定数值,其实是在shader编译之前动态替换的;上述代码主要是判断点落在了平面的哪一测,如果不在指定的一侧,就discard,不绘制;
Three.js里的Plane用的是Hessian Normal Form
来描述一个明面,特别要注意,Plane的构造方法里,传入的距离是带符号的,正值表示圆点位于法线方向指向的那一侧,负值表示另一侧,见下图:
注意:上面顶点着色器里,vClipPosition = -mvPosition.xyz,之所以有个负号,也是从上面Hessian Normal Form表达式得出的,NX = -P => -NX = P => N*(-X)=P,P是有符号的距离。在片元着色器里 dot( vClipPosition, plane.xyz ) > plane.w,plane.xyz和plane.w都是经过法线矩阵变换后的值,不是构造Plane时候传入的。