Terrain Quadtree LOD裂缝/丁字路口

时间:2017-07-20 16:52:41

标签: algorithm opengl terrain

我已经使用四叉树在我的图形引擎中实现了基本地形,现在我遇到了修复T型接头和裂缝的问题。首先我使用的是OpenGL 3.2,所以我无法使用tesslation。也许我会在不久的将来实现这个功能。基本上我有一个存储四叉树对象的terrain对象,并有一个名为render的方法:

/**
 * Render tile
 * @param program - shader program
 */
public void render(Camera camera, Shader program)
{
    if(camera.hasMoved())
        this.quadtree.updateQuadTree(camera);

    this.quadtree.render(program);
}

然后我的四叉树对象有四个名为TerrainTreeNode的孩子,这个方法:

/**
 * Update quadtree
 * @param camera - camera
 */
public void updateQuadTree(Camera camera)
{
    for(Node node : getChildren())
        ((TerrainTreeNode) node).updateQuadtree(camera);
}

然后我的TerrainTreeNode对象有以下方法:

/**
 * Update quad tree
 * @param camera - camera
 */
public void updateQuadtree(Camera camera)
{
    updateChildNodes(camera.position);

    for(Node node : getChildren())
    {
        ((TerrainTreeNode) node).updateQuadtree(camera);
    }
}

/**
 * Update child nodes
 * @param cameraPosition - camera position
 */
private void updateChildNodes(Vector3f cameraPosition)
{
    Vector3f tempCamera = new Vector3f(cameraPosition);
    Vector3f tempPosition = new Vector3f(this.position);
    Vector3f.sub(tempCamera, tempPosition, tempCamera);
    float distance = tempCamera.length();

    switch(this.lod)
    {
        case 0: 
            if(distance < 1750)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 1750)
            {
                removeChildNodes();
            }
            break;

        case 1: 
            if(distance < 874)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 874)
            {
                removeChildNodes();
            }
            break;

        case 2: 
            if(distance < 386)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 386)
            {
                removeChildNodes();
            }
            break;

        case 3: 
            if (distance < 192)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 192)
            {
                removeChildNodes();
            }
            break;

        case 4: 
            if(distance < 100)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 100)
            {
                removeChildNodes();
            }
            break;

        case 5: 
            if(distance < 50)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 50)
            {
                removeChildNodes();
            }
            break;

        case 6: 
            if(distance < 0)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 0)
            {
                removeChildNodes();
            }
            break;

        case 7: 
            if (distance < 0)
            {
                addChildNodes(this.lod+1);
            }
            else if(distance >= 0)
            {
                removeChildNodes();
            }
            break;
    }
}

/**
 * Add child nodes
 * @param lod - level of detail
 */
public void addChildNodes(int newLod)
{
    if(isLeaf)
    {
        isLeaf = false;
        if(this.mesh != null)
            this.mesh.dispose();
    }
    if(getChildren().size() == 0)
    {   
        float newWidth = this.width/2f;
        float newWidth2 = newWidth/2f;
        for(int i = 0; i < 2; i++)
        {
            for(int j = 0; j < 2; j++)
            {
                float first, second;
                if(i == 0)
                    first = -(newWidth/2f);
                else
                    first = newWidth/2f;
                if(j == 0)
                    second = -(newWidth/2f);
                else
                    second = newWidth/2f;

                Vector3f newPosition = new Vector3f(this.position.x+first, 
                        0f, this.position.z+second);
                addChild(new TerrainTreeNode(newPosition, 
                        newLod, 
                        new Vector2f(i, j), 
                        newWidth));
            }
        }
    }   
}

/**
 * Remove child nodes
 */
private void removeChildNodes()
{
    if(!isLeaf)
    {
        isLeaf = true;
        this.mesh = generateMesh();

    }
    //Remove childrends
    if(getChildren().size() != 0)
    {
        for(Node child : getChildren())
            child.dispose();

        getChildren().clear();
    }
}

正如你所看到的那样,树节点距离摄像机的距离很远,然后它会删除子节点并创建自己的vao,相反,它会创建子节点并从内存中删除vao。我的vao使用三角扇,它看起来像这样:

enter image description here

1,2,4,6,8和10个顶点始终处于活动状态,其他我要打开和关闭的顶点取决于邻居的详细程度以避免这种情况:

enter image description here

算法应该禁用红色顶点。我怎样才能做到这一点?如何找到所有无用的顶点? 该算法基于来自gamesutra的这篇文章。

感谢您的帮助!

修改 我发现(从这个链接:http://www.dice.se/wp-content/uploads/2014/12/Chapter5-Andersson-Terrain_Rendering_in_Frostbite.pdf - &gt;请参阅第53-55页)我不必打开和关闭顶点,而是我必须在不同的vao中存储节点的所有排列。这很清楚。但仍然不知道如何检测裂缝:/。

1 个答案:

答案 0 :(得分:1)

我不想在你的情况下修改数据,四叉树。

我更喜欢根据LOD选择要绘制的子节点和节点。当相机很远时,只有大多数孩子被丢弃(他们在屏幕上的尺寸远小于一个像素),许多人只选择点'1'或连接中的一些(2,4,6或8),并且只有最接近所有的vetices。

您需要确定哪个顶点是每个LOD的“相关”。

您应该使用“选择子节点”部分。

修改

您需要的是一种为贴片选择顶点的方法,使其适合距离相机较远的相邻贴片。因此,该邻居使用不同的LOD。

算法取决于邻居的相对位置(左侧或右侧或上下)。它还取决于邻居与补丁相比的不同LOD(如果使用多个LOD,从补丁到其邻居的LOD步骤应该只有一个,但是要小心,你可以编写高低LOD之间的连接,而不是中途LOD)。有几种组合。

要允许至少两个不同的LOD,您需要一个5x5顶点补丁。低LOD补丁将是3x3(你画的是什么)。

然后你选择高LOD的顶点(你称之为“修改qtree”,右边?),如下所示:

func1_list = func1(x)

具有低LOD的邻居选择其所有顶点。

通过使用索引缓冲区选择顶点时,该链接中显示的内容。每个排列代表根据邻居的位置得到的顶点。