VTK三角化3D物体的表面

Posted theArcticOcean

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTK三角化3D物体的表面相关的知识,希望对你有一定的参考价值。

在VTK的体系中,要正常将actor输出STL文件,需要相应的PolyData三角化。

    vSPNew( triangle, vtkTriangleFilter);
    triangle->SetInputData( polyData );
    triangle->Update();

在一些专业软件,比如Meshmixer中查看STL文件,如果有任何的“不和谐”都会被标注出来。
下图中的物体是用两个长方体拼凑而成的。因为存在共面,所以meshmixer用红线标注出来了。

相关的生成代码:
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkLight.h>
#include <vtkCamera.h>
#include <vtkActor2D.h>
#include <vtkPoints.h>
#include <vtkSTLWriter.h>
#include <vtkAppendPolyData.h>
#include <vtkAppendFilter.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkSmoothPolyDataFilter.h>
#include <vtkPolyDataNormals.h>
#include <vtkCleanPolyData.h>
#include "tool.h"

using namespace std;

PointStruct getNormal(const PointStruct p1, const PointStruct p2, const PointStruct p3)

    PointStruct normal;
    PointStruct vec1( p1 - p3 );
    PointStruct vec2( p2 - p3 );
    vtkMath::Cross(vec1.point, vec2.point, normal.point);
    vtkMath::Normalize( normal.point );
    return normal;


PointStruct getNormal(const double *p1, const double *p2, const double *p3)

    PointStruct normal;
    PointStruct ps1( (double *)p1 );
    PointStruct ps2( (double *)p2 );
    PointStruct ps3( (double *)p3 );
    PointStruct vec1( ps1 - ps3 );
    PointStruct vec2( ps2 - ps3 );
    vtkMath::Cross(vec1.point, vec2.point, normal.point);
    vtkMath::Normalize( normal.point );
    return normal;


vtkSmartPointer<vtkCellArray> g_Poly =
        vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkPoints> g_Points =
        vtkSmartPointer<vtkPoints>::New();

void CreateVol1()

    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    points->InsertPoint(0, 0, 0, 0);
    points->InsertPoint(1, 1, 0, 0);
    points->InsertPoint(2, 1, 1, 0);
    points->InsertPoint(3, 0, 1, 0);

    PointStruct ps0( points->GetPoint(0) );
    PointStruct ps1( points->GetPoint(1) );
    PointStruct ps2( points->GetPoint(2) );
    PointStruct ps3( points->GetPoint(3) );

    PointStruct normal = getNormal( ps1, ps2, ps3 );
    PointStruct ps4 = ps0 + normal * 4;
    PointStruct ps5 = ps1 + normal * 4;
    PointStruct ps6 = ps2 + normal * 4;
    PointStruct ps7 = ps3 + normal * 4;

    points->InsertPoint(4, ps4.point);
    points->InsertPoint(5, ps5.point);
    points->InsertPoint(6, ps6.point);
    points->InsertPoint(7, ps7.point);

    vtkIdType pts1[4] =  0, 1, 2, 3 ;
    g_Poly->InsertNextCell( 4, pts1 );
    vtkIdType pts2[4] =  4, 5, 6, 7 ;
    g_Poly->InsertNextCell( 4, pts2 );
    vtkIdType pts3[4] =  1, 2, 6, 5 ;
    g_Poly->InsertNextCell( 4, pts3 );
    vtkIdType pts4[4] =  0, 3, 7, 4 ;
    g_Poly->InsertNextCell( 4, pts4 );
    vtkIdType pts5[4] =  3, 2, 6, 7 ;
    g_Poly->InsertNextCell( 4, pts5 );
    vtkIdType pts6[4] =  0, 1, 5, 4 ;
    g_Poly->InsertNextCell( 4, pts6 );

    for( int i = 0; i < points->GetNumberOfPoints(); ++i )
    
        PointStruct pt( points->GetPoint( i ) );
        g_Points->InsertNextPoint( pt.point );
    


void CreateVol2()

    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    points->InsertPoint(0, 1, 0, 0);
    points->InsertPoint(1, 2, 0, 0);
    points->InsertPoint(2, 2, 1, 0);
    points->InsertPoint(3, 1, 1, 0);

    PointStruct ps0( points->GetPoint(0) );
    PointStruct ps1( points->GetPoint(1) );
    PointStruct ps2( points->GetPoint(2) );
    PointStruct ps3( points->GetPoint(3) );

    PointStruct normal = getNormal( ps1, ps2, ps3 );
    PointStruct ps4 = ps0 + normal * 4;
    PointStruct ps5 = ps1 + normal * 4;
    PointStruct ps6 = ps2 + normal * 4;
    PointStruct ps7 = ps3 + normal * 4;

    points->InsertPoint(4, ps4.point);
    points->InsertPoint(5, ps5.point);
    points->InsertPoint(6, ps6.point);
    points->InsertPoint(7, ps7.point);

    vtkIdType pts1[4] =  8, 9, 10, 11 ;
    g_Poly->InsertNextCell( 4, pts1 );
    vtkIdType pts2[4] =  12, 13, 14, 15 ;
    g_Poly->InsertNextCell( 4, pts2 );
    vtkIdType pts3[4] =  9, 10, 14, 13 ;
    g_Poly->InsertNextCell( 4, pts3 );
    vtkIdType pts4[4] =  8, 11, 15, 12 ;
    g_Poly->InsertNextCell( 4, pts4 );
    vtkIdType pts5[4] =  11, 10, 14, 15 ;
    g_Poly->InsertNextCell( 4, pts5 );
    vtkIdType pts6[4] =  8, 9, 13, 12 ;
    g_Poly->InsertNextCell( 4, pts6 );

    for( int i = 0; i < points->GetNumberOfPoints(); ++i )
    
        PointStruct pt( points->GetPoint( i ) );
        g_Points->InsertNextPoint( pt.point );
    


int main()

    CreateVol1();
    CreateVol2();

    vtkSmartPointer<vtkPolyData> pd = vtkSmartPointer<vtkPolyData>::New();
    pd->SetPoints( g_Points );
    pd->SetPolys( g_Poly );

    vtkSmartPointer<vtkCleanPolyData> cleanFilter =
      vtkSmartPointer<vtkCleanPolyData>::New();
    cleanFilter->SetInputData( pd );
    cleanFilter->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    //mapper->SetInputConnection( normals->GetOutputPort() );
    mapper->SetInputConnection( cleanFilter->GetOutputPort() );

    vtkSmartPointer<vtkActor> actor =
            vtkSmartPointer<vtkActor>::New();
    actor->SetMapper( mapper );

    vtkSmartPointer<vtkRenderer> renderer =
            vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor( actor );
    renderer->SetBackground( 0, 0, 0 );

    vtkSmartPointer<vtkRenderWindow> renderWindow =
            vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer( renderer );

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
            vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow( renderWindow );

    renderer->ResetCamera();
    renderWindow->Render();

    vtkSmartPointer<vtkSTLWriter> stlWriter =
            vtkSmartPointer<vtkSTLWriter>::New();
    stlWriter->SetFileName( "/Users/weiyang/Desktop/test.stl" );
    stlWriter->SetInputData( actor->GetMapper()->GetInput() );
    stlWriter->Write();

    renderWindowInteractor->Start();
    return 0;

下图是一个由从左到右的四个不同三角形组成的矩形,三角形法向量不同的情况下在meshmixer中查看得到如下的结果。

重构代码,使得所有的三角形,法线方向朝里(世界坐标系Z轴负向)。

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkLight.h>
#include <vtkCamera.h>
#include <vtkActor2D.h>
#include <vtkPoints.h>
#include <vtkSTLWriter.h>
#include <vtkAppendPolyData.h>
#include <vtkAppendFilter.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkSmoothPolyDataFilter.h>
#include <vtkPolyDataNormals.h>
#include "tool.h"

using namespace std;

int main()

    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    points->InsertPoint(0, 0, 0, 0);
    points->InsertPoint(1, 1, 0, 0);
    points->InsertPoint(2, 1, 1, 0);
    points->InsertPoint(3, 0, 1, 0);
    points->InsertPoint(4, 2, 0, 0);
    points->InsertPoint(5, 2, 1, 0);

    vtkSmartPointer<vtkCellArray> poly = vtkSmartPointer<vtkCellArray>::New();
    vtkIdType pts1[3] =  3, 1, 0 ;
    poly->InsertNextCell( 3, pts1 );
    vtkIdType pts2[3] =  1, 3, 2 ;
    poly->InsertNextCell( 3, pts2 );
    vtkIdType pts3[3] =  2, 4, 1 ;
    poly->InsertNextCell( 3, pts3 );
    vtkIdType pts4[3] =  4, 2, 5 ;
    poly->InsertNextCell( 3, pts4 );

    vtkSmartPointer<vtkPolyData> pd = vtkSmartPointer<vtkPolyData>::New();
    pd->SetPoints( points );
    pd->SetPolys( poly );

    vtkSmartPointer<vtkSTLWriter> stlWriter =
            vtkSmartPointer<vtkSTLWriter>::New();
    stlWriter->SetFileName( "/Users/weiyang/Desktop/test.stl" );
    stlWriter->SetInputData( pd );
    stlWriter->Write();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData( pd ); //normals->GetOutput() );

    vtkSmartPointer<vtkActor> actor =
            vtkSmartPointer<vtkActor>::New();
    actor->SetMapper( mapper );

    vtkSmartPointer<vtkRenderer> renderer =
            vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor( actor );
    renderer->SetBackground( 0, 0, 0 );

    vtkSmartPointer<vtkRenderWindow> renderWindow =
            vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer( renderer );

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
            vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow( renderWindow );

    renderer->ResetCamera();
    renderWindow->Render();

    renderWindowInteractor->Start();
    return 0;

单个矩形的三角构造:

    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    points->InsertPoint(0, 0, 0, 0);
    points->InsertPoint(1, 1, 0, 0);
    points->InsertPoint(2, 1, 1, 0);
    points->InsertPoint(3, 0, 1, 0);

    //vtkIdType pts[8] =  0, 1, 2, 3, 4, 5, 6, 7 ;
    vtkSmartPointer<vtkCellArray> poly = vtkSmartPointer<vtkCellArray>::New();
    vtkIdType pts1[3] =  0, 1, 3 ;
    poly->InsertNextCell( 3, pts1 );
    vtkIdType pts2[3] =  3, 1, 2 ;
    poly->InsertNextCell( 3, pts2 );

    vtkSmartPointer<vtkPolyData> pd = vtkSmartPointer<vtkPolyData>::New();
    pd->SetPoints( points );
    pd->SetPolys( poly );

以上是关于VTK三角化3D物体的表面的主要内容,如果未能解决你的问题,请参考以下文章

Threejs 开发3D地图实践总结

Threejs 开发3D地图实践总结

Threejs 开发 3D 地图实践总结

Unity3D绘制物体表面三角形网格

UE4 FBX静态网格物体通道

WebGL学习之法线贴图