BVH 结构在着色器中不起作用,但在 cpp 代码中起作用

问题描述 投票:0回答:1

我一直在学习渲染,在学习光线追踪之后,我想探索加速结构并编写自己的 BVH 实现。我正在通过在一个方向内发送阴影光线并检查它是否击中物体(三角形)来测试它。但是,我无法让射线与任何三角形相交(它确实成功地与 AABB 框相交)。我将代码从计算着色器复制到 cpp 代码中,它似乎成功与三角形相交。

void TraceRay(inout RayPayload Payload)
{
     float tMin = FLOAT_MAX;
    
    int Stack[MAX_STACK_SIZE];
    int StackPtr = 0;
       
    Stack[StackPtr++] = 0;

    while(StackPtr > 0)
    {
        int CurrentNode = Stack[--StackPtr];

        if (BVHStructure.nodes[CurrentNode].Primitive[0] != -1) // is a leaf
        {
            for (int i = 0; i < 20; i++)
            {
                if (BVHStructure.nodes[CurrentNode].Primitive[i] == -1)
                    break;
              
                if (IntersectTriangle(Payload, BVHStructure.nodes[CurrentNode].Primitive[i]))
                {
                    Payload.InLight = false;
                    return; 
                }
            }
        }
        else
        {
            int Child1 = BVHStructure.nodes[CurrentNode].LeftNode;
            int Child2 = BVHStructure.nodes[CurrentNode].RightNode;

            if (Child1 != -1)
            {
                float Distance1 = IntersectAABB(Payload, BVHStructure.nodes[Child1].BoundingBox);
                if (Distance1 != FLOAT_MAX)
                    Stack[StackPtr++] = Child1;
                   
            }

            if (Child2 != -1)
            {
                float Distance2 = IntersectAABB(Payload, BVHStructure.nodes[Child2].BoundingBox);
                if (Distance2 != FLOAT_MAX)
                    Stack[StackPtr++] = Child2;

            }
        }
    }
}

这就是追迹射线函数的样子。我不确定我是否以正确的方式遍历它,但这就是我阅读如何做到这一点的方式。我通过递归在CPU上构建了结构,三角形也在CPU上排序。

void BVHBuilder::BuildBVH(int NodeIndex, int min, int max)
{
    if (max <= min)
        return;

    if (max - min <= 20)
    {
        size_t k = 0;
        BVHNode leafNode{};

        for (size_t i = std::max(min, 0); i < max; i++)
        {
            leafNode.BoundingBox.MinValue = glm::min(ComputeMinimum(m_TriangleData[i]), leafNode.BoundingBox.MinValue);
            leafNode.BoundingBox.MaxValue = glm::max(ComputeMaximum(m_TriangleData[i]), leafNode.BoundingBox.MaxValue);
            leafNode.Primitive[k] = i;
            k++;
        }

        m_Nodes.push_back(leafNode);
        m_Nodes[NodeIndex].RightNode = m_Nodes.size() - 1;
        
        return;
    }

    int median = (min + max) / 2;

    BVHNode LeftChild{};
    LeftChild.BoundingBox.MinValue = ComputeMinimum(m_TriangleData[min]);
    LeftChild.BoundingBox.MaxValue = ComputeMaximum(m_TriangleData[median]);

    m_Nodes.push_back(LeftChild);
    m_Nodes[NodeIndex].LeftNode = m_Nodes.size() - 1;
    

    BVHNode RightChild{};
    RightChild.BoundingBox.MinValue = ComputeMinimum(m_TriangleData[median]);
    RightChild.BoundingBox.MaxValue = ComputeMaximum(m_TriangleData[max]);

    m_Nodes.push_back(RightChild);
    m_Nodes[NodeIndex].RightNode = m_Nodes.size() - 1;

    BuildBVH(m_Nodes[NodeIndex].LeftNode, min, median);
    BuildBVH(m_Nodes[NodeIndex].RightNode, median, max);

我首先认为问题出在着色器存储缓冲区内的数据对齐,但是修复此问题后似乎没有任何变化。然后我认为我计算世界空间坐标的计算不正确

RayPayload DispatchShadowRay(in ivec2 Coordinate, in vec3 LightDirection)
{ 
    RayPayload Payload;
    Payload.Valid = true;
    Payload.InLight = true;

    
    vec2 NormalizedCoord = vec2(Coordinate) / vec2(WINDOW_WIDTH, WINDOW_HEIGHT);
    float DepthValue = texture(DepthBuffer, NormalizedCoord).r;

    if(DepthValue >= 1.0 - EPSILON)
    {
        Payload.Valid = false;
        return Payload;
    }

    DepthValue = DepthValue * 2.0 - 1.0;
    vec4 ViewSpace = InverseProjection * vec4(NormalizedCoord * 2.0 - 1.0, 
                                                       DepthValue, 1.0);

    ViewSpace /= ViewSpace.w;
    vec4 WorldSpace = InverseView * ViewSpace;
    Payload.Origin = WorldSpace.xyz;

    Payload.Direction = normalize(-LightDirection);
    Payload.Origin += Payload.Direction * 0.001;


    TraceRay(Payload);

    return Payload;
}

不过这似乎也不错 。我还仔细检查了 AABB 交集和 Intersect Triangle 函数的实现,但找不到任何东西。我还尝试使用 Nsight 或 Renderdoc 等工具进行调试(当它不崩溃时),除了存储对齐之外,它们似乎没有为我的问题提供任何有用的信息。

data-structures graphics 3d raytracing
1个回答
0
投票

问题是迭代基元,似乎如果 glsl 知道会有一个无效索引,它就会完全跳过该部分,我添加了一个变量来跟踪叶节点中基元的数量(我应该这样做)以前)这似乎解决了问题。

© www.soinside.com 2019 - 2024. All rights reserved.