Meshlet cone cull

  一块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;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容