1

여기에 특별한 경우가 있는데, 나는 helix-toolkit이라는 라이브러리를 사용하고 있기 때문에 여기에 나와 있습니다.3D 모델 생성을 병렬화하는 방법은 무엇입니까?

사실 제가 backgroundworker를 사용하여 코드에서 모델 개체를 만드는 것을 병렬 처리하고 싶습니다.

나는 mutlithreading과 UI 요소 작업에 큰 문제가 있음을 알고 있지만 어떻게 든 해결 방법이 있습니다. 나는 Backgroundwoker를 생성하는

첫 번째 파일, Geometry3D 객체를 생성하고 마지막으로 뷰포트에 형상을 결합하는 SetModelGeometry을 호출하는 작업 부하를 분할 :

여기 내 코드의 거친 구조입니다. 두 번째 파일은 바인딩이 수행되는 방법을 보여줍니다.

MainWindow.xaml.cs를

private void Draw_Building() 
     { 
      _worker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; 
      _worker.DoWork += Draw_Building_DoWork; 
      _worker.ProgressChanged += DrawBuilding_ProgressChanged; 
      _worker.RunWorkerCompleted += DrawBuilding_RunWorkerCompleted; 
      _worker.RunWorkerAsync(10000); 

     } 

     private void Draw_Building_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
     { 
      // returns a list containing Geometry3D objects (created by meshBuilder.ToMeshGeometry3D()) 
      Geometryhandler.Draw_Building(sender, e); 
     } 

     private void DrawBuilding_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      StatusProgressBar.Value = e.ProgressPercentage; 
      var i = (int)e.UserState; 
      var actualComponent = MyBuildingComponents.First(c => c.Id == i); 
      LblStatusbarInfo.Text = "Currently meshing element #" + actualComponent.Globalid + " (" + 
            actualComponent.Objectname + ")"; 
      StatusProgressbarMsg.Text = "Meshing (" + e.ProgressPercentage + " %)"; 
     } 

     private void DrawBuilding_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      StatusProgressbarMsg.Text = "-"; 
      StatusProgressBar.Value = 0; 
      LblStatusbarInfo.Text = "Meshing completed."; 

      Geometry = e.Result as List<MeshIdandGeometry>; 

      // creates MeshGeometryModel3D objects and binds them to the viewport using the List of Geometries 
      MainViewModel.SetModelGeometry(Geometry); 

     } 

MainViewModel.cs

public void SetModelGeometry(List<MeshIdandGeometry> geometry) 
    { 

     MyModelGeometry = new Element3DCollection(); 

     if (geometry != null) 
     { 
      foreach (var mygeometry in geometry) 
      { 

       var s = new MeshGeometryModel3D 
       { 
        Geometry = mygeometry.Geometry, 
        Material = mygeometry.Material, 
       }; 
       this.MyModelGeometry.Add(s); 

       s.Attach(MyModelViewport.RenderHost); 
      } 

     } 

     this.OnPropertyChanged("MyModelGeometry"); 
    } 

순간 내 문제는 다음과 같은 오류 메시지입니다 :

호출 스레드 광고 때문에이 개체에 액세스 할 수 없습니다. ifferent 스레드가 소유하고 있습니다.

ModelGeometry을 뷰포트에 첨부하려고 할 때 SetModelGeometry 함수에서 발생합니다.

필자는 기하학이 다른 스레드에서 만들어졌으며 지금은 액세스 할 수 없다는 사실에 대해 컴파일러가 불평하고 있다고 생각합니다.

DrawBuilding 함수의 병렬 실행을 손상시키지 않는 해결 방법이 있습니까?

는 편집 :

편집 2 : GeometryhandlerDraw_Building 방법

Draw_Building 방법의 잘못된 버전을 게시 :

public void Draw_Building(object sender, DoWorkEventArgs e) 
    { 

     var geometry = new List<MeshIdandGeometry>(); 

     var standardMaterial = new PhongMaterial() 
     { 
      AmbientColor = SharpDX.Color.LightGray, 
      //DiffuseColor = new Color4(0.35f, 0.35f, 0.35f, 1.0f), 
      //DiffuseMap = new BitmapImage(new System.Uri(@"Con_Diffuse_2.jpg", System.UriKind.RelativeOrAbsolute)), 
      //NormalMap = new BitmapImage(new System.Uri(@"Con_Normal_2.jpg", System.UriKind.RelativeOrAbsolute)), 
     }; 

     var max = _mainWindow.MyBuildingComponents.Count; 
     var i = 1; 

     // Loop over building components 
     foreach (var component in _mainWindow.MyBuildingComponents) 
     { 

      //if (i == 5) break; 
      var component1 = component; 
      var componentTriangles = _mainWindow.MyTriangles.Where(triangle => triangle.ComponentId == component1.Id); 

       var meshBuilder = new MeshBuilder(true, true, true); 

      // Loop over triangles in building element 
      foreach (var triangle in componentTriangles) 
      { 
       var triangle1 = triangle; 

       var p1 = _mainWindow.MyVertices.Find(
        vt => vt.Id == triangle1.PointId1); 
       var p2 = _mainWindow.MyVertices.Find(
        vt => vt.Id == triangle1.PointId2); 
       var p3 = _mainWindow.MyVertices.Find(
        vt => vt.Id == triangle1.PointId3); 
       if (p1 != null && p2 != null && p3 != null) 
       { 
        //meshBuilder.AddTriangle(new Vector3((float)p1.X, (float)p1.Y, (float)p1.Z), 
        // new Vector3((float)p2.X, (float)p2.Y, (float)p2.Z), 
        // new Vector3((float)p3.X, (float)p3.Y, (float)p3.Z)); 

        // coordination are switched to match the coordinate system in SharpDX viewport 
        meshBuilder.AddTriangle(new Vector3(-(float)p1.Y, (float)p1.Z, -(float)p1.X), 
         new Vector3(-(float)p2.Y, (float)p2.Z, -(float)p2.X), 
         new Vector3(-(float)p3.Y, (float)p3.Z, -(float)p3.X)); 
       } 
      } 
      var mesh = meshBuilder.ToMeshGeometry3D(); 

      var meshandtriangle = new MeshIdandGeometry 
      { 
       Id = component1.Id, 
       Geometry = mesh, 
       Material = standardMaterial, 
      }; 
      geometry.Add(meshandtriangle); 

      i++; 
      var progressPercentage = Convert.ToInt32(((double)i/max) * 100); 
      var backgroundWorker = sender as BackgroundWorker; 
      backgroundWorker?.ReportProgress(progressPercentage, component1.Id); 
     } 

     e.Result = geometry; 

    } 
+0

Freeze and Clone 시도 – egse

+0

안녕하세요 egse, 죄송합니다. 지금 귀하의 의견을 보았습니다. 정확히 어떻게 사용합니까? 예를 들어 Media3D.GeometryModel3D 객체에 대해 고정이 구현되었지만 sharpDX 분기가 사용하는 모델 객체에 해당하는 것을 찾지 못했습니다. – Daniel

+0

네, 맞습니다. 그렇다면 오류를 일으키는 기하학이 아니라 재료라고 생각합니다. Geometryhandler.Draw_Building 메서드의 내용을 보여 주면 더 도움이 될 수 있습니다. – egse

답변

1

큰 감사 해결책을 찾기 위해 @egse 할 수 있습니다. 문제를 일으키는 코드

부분 :

var standardMaterial = new PhongMaterial() 
    { 
     AmbientColor = SharpDX.Color.LightGray, 
     //DiffuseColor = new Color4(0.35f, 0.35f, 0.35f, 1.0f), 
     //DiffuseMap = new BitmapImage(new System.Uri(@"Con_Diffuse_2.jpg", System.UriKind.RelativeOrAbsolute)), 
     //NormalMap = new BitmapImage(new System.Uri(@"Con_Normal_2.jpg", System.UriKind.RelativeOrAbsolute)), 
    }; 

기본적 상기 코드의 문제점은 재료가 BackgroundWorker에 범위 안에 로컬 변수로 생성된다는 점이다. UI 스레드가 머티리얼 객체를 입력하려고 할 때 소유권 문제가 발생합니다.

이 문제에 대한 해결책은 자료가 UI 스레드 (예 : UI 스레드)에 의해 작성되었는지 확인하는 것입니다.이 경우에는 Geometryhandler의 생성자

TL : DR : UI가 아닌 다른 스레드에서 DependencyObject에서 상속 한 클래스의 인스턴스를 만들지 마십시오.