美文网首页
Meshlet cone cull

Meshlet cone cull

作者: crossous | 来源:发表于2022-08-19 20:50 被阅读0次

      一块Meshlet可以被一个圆锥简易表达,圆锥的表示为:顶点(Apex)、轴(Axis)和顶角(1/2锥角)。



      圆锥的的范围包含了Meshlet所有法线方向,因此如果一个view向量和圆锥范围内所有向量的点积都是负数,就说明整个Meshlet都是背对着相机,可以整体剔除,体现在下图中,就是如果相机在蓝色区域内,就可以剔除这个Meshlet: image.png

    圆锥生成

    引用自ComputeCullData方法

    1. 计算Axis

      对所有normal生成最小包围球,球心的单位化向量既是圆锥的轴(Axis):


    // Calculate the normal cone
    // 1. Normalized center point of minimum bounding sphere of unit normals == conic axis
    XMVECTOR normalBounds = MinimumBoundingSphere(normals, m.PrimCount);
    
    // 2. Calculate dot product of all normals to conic axis, selecting minimum
    XMVECTOR axis = XMVectorSetW(XMVector3Normalize(normalBounds), 0);
    
    2. 去掉退化圆锥

      如果圆锥的顶角是钝角,则没有剔除意义,所以对Axis和Meshlet每个面的法线做点积,如果有小于0的,则代表是退化圆锥:

    XMVECTOR minDot = g_XMOne;
    for (uint32_t i = 0; i < m.PrimCount; ++i)
    {
        XMVECTOR dot = XMVector3Dot(axis, XMLoadFloat3(&normals[i]));
        minDot = XMVectorMin(minDot, dot);
    }
    
    if (XMVector4Less(minDot, XMVectorReplicate(0.1f)))
    {
        // Degenerate cone
        c.NormalCone[0] = 127;
        c.NormalCone[1] = 127;
        c.NormalCone[2] = 127;
        c.NormalCone[3] = 255;
        continue;
    }
    

      在后续的Amplification Shader中,会拿取到当前数据,并判断假如w分享是0xff,则判断为退化圆椎:

    bool IsConeDegenerate(CullData c)
    {
        //这里NormalCone4个分量被打包成uint,所以要>>24
        return (c.NormalCone >> 24) == 0xff;
    }
    
    3. 偏移顶点

      上图事例中,圆锥顶点都在Meshlet网格的后面,但实际上可能在网格的前面,这时候要将顶点按轴移动到所有Mesh的负半空间:



      首先计算Meshlet的最小包围球(上面是normal,现在是mesh的),默认顶点是这个最小包围球的球心。
      对于每个面,计算原顶点按轴移动,移动到负半轴的距离t,找到最大的t作为顶点偏移值。



      如上图,深蓝色标记着3个面,红色点沿轴移动后,分别在三个粉色点达到平面,需要计算的是红色点和粉色点的距离t,并找到最大值后移动。

      我们有normal、axis是单位向量,找三角形任意一点连接Center,将线段投影到normal,得到center到表面的距离:



    上图标识的角度的cos是axis和normal的点积,通过点积和center到面距离,可以算出t
    // Find the point on center-t*axis ray that lies in negative half-space of all triangles
    float maxt = 0;
    
    for (uint32_t i = 0; i < m.PrimCount; ++i)
    {
        auto primitive = primitiveIndices[m.PrimOffset + i];
    
        uint32_t indices[3]
        {
            primitive.indices.i0,
            primitive.indices.i1,
            primitive.indices.i2,
        };
    
        XMVECTOR triangle[3]
        {
            XMLoadFloat3(&vertices[indices[0]]),
            XMLoadFloat3(&vertices[indices[1]]),
            XMLoadFloat3(&vertices[indices[2]]),
        };
    
        XMVECTOR c = positionBounds - triangle[0];
    
        XMVECTOR n = XMLoadFloat3(&normals[i]);
        float dc = XMVectorGetX(XMVector3Dot(c, n));
        float dn = XMVectorGetX(XMVector3Dot(axis, n));
    
        // dn should be larger than mindp cutoff above
        assert(dn > 0.0f);
        float t = dc / dn;
    
        maxt = (t > maxt) ? t : maxt;
    }
    
    4. 预计算cutoff阈值

      对于圆锥母线和轴的夹角cos值可以预计算,不过别忘了需要计算的是蓝色区域:


      cos(\frac{\pi}{2}-\alpha)=sin(\alpha)
    // cos(a) for normal cone is minDot; we need to add 90 degrees on both sides and invert the cone
    // which gives us -cos(a+90) = -(-sin(a)) = sin(a) = sqrt(1 - cos^2(a))
    XMVECTOR coneCutoff = XMVectorSqrt(g_XMOne - minDot * minDot);
    

      在Amplification Shader中直接比较:

    //bool IsVisible(CullData c, float4x4 world, float scale, float3 viewPos)
    
    float4 center = mul(float4(c.BoundingSphere.xyz, 1), world);
    
    // Transform axis to world space
    float3 axis = normalize(mul(float4(normalCone.xyz, 0), world)).xyz;
    
    // Offset the normal cone axis from the meshlet center-point - make sure to account for world scaling
    float3 apex = center.xyz - axis * c.ApexOffset * scale;
    float3 view = normalize(viewPos - apex);
    
    // The normal cone w-component stores -cos(angle + 90 deg)
    // This is the min dot product along the inverted axis from which all the meshlet's triangles are backface
    if (dot(view, -axis) > normalCone.w)
    {
        return false;
    }
    

    相关文章

      网友评论

          本文标题:Meshlet cone cull

          本文链接:https://www.haomeiwen.com/subject/hlvugrtx.html