Opengl es 对多边形进行细分和三角剖分

Opengl es 对多边形进行细分和三角剖分,opengl-es,mesh,triangulation,Opengl Es,Mesh,Triangulation,我得到一个随机轮廓作为输入。我需要将其转换为多边形并在三维空间中显示(A) 通常,我会通过一个标准的耳朵剪辑算法来做,结果会像(B) 然而,由于我正在开发的视频卡(VIVANTE GC 2000)的图形驱动程序中存在一个bug,我只能对这样的小形状进行三角剖分。原因是,在渲染时,如果网格顶点位于截锥体左侧或右侧太远的外部,则位置计算不正确。这会导致屏幕上大网格的剧烈闪烁和变形。 这是一个已确认的驱动程序问题,在其他平台上,甚至同一显卡的旧版本驱动程序上都不会发生这种情况。不幸的是,我不能使用旧的

我得到一个随机轮廓作为输入。我需要将其转换为多边形并在三维空间中显示(A)

通常,我会通过一个标准的耳朵剪辑算法来做,结果会像(B)

然而,由于我正在开发的视频卡(VIVANTE GC 2000)的图形驱动程序中存在一个bug,我只能对这样的小形状进行三角剖分。原因是,在渲染时,如果网格顶点位于截锥体左侧或右侧太远的外部,则位置计算不正确。这会导致屏幕上大网格的剧烈闪烁和变形。 这是一个已确认的驱动程序问题,在其他平台上,甚至同一显卡的旧版本驱动程序上都不会发生这种情况。不幸的是,我不能使用旧的驱动程序,而且卡制造商也不太可能修复这个bug,因为它已经被知道了将近十年

下面是一个关于这个问题的更深入的线程

所以我得用拐杖。换句话说,我必须将网格分割成几个较小的三角形,比如(C) 因此,在任何时间点,渲染的三角形的顶点都不会离平截头体太远

不幸的是,在我看来,真的没有别的办法。我知道这是一个非常不雅观的解决方案,但实际上没有其他方法可以绕过驱动程序错误

但我被困在实际做这件事上了。不知何故,我无法思考如何生成三角化数据(A->C)。有人能以这种方式帮助我分割/三角剖分网格的算法吗?假设所有“正方形”都是N乘N的正方形,其中N由我指定

也许有人对我如何处理这个问题提出了其他建议


< P>我猜你可以考虑在你有B之后继续细分每一个三角形,像这样:

根据需要设置尽可能多的细分:

所以,我成功了

