對模型剖切是通過設置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
image.png
來描述一個明面,特別要注意,Plane的構造方法里,傳入的距離是帶符號的,正值表示圓點位于法線方向指向的那一側,負值表示另一側,見下圖:
image.png
image.png
注意:上面頂點著色器里,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時候傳入的。