PISCOnoob

导航

Clipping a Model with a plane

写在前面:

本文章为个人学习笔记,方便以后自己复习,也希望能帮助到他人。

由于本人水平有限难免出现错误,还请评论区指出,多多指教。

部分图元和素材来源于网络,如有侵权请联系本人删除。

参考资料与链接会在文章末尾贴出。

=======================================================================

1 Define Plane

我们首先在C#脚本中定义一个Plane,并将其一些信息传递给shader。

[ExecuteAlways]这个attribute可以让脚本在editor mode下也能work。

我们创建了一个vector4,把新平面的法线放在xyz同道中人,第四个通道代表Plane到原点的距离。

[ExecuteAlways]
public class ClippingPlane : MonoBehaviour
{
    // material we pass the values to
    public Material mat;

    void Update()
    {
        // create plane
        Plane plane = new Plane(transform.up, transform.position);
        // transfer values from plane to vector4
        Vector4 planeInfo = new Vector4(plane.normal.x, plane.normal.y, plane.normal.z, plane.distance);
        // pass vector to shader
        mat.SetVector("_Plane", planeInfo);
    }
}

我们将此添加到一个empty object中,并将我们的材质应用于相应的变量

 

2 Clip Plane

假设我们希望将位于Plane上方的部分给clip掉,那么表达这个上方自然是Plane的normal了,判断模型表面上的点是否位于Plane上方我们可以用点乘,如果值大于0则为上方,等于0就是在Plane上,负数则在Plane下方。然后将值作为颜色输出。

       float4 frag (v2f i) : SV_Target
            {
                float distance = dot(i.posWS,_Plane.xyz);

                float4 finalCol = distance;
                
                return distance;
            }

但是移动Plane的poisition却不会发生变化因为我们目前没有将相关变量加入计算,这时候就要用到_Plane的第四个通道plane.distance。

        float4 frag (v2f i) : SV_Target
            {
                float distance = dot(i.posWS,_Plane.xyz);

                float4 finalCol = distance + _Plane.w;
                
                return finalCol;
            }

接下来我们可以通过clip函数裁剪Plane上方

        float4 frag (v2f i) : SV_Target
            {

                float4 var_tex = tex2D(_MainTex,i.uv);

                float distance = dot(i.posWS,_Plane.xyz);

                 distance += _Plane.w;

                clip(-distance);

                float4 finalCol = -distance * var_tex;
                
                return finalCol;
            }

 

2 Show Inside

两个新问题:

一是没有渲染模型背面,因此我们把 Cull 关掉

二是横切面没有渲染

 

现在我们可以看到头部内部,法线仍然指向模型外部,我们可能不想看到头部内部。

我们希望区分出内表面和外表面之间,为了确定我们是在渲染内部表面还是外部表面,我们在fragment shader输入参数中加入新参数facing并给它VFACE的semantic,1表述外面,-1表示里面



因为之后要将值用于线性插值之类的东西,我们将其值映射在 0 到 1 的范围内。

现在我们可以区分模型外面和里面,我们可以让模型内部有单独的颜色:

 

        float4 frag (v2f i,float facing : VFACE) : SV_Target
            {

                float4 var_tex = tex2D(_MainTex,i.uv);

                float distance = dot(i.posWS,_Plane.xyz);

                 distance += _Plane.w;

                clip(-distance);

                facing = facing * 0.5 + 0.5;

                float4 finalCol = lerp(_InsideColor,-distance * var_tex,facing);
                
                return finalCol;
            }

 

参考链接:

1.

posted on 2022-11-01 15:38  PISCOnoob  阅读(26)  评论(0编辑  收藏  举报