构思大纲:

  • 画一个等高线
  • 计算横穿X和Y的等分线(可以是多条线
  • 将初始轮廓细分为“切片”,在特定Y坐标上对分
  • 遍历每个切片并在特定的X坐标上分割其边
  • 对每个生成的子图进行三角剖分
我还确保跟踪唯一的向量(因为我最终在分界线上得到了顶点的双精度)。这也有助于我以后更容易地创建顶点数组

这里有几个链接:

  • 细分非凸轮廓:
  • 耳削三角测量:
我的代码(有点凌乱,我计划重构它,但另一方面它是一体的)

public triangulation输出三角形subdivide(列表等高线)
{
//清除列表并重置变量
input.clear();
polygonVerts.clear();;
凸面。清除();
反射波清除();
清晰的;
earVerts.clear();
canBeEars.clear();
角=空;
uniqueVectors.clear();
列表结果=新建ArrayList();
//如果列表为顺时针方向,则反转顶点的顺序
if(逆时针(轮廓))
{
收藏。反向(等高线);
}
//查找图形中最左侧和最顶部的点
Vector2f top=轮廓。获取(0);
Vector2f left=轮廓。获取(0);
Vector2f-bottom=等高线.get(0);
Vector2f right=轮廓。获取(0);
对于(int i=1;i顶部y)
top=电流;
if(当前y<底部y)
底部=电流;
如果(当前.x<左.x)
左=电流;
如果(当前.x>右.x)
右=电流;
}
//检查整个网格是否适合该空间
if((Math.abs(top.y-bottom.y)bottom.y)
{
linesY.add(lineCoord);
lineCoord-=GlobalSettings.OPT_MAX_DISTANCE;
}
List linesX=new ArrayList();
lineCoord=((float)((int)(right.x/GlobalSettings.OPT_MAX_DISTANCE))*GlobalSettings.OPT_MAX_DISTANCE;
而(lineCoord>left.x)
{
linesX.add(lineCoord);
lineCoord-=GlobalSettings.OPT_MAX_DISTANCE;
}
列表子画面=新建ArrayList();
List contourCpy=new ArrayList();
contourCpy.addAll(轮廓);
对于(int i=0;i=contourCpy.size()?0:(j+1);
Vector2f next=contourCpy.get(索引);
//确定顶点位于直线的哪一侧,或者它们是否直接位于直线上
VertexStatus vsCurrent=新的VertexStatus(当前,yCoord,true);
VertexStatus vsNext=新的VertexStatus(next,yCoord,true);
VertexStatus vsPrevious=新的VertexStatus(previous,yCoord,true);
if(vsPrevious.isOn()&&vsCurrent.isOn()&&vsNext.isOn())
{
//相邻边完全位于直线上
继续;
}
if(vsCurrent.isOn())
{
//如果它位于th上,则添加点
public TriangulationOutput triangulateSubdivide(List<Vector2f> contour)
    {
        // clear lists and reset variables
        input.clear();
        polygonVerts.clear();;
        convexVerts.clear();
        reflexVerts.clear();
        straightVerts.clear();
        earVerts.clear();
        canBeEars.clear();
        corner = null;
        uniqueVectors.clear();

        List<Triangle>  result = new ArrayList<>();

        // Reverse the order of verts if the list is clockwise
        if (isClockwise(contour))
        {
            Collections.reverse(contour);
        }

        // find leftmost and topmost points in the
        Vector2f top = contour.get(0);
        Vector2f left = contour.get(0);
        Vector2f bottom = contour.get(0);
        Vector2f right = contour.get(0);
        for (int i = 1; i < contour.size(); i++)
        {
            Vector2f current = contour.get(i);
            if (current.y > top.y)
                top = current;
            if (current.y < bottom.y)
                bottom = current;
            if (current.x < left.x)
                left = current;
            if (current.x > right.x)
                right = current;
        }

        // check if the entire mesh fits within the space
        if ((Math.abs(top.y - bottom.y) <= GlobalSettings.OPT_MAX_DISTANCE)&&(Math.abs(right.x - left.x) <= GlobalSettings.OPT_MAX_DISTANCE))
        {
            // I haven't tested this edge case yet, but it's not really relevant to the algorythm
            System.err.println("TriangulateSubdivide -> shortcut used");
            return new TriangulationOutput(triangulateSimple(contour), contour);
            //TODO: Could be trouble
        }

        //Find X and Y split coordinates
        List<Float> linesY = new ArrayList<>();
        float lineCoord = ((float)((int)(top.y / GlobalSettings.OPT_MAX_DISTANCE))) * GlobalSettings.OPT_MAX_DISTANCE;
        while (lineCoord > bottom.y)
        {
            linesY.add(lineCoord);
            lineCoord -= GlobalSettings.OPT_MAX_DISTANCE;
        }

        List<Float> linesX = new ArrayList<>();
        lineCoord = ((float)((int)(right.x / GlobalSettings.OPT_MAX_DISTANCE))) * GlobalSettings.OPT_MAX_DISTANCE;
        while (lineCoord > left.x)
        {
            linesX.add(lineCoord);
            lineCoord -= GlobalSettings.OPT_MAX_DISTANCE;
        }

        List<List<Vector2f>> submeshes = new ArrayList<>();
        List<Vector2f> contourCpy = new ArrayList<>();
        contourCpy.addAll(contour);
        
        for (int i = 0; i < linesY.size(); i++)
        {
            List<Vector2f> submesh;
            List<Vector2f> intersections = new ArrayList<>();

            float yCoord = linesY.get(i);

            // split polygon edges on dividing horizontal lines
            // store found intersections to find them easier later
            for (int j = 0; j < contourCpy.size(); j++)
            {
                Vector2f current = contourCpy.get(j);
                int index = (j - 1) < 0 ? contourCpy.size()-1 : (j - 1);
                Vector2f previous = contourCpy.get(index);
                index = (j + 1) >= contourCpy.size() ? 0 : (j + 1);
                Vector2f next = contourCpy.get(index);

                // determines on which side of the line vertexes lie, or if they lie directly on it
                VertexStatus vsCurrent = new VertexStatus(current, yCoord, true);
                VertexStatus vsNext = new VertexStatus(next, yCoord, true);
                VertexStatus vsPrevious = new VertexStatus(previous, yCoord, true);

                if (vsPrevious.isOn() && vsCurrent.isOn() && vsNext.isOn())
                {
                    // adjacient edges lie completely on the line
                    continue;
                }

                if (vsCurrent.isOn())
                {
                    // add point if it lies on the line
                    intersections.add(current);
                }
                else if ((vsCurrent.status() != vsNext.status()) && (!vsNext.isOn()))
                {
                    // line intersects current edge in a point other than vertexes
                    float x = current.x + ((yCoord - current.y)*(next.x - current.x)) / (next.y - current.y);
                    Vector2f ip = new Vector2f(x, yCoord);
                    intersections.add(ip);
                    contourCpy.add(index, ip);       //TODO: possible trouble at last node
                    j++;    //increment to skip the point we just added
                }
            }

            //sort intersections
            intersections.sort(new Comparator<Vector2f>()
            {
                @Override
                public int compare(Vector2f v1, Vector2f v2)
                {
                    return (v1.x < v2.x) ? -1 : 1;
                }
            });

            // find submeshes that lie above the line. Every two intersections 
            for (int j = 0; j < intersections.size(); j+=2)
            {
                // for every two points we find a linked submesh
                submesh = new ArrayList<>();

                int indexEnd = contourCpy.indexOf(intersections.get(j));
                int indexStart = contourCpy.indexOf(intersections.get(j+1));

                int index = indexStart;
                boolean cont = true;
                while (contourCpy.size() > 0)
                {

                    submesh.add(contourCpy.get(index));

                    if (index == indexEnd)
                    {
                        break;
                    }

                    if ((index != indexStart))
                    {
                        // remove points between intersections from future countour
                        contourCpy.remove(index);

                        if (index < indexEnd)
                        {
                            indexEnd--;
                        }
                    }
                    else
                    {
                        index++;
                    }

                    if (index >= contourCpy.size())
                    {
                        index = 0;
                    }
                }
                //while (index != indexEnd);

                submeshes.add(submesh);
            }
        }

        // add the remaining contour as final bottom-most mesh
        submeshes.add(contourCpy);
        
        for (List<Vector2f> submesh : submeshes)
        {
            // Add more vertexes for X coord divisions
            for (int i = 0; i < submesh.size(); i++)
            {
                Vector2f current = submesh.get(i);

                // add current vector to unique
                boolean add = true;
                for (int v = 0; v < uniqueVectors.size(); v++)
                {
                    if (uniqueVectors.get(v).equals(current))
                    {
                        add = false;
                        break;
                    }
                }
                if (add)
                {
                    uniqueVectors.add(current);
                }

                int index = (i + 1) >= submesh.size() ? 0 : (i + 1);
                Vector2f next = submesh.get(index);

                for (int j = 0; j < linesX.size(); j++)
                {
                    float xCoord = linesX.get(j);
                    VertexStatus vsCurrent = new VertexStatus(current, xCoord, false);
                    VertexStatus vsNext = new VertexStatus(next, xCoord, false);

                    if (vsCurrent.isOn() || vsNext.isOn())
                    {
                        continue;
                    }

                    if (vsCurrent.status() != vsNext.status())
                    {
                        // vectors lie on different sides of xCoord
                        float y = current.y + ((next.y - current.y)*(xCoord - current.x)) / (next.x - current.x);
                        Vector2f ip = new Vector2f(xCoord, y);
                        // add current vector to unique
                        add = true;
                        for (int v = 0; v < uniqueVectors.size(); v++)
                        {
                            if (uniqueVectors.get(v).equals(ip))
                            {
                                ip = uniqueVectors.get(v);
                                add = false;
                                break;
                            }
                        }
                        if (add)
                        {
                            uniqueVectors.add(ip);
                        }
                        submesh.add(index,ip);

                        //TODO: possible trouble here
                        if (current.x > next.x)
                        {
                            index++;
                        }
                        i++;
                    }
                }
            }

            result.addAll(triangulateSimple(submesh));
        }

        // this basically just stores triangles and a list of vertexes and doesn't do anything else.
        return new TriangulationOutput(result, uniqueVectors);
    }