HoloLens MRTK模型切割算法解析

脚本解析

    例程中主要用到的脚本有位于Assets/MRTK/Core/Utilities/StandardShader路径下的ClippingPlane.cs、ClippingBox.cs、ClippingSphere.cs、ClippingPrimitive.cs(继承关系),位于Assets/MRTK/Core/StandardAssets/Shaders路径下的MixedRealityStandard.shader着色器,以及位于Assets/MRTK/Core/StandardAssets/Shaders路径下的MixedRealityShaderUtils.cginc。它们三个的关系如下:
在这里插入图片描述
清晰框图及注释见:https://download.csdn.net/download/qq_41452267/12986383

算法实现

面切割算法:对于心脏模型的每一个片元,在世界坐标系下,使用平面的法线向量n与平面中心点到待渲染点的方向向量d做点乘。根据计算结果的正负号将模型划分为平面的内侧和外侧两部分。
球切割算法:对于心脏模型的每一个片元,计算其到球心的距离,如果小于半径,则位于内侧,反之,位于外侧。
立方体切割算法:对于心脏模型的每一个片元,将片元坐标变换到立方体的模型坐标系下得到坐标position,用position的每个坐标分量取绝对值再减去立方形大小。最终得到的坐标中最大值大于零的,说明在立方体外,最大值小于零的说明在立方体内。

修改shader实现不同的功能

修改Clipping Plane裁剪的范围

在原工程中,Clipping Plane会将整个空间一分为二,空间的一侧被切割,另一侧不被切割。
需求:希望Clipping Plane根据自身范围进行切割,只有接触到的部分被切割,未接触到的部分不予切割,效果如下图:
在这里插入图片描述
实现方法
①在场景中修改变量至合适大小,默认大小为1米x1米。这里设置切片为0.5米
在这里插入图片描述

①在ClippingPlane.cs文件中声明变量,并获取切片信息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
③在着色器MixedRealityStandard.shader中调用变量和函数,函数定义在MixedRealityShaderUtils.cginc文件中:
MixedRealityStandard.shader如下:
在这里插入图片描述
在这里插入图片描述

primitiveDistance = min(primitiveDistance, PointVsPlanePart(i.worldPosition.xyz, _ClipPlane, _ClipPlanePosition, _ClipPlaneUp, _ClipPlaneRight, _ClipPlaneForward) * _ClipPlaneSide);

MixedRealityShaderUtils.cginc定义函数如下:
在这里插入图片描述

//部分截取,返回值为负时显示,为正时不显示
inline float PointVsPlanePart(float3 worldPosition, float4 plane,float3 planeRawPosition,float3 planeUp, float3 planeRight, float3 planeForward)
{      
    float3 planePosition = plane.xyz * plane.w;
    float3 distance = worldPosition - planeRawPosition;//计算面片与平面中心坐标差
    float x = dot(distance, planeRight);//计算面片在平面坐标系下的x y值
    float z = dot(distance, planeForward);
    float y = dot(distance, planeUp);
    if (y<0 || z<-0.25 || z>0.25 || x<-0.25 || x>0.25)
        return -0.2;//超过面片范围显示显示
    else
        return 0.2;//不显示
    //return dot(worldPosition - planePosition, plane.xyz);//plane.xyz是平面法向量
}

修改模型透明度

需求:原始可切割模型默认为不透明渲染模式,希望调整模型为半透明可切割,且透明度可调整。
①创建材质球,选择着色器为mixedrealitytoolkit/Standard(这里最好自己创一个新的shader,否则很多场景都将无法正常显示),选择Rendering Mode为Transparent
在这里插入图片描述
②在MixedRealityStandard.shader中(或者是自己创建的shader),修改最终的output如下:
在这里插入图片描述

                // Perform non-alpha clipped primitive clipping on the final output.
#if defined(_CLIPPING_PRIMITIVE) && !defined(_ALPHA_CLIP)
                //output *= saturate(primitiveDistance * (1.0f / _BlendedClippingWidth));//saturate函数将返回值限制在0-1之间
                if (primitiveDistance > 0) {
                    output.a = 0.3;
                }
                else {
                    output *= 0;
                }
                
#endif
                return output;
            }

            ENDCG
        }

output.a即是调整透明度的地方。

多个ClippingPrimitive对同一个模型进行切割

By default only one ClippingPrimitive can clip a renderer at a time. If your project requires more than one ClippingPrimitive to influence a renderer the sample code below demonstrates how to achieve this.

Two different ClippingPrimitives clip a render

How to have two different ClippingPrimitives clip a render. For example a ClippingSphere and ClippingBox at the same time:

// Within MRTK/Core/StandardAssets/Shaders/MixedRealityStandard.shader (or another MRTK shader) change:

#pragma multi_compile _ _CLIPPING_PLANE _CLIPPING_SPHERE _CLIPPING_BOX

// to:

#pragma multi_compile _ _CLIPPING_PLANE
#pragma multi_compile _ _CLIPPING_SPHERE
#pragma multi_compile _ _CLIPPING_BOX

Two of the same ClippingPrimitives clip a render

How to have two of the same ClippingPrimitives clip a render. For example two ClippingBoxes at the same time:

// 1) Add the below MonoBehaviour to your project:

[ExecuteInEditMode]
public class SecondClippingBox : ClippingBox
{
    /// <inheritdoc />
    protected override string Keyword
    {
        get { return "_CLIPPING_BOX2"; }
    }

    /// <inheritdoc />
    protected override string ClippingSideProperty
    {
        get { return "_ClipBoxSide2"; }
    }

    /// <inheritdoc />
    protected override void Initialize()
    {
        base.Initialize();

        clipBoxSizeID = Shader.PropertyToID("_ClipBoxSize2");
        clipBoxInverseTransformID = Shader.PropertyToID("_ClipBoxInverseTransform2");
    }
}

// 2) Within MRTK/Core/StandardAssets/Shaders/MixedRealityStandard.shader (or another MRTK shader) add the following multi_compile pragma:

#pragma multi_compile _ _CLIPPING_BOX2

// 3) In the same shader change:

#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX)

// to:

#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX) || defined(_CLIPPING_BOX2)

// 4) In the same shader add the following shader variables:

#if defined(_CLIPPING_BOX2)
    fixed _ClipBoxSide2;
    float4 _ClipBoxSize2;
    float4x4 _ClipBoxInverseTransform2;
#endif

// 5) In the same shader change:

#if defined(_CLIPPING_BOX)
    primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, _ClipBoxSize.xyz, _ClipBoxInverseTransform) * _ClipBoxSide);
#endif

// to:

#if defined(_CLIPPING_BOX)
    primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, _ClipBoxSize.xyz, _ClipBoxInverseTransform) * _ClipBoxSide);
#endif
#if defined(_CLIPPING_BOX2)
    primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, _ClipBoxSize2.xyz, _ClipBoxInverseTransform2) * _ClipBoxSide2);
#endif

Finally, add a ClippingBox and SecondClippingBox component to your scene and specify the same renderer for both boxes. The renderer should now be clipped by both boxes simultaneously.

详情见:https://microsoft.github.io/MixedRealityToolkit-Unity/Documentation/Rendering/ClippingPrimitive.html

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值