Menu

BoundingBox GLPipe

Help
2019-06-19
2019-07-12
  • Jack Houben

    Jack Houben - 2019-06-19

    Hello I am starting my journey in the world of GLScene…
    I’m using Delphi Rio (10.3.1) and GLScene 1.8.

    First I built my own mouse control: zoom and pan, like in AutoCad.
    Second I build some routines to draw parts of railpipes for a rollercoaster.

    Now I’trying to zoom the whole scene (all visible pipes).
    First I tried to get the BoundingBox of several pipes (TGLPipes). But these are stuck at -0.5,-0.5,-0.5 to 0.5.0.5.0.5. Is this not implemented yet?

    After that I created a MeshObjects on a GLFreeForm with GLFeedback1.BuildMeshFromBuffer. This will give rouphly x,y, and z coordinates for the bounding boxes.

    Now again I’m challenged on how to convert these world coordinates to, projected, view coordinates, not screen!

    Bear with me… It’s my first GLScene project.

    Kind regards,
    DaSteelMan

     
  • shine world

    shine world - 2019-06-19

    For panning the solution is move camera and target dummy box contemporaneously.
    I do that using right key pressed:

    procedure TGLSceneFrame.GLSceneViewerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
      // stores mouse coordinates when a button went down
      FMDX := X;
      FMDY := Y;
    end;
    
    procedure TGLSceneFrame.GLSceneViewerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    var
      DX: Integer;
      DY: Integer;
      VT: TAffineVector;
      VTA: TAffineVector;
      VTS: TAffineVector;
      VTW: TAffineVector;
    begin
      // calculates delta since last move or last mousedown
      DX := FMDX - X;
      DY := FMDY - Y;
      FMDX := X;
      FMDY := Y;
    
      // if pressed right mouse button, and not in follow tool mode, moves camera and camera target to get panning in H&V
      if (ssRight in Shift) and not FollowTool then
      begin
        VT := CameraTarget.Position.AsAffineVector;
        VTA := GLScene.Objects.LocalToAbsolute(VT);
        VTS := GLSceneViewer.Buffer.WorldToScreen(VTA);
        VTS[0] := VTS[0] + DX;
        VTS[1] := VTS[1] - DY;
        VTW := GLSceneViewer.Buffer.ScreenToWorld(VTS);
        CameraTarget.Position.AsAffineVector := VTW;
        Camera.Position.AsAffineVector := VectorAdd(Camera.Position.AsAffineVector, VectorSubtract(VTW, VT));
      end;
    end;
    

    Like in attached video.

    For Zoom to FIT I was unable to get a valid solution at yet.

     

    Last edit: shine world 2019-06-19
  • Jerome.D (BeanzMaster)

    Hi to fit you all scene on screen you can try GLCamera1.ZoomAll(GLSceneViewer1.Buffer); but not sure it is working properly

    Cheers

     
  • Jerome.D (BeanzMaster)

    Hi for fit scene after GLCamera1.ZoomAll(GLSceneViewer1.Buffer);
    you must add GLCamera1.TransformationChanged; far validating the changes

    Cheers

    EDIT : You can also try : GLCamera.DepthOfView:=2*DCRootWorld.BoundingSphereRadiusUnscaled
    Where DCRootWorld is the DummyCube wich is contains all your objets

     

    Last edit: Jerome.D (BeanzMaster) 2019-06-19
    • shine world

      shine world - 2019-06-20

      Jerome there is a fast/simple way to get a DummyCube containing all scene visibible objects ?

       
      • Jerome.D (BeanzMaster)

        What do you mean by "get" ? Copy or retreive all visible object in the DummyCube ?

         
  • Jack Houben

    Jack Houben - 2019-06-20

    @Jerome.D: ZoomAll zooms out way to much, that is why I was trying to get the size in projection of the view and then adjustdistancetotarget accordingly. I still have to find out how...

    @shine world: Thanks for the example of pan. I saw a lot of weird solutions... I have my camera targeted to a DummyCube. Left mousebutton for orbit, right mousbutton for pan. This makes my pan very simple:

    PanRatio := 0.128*Camera.DistanceToTarget/Camera.FocalLength;
    
    ...
    // Berekenen afstand naar vorige punt
    dx := mdx - x;
    dy := mdy - y;
    mdx := x;
    mdy := y;
    
    if (ssRight in Shift) then
      begin
        // Pan
        Camera.MoveInEyeSpace(0,-PanRatio*dx,PanRatio*dy);
        Camera.MoveTargetInEyeSpace(0,PanRatio*dx,-PanRatio*dy);
      end;
    
     
    • Jerome.D (BeanzMaster)

      @Jack for fit try this :
      i've modified ZoomAll function a little bit, it seems to work well enought

      procedure FitScene;
      var
        extent: Single;
        Ratio : Single;
      begin
        with GLSceneViewer1.Buffer do
        begin
         Ratio := 1.5*DummyCubeRoot.BoundingSphereRadiusUnscaled/GLCamera1.FocalLength;
      
          if Viewport.Height < Viewport.Width then Extent := Viewport.Height * Ratio
          else Extent := Viewport.Width * Ratio;
      
          GLCamera1.Position.DirectVector := NullHmgPoint;
          GLCamera1.Move(-GLCamera1.NearPlane * Extent);
          // let the camera look at the scene center
          GLCamera1.Direction.SetVector(-GLCamera1.Position.X, -GLCamera1.Position.Y, -GLCamera1.Position.Z, 0);
        end;
      //  GLCamera1.ZoomAll(GLSceneViewer1.Buffer);
        GLCamera1.TransformationChanged;
      end; 
      

      Now for pan, i understand what you searched to do :P

       

      Last edit: Jerome.D (BeanzMaster) 2019-06-20
  • Jack Houben

    Jack Houben - 2019-06-20

    Super!

     
  • shine world

    shine world - 2019-06-20

    Tried the Jerome.D solution :)

    I need extra work but seem to be the right way !

    Thanks a lot

    PS: a odd hourglass appears after zoom to fit.
    What mean ?

     

    Last edit: shine world 2019-06-20
    • Jerome.D (BeanzMaster)

      Yes but like i could see BoundingBoxes in DummyCube are not updated when you move a child object. I'll see more deeply where the update of those are made in the GLscene's code

      PS: a odd hourglass appears after zoom to fit. I think is cause by the transformationchanged function and should depend of the complexity of the scene

       
  • tambok

    tambok - 2019-06-20

    hi,
    i tried Jerome.D solution,
    but did not work on Orthogonal projection in my project..

    the panning is neither not work, accept from shine world codes.

    regards
    tbk

     
  • Jerome.D (BeanzMaster)

    Hi with Orthogonal need somme other calculs. In waiting i've found better solution

    Uses
      GLGeometryBB;
    
    procedure FitToScreen
    var
      extent: Single;
      Ratio : Single;
      Dist : Single;
      AABB : TAABB;
    begin
      with GLSceneViewer1.Buffer do
      begin  
        AABB := DummyCubeRoot.AxisAlignedBoundingBox();
        Dist := VectorDistance(AABB.Min, AABB.Max);
        Ratio := 0.35*Dist/GLCamera1.FocalLength;
    
        if Viewport.Height < Viewport.Width then Extent := Viewport.Height * Ratio
        else Extent := Viewport.Width * Ratio;
    
        GLCamera1.Position.DirectVector := NullHmgPoint;
        GLCamera1.Move(-GLCamera1.NearPlane * Extent);
        // let the camera look at the scene center
        GLCamera1.Direction.SetVector(-GLCamera1.Position.X, -GLCamera1.Position.Y, -GLCamera1.Position.Z, 0);
      end;
    end;  
    
     
  • Jack Houben

    Jack Houben - 2019-06-28

    Hello,
    My UI start to get shape... I used the bendingcyl demo as a starting point.
    Very satisfied the way pan, zoom, dolly-zoom and orbit worked out. Pan thanks to shine world!
    I'll start on the zoom to fit now.

    This UI demo nicely shows how the camera frustum is shaped. See the second form for this.

    What I miss out on:
    1) When I start the program the near plane does not fit the sceneviewer. Do I always need to set the cameras SceneScale for this? Or don't I understand the basics?
    2) Is there a rule of thumb for a model in meters and camera distance and focal distance? In the UI demo you'll see model can't be set to full screen (without scenescale that is). You can change SceneScale by holding the ALT-key when zooming. Setting SceneScale to 0.12 will show the near plane of the frustum...
    3) How can I let a cadencer continue to work when a second form is opened?
    4) Is the near plane always connected to focal distance, or can it be set seperately?

    The source for my UI demo is attached.
    What do you tink about the camera actions?

    Kind regards,
    DaSteelMan

     
  • Jack Houben

    Jack Houben - 2019-07-12

    Update.

    I solved boundingbox for TGLPipe on a basic level: For every node check for max and min, take radius into account. This whil give you a boundingbox that can be off by +radius

    The code to implement in TGLPipe is attached.

    function TGLPipe.AxisAlignedDimensionsUnscaled: TVector;
    //******************************************************
    var
      count: Integer;
      locRadius: Single;
    
      dMin, dMax: TAffineVector;
    begin
      // JJH 12/07/2019
    
      // Estimate of GLPipe BoundingBox
      // Check dimensions for every node and radius
    
      locRadius := Radius * TGLPipeNode(Nodes[0]).RadiusFactor;
    
      dMin.X := nodes[0].X - locRadius;
      dMin.Y := nodes[0].Y - locRadius;
      dMin.Z := nodes[0].Z - locRadius;
    
      dMax.X := nodes[0].X + locRadius;
      dMax.Y := nodes[0].Y + locRadius;
      dMax.Z := nodes[0].Z + locRadius;
    
      for count := 1 to nodes.Count -1 do
      begin
        locRadius := Radius * TGLPipeNode(Nodes[count]).RadiusFactor;
    
        dMin.X := Min(dMin.X,nodes[count].X - locRadius);
        dMin.Y := Min(dMin.Y,nodes[count].Y - locRadius);
        dMin.Z := Min(dMin.Z,nodes[count].Z - locRadius);
    
        dMax.X := Max(dMax.X,nodes[count].X + locRadius);
        dMax.Y := Max(dMax.Y,nodes[count].Y + locRadius);
        dMax.Z := Max(dMax.Z,nodes[count].Z + locRadius);
      end;
    
      Result.X := (dMax.X - dMin.X) * 0.5;
      Result.Y := (dMax.Y - dMin.Y) * 0.5;
      Result.Z := (dMax.Z - dMin.Z) * 0.5;
      Result.W := 0;
    
      // AxisAlignedDimensionsUnscaled
    end;
    
    function TGLPipe.BarycenterAbsolutePosition: TVector;
    //***************************************************
    var
      count: Integer;
      locRadius: Single;
    
      dMin, dMax: TAffineVector;
    begin
      // JJH 12/07/2019
    
      // Estimate of GLPipe BarycenterAbsolutePosition
      // Check dimensions for every node and radius
    
      locRadius := Radius * TGLPipeNode(Nodes[0]).RadiusFactor;
    
      dMin.X := nodes[0].X - locRadius;
      dMin.Y := nodes[0].Y - locRadius;
      dMin.Z := nodes[0].Z - locRadius;
    
      dMax.X := nodes[0].X + locRadius;
      dMax.Y := nodes[0].Y + locRadius;
      dMax.Z := nodes[0].Z + locRadius;
    
      for count := 1 to nodes.Count -1 do
      begin
        locRadius := Radius * TGLPipeNode(Nodes[count]).RadiusFactor;
    
        dMin.X := Min(dMin.X,nodes[count].X - locRadius);
        dMin.Y := Min(dMin.Y,nodes[count].Y - locRadius);
        dMin.Z := Min(dMin.Z,nodes[count].Z - locRadius);
    
        dMax.X := Max(dMax.X,nodes[count].X + locRadius);
        dMax.Y := Max(dMax.Y,nodes[count].Y + locRadius);
        dMax.Z := Max(dMax.Z,nodes[count].Z + locRadius);
      end;
    
      Result.X := (dMax.X + dMin.X) * 0.5;
      Result.Y := (dMax.Y + dMin.Y) * 0.5;
      Result.Z := (dMax.Z + dMin.Z) * 0.5;
      Result.W := 0;
    
      // BarycenterAbsolutePosition
    end;
    
    function TGLPipe.BoundingBox(const AIncludeChilden: Boolean;
      const AUseBaryCenter: Boolean): THmgBoundingBox;
    var
      CurrentBaryOffset: TVector;
    //**********************************************************
    begin
      // JJH 12/07/2019
    
      Result := AABBToBB(AxisAlignedBoundingBox(AIncludeChilden));
    
      // DaStr: code not tested...
      if AUseBaryCenter then
      begin
        CurrentBaryOffset :=
          VectorAdd(AbsoluteToLocal(BarycenterAbsolutePosition),
          Position.AsVector);
        OffsetBBPoint(Result, CurrentBaryOffset);
      end;
    
      // BoundingBox
    end;
    
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.