15 Replies Latest reply on Apr 13, 2018 12:57 PM by Jacob Corder

    (C#) Using OpenGL to render in Solidworks

    Daniel Mansour

      Hello, I'm using Solidworks 2016, the Solidworks C# addin template, and OpenTK.

       

      I am having a problem when attempting to render anything programmatically with OpenGL in Solidworks. I have run into several conflicting statements regarding rendering what I want in the window.

       

      Source 1: Using OpenGL with VBO's in SolidWorks problem

      Tony Van De Velde is attempting to use VBOs to render using the ModelView.BufferSwapNotify event handler. He initially is able to render using OpenGL's Immediate Mode, but finds that rendering VBOs needs to happen in the event handler so that it may be rendered after Solidworks Layer0 which is the part/assembly graphical output.

       

      Source 2: Help me about OpenGL!

      Lenny Yang is attempting to draw into SolidWorks using the OpenGL interface in Visual Basic. Several other questions are asked and answered regarding the context used to draw in. The answer by Artem Taturevych is vague regarding why we should ignore what the API documentation recommends using for drawing to the context.

       

      I currently am getting visible OpenGL renderings when I draw using the following code:

       

      Code
      // in EventHandling.cs

      public class DocView
      {
        ISldWorks iSwApp;
        SwAddin userAddin;
        ModelView mView;
        DocumentEventHandler parent;

        private GLControl glControl;

       

        public DocView(SwAddin addin, IModelView mv, DocumentEventHandler doc)
        {
           userAddin = addin;
           mView = (ModelView)mv;
           iSwApp = (ISldWorks)userAddin.SwApp;
           parent = doc;

           glControl = new GLControl();         // Program does not work without this
           glControl.Context.MakeCurrent(null); // Program does not work without this
        }

       

        public bool AttachEventHandlers()

        {

           mView.DestroyNotify2 += new DModelViewEvents_DestroyNotify2EventHandler(OnDestroy);

           mView.RepaintNotify += new DModelViewEvents_RepaintNotifyEventHandler(OnRepaint);

           mView.BufferSwapNotify += OnBufferSwapNotify;

           return true;

        }

       

          public bool DetachEventHandlers()

        {

           mView.DestroyNotify2 -= new DModelViewEvents_DestroyNotify2EventHandler(OnDestroy);

           mView.RepaintNotify -= new DModelViewEvents_RepaintNotifyEventHandler(OnRepaint);

           mView.BufferSwapNotify -= OnBufferSwapNotify;

           parent.DetachModelViewEventHandler(mView);

           return true;

        }

       

        public int OnBufferSwapNotify()

        {

            #region RENDER_SIMPLE_LINE
            GL.LineWidth(3);

       

            GL.Begin(PrimitiveType.Triangles);
                GL.Vertex3(0.0f, 0.0f, 0.0f);
                GL.Vertex3(0.5f, 0.5f, 0.5f);
                GL.Vertex3(0.0f, 1.0f, 0.0f);
            GL.End();
            #endregion

            return 0;
        }

      }

       

       

      Note the green highlighted lines. The program does not run without them. What they do is set an OpenGL context and then release the context. I'm not understanding what context I'm drawing into since the program does not run without first setting a custom context but then releasing it.

       

      My question: Why does drawing to the context work like this? Which GL context should I aim to draw to?

       

      I'm not sure what's going on but I am getting renderings with whatever shading was available prior to the event handler drawing. I want to know why this is possible and why I should be ignoring what the API documentation says since that doesn't seem to work when I try to mimic it.

       

      2017 SOLIDWORKS API Help - InitializeShading Method (IModelView)

       

      Maybe I'm misunderstanding what I need to be rendering with the InitializeShading method? Should I draw the vertices prior to calling InitializeShading and then set the lighting/textures after?

       

      Any help is appreciated.

       

      Message was edited by: Daniel Mansour Reason: Cleaned formatting of code. Made question more specific.

        • Re: (C#) Using OpenGL to render in Solidworks
          Amen Allah Jlili

          Does the glcontrol work? I have had trouble using it in the past (Couldn't add it to the vs toolbox).

            • Re: (C#) Using OpenGL to render in Solidworks
              Jacob Corder

              I use the SharpGl library. It seems a little slow maybe. But it is .net based.

                • Re: (C#) Using OpenGL to render in Solidworks
                  Simon Turner

                  I use Tao OpenGL, which I think is similar to SharpGL in that it is just a .net wrapper for the opengl32.dll and glu32.dll files

                  Using that, I don't need to create a new context or MakeCurrent. I can just start using opengl drawing routines straight away.

                  I put all drawing commands into the BufferSwapNotify event.

                  • Re: (C#) Using OpenGL to render in Solidworks
                    Daniel Mansour

                    Thank you for the recommendation. I'll take a look at SharpGL. I see that the library hasn't been updated for a few years. Is it an actively maintained project?

                    • Re: (C#) Using OpenGL to render in Solidworks
                      Amen Allah Jlili

                      I'll definitely try that.

                      • Re: (C#) Using OpenGL to render in Solidworks
                        Simon Turner

                        Hi Jacob,

                         

                        just a quick question - I have decided to take a look at SharpGL. How do you create / get the context to draw into the SolidWorks model view?

                         

                        Thanks!

                          • Re: (C#) Using OpenGL to render in Solidworks
                            Jacob Corder
                                Sub CreateCone(ByVal ConeStartPt() As Double, ByVal ConeEndPt() As Double, ByVal Topradius As Double, ByVal TipRadius As Double, ByVal ConeHeight As Double)
                                    Dim glUObj As IntPtr = NativeMethods.gluNewQuadric()
                                    NativeMethods.glEnable(SharpGL.OpenGL.GL_CULL_FACE)
                                    NativeMethods.glMatrixMode(SharpGL.OpenGL.GL_MODELVIEW)
                                    NativeMethods.glPushMatrix()
                                    Dim IsFlipped As Boolean = False
                                    SetTranslation(ConeStartPt, ConeEndPt, IsFlipped)
                                    SetRotation(ConeStartPt, ConeEndPt, IsFlipped)
                                    NativeMethods.gluQuadricNormals(glUObj, SharpGL.OpenGL.GLU_SMOOTH)
                                    NativeMethods.gluCylinder(glUObj, Topradius, TipRadius, ConeHeight, slices, stacks)
                                    NativeMethods.glPopMatrix()
                                End Sub
                            
                            
                            
                            

                             

                            Sub SetRotation(ByVal Stpt() As Double, ByVal EndPt() As Double, ByVal IsFlipped As Boolean)
                                    Dim Dx As Double = 0
                                    Dim DY As Double = 0
                                    Dim DZ As Double = 0
                                    Dim vx As Double = 0
                                    Dim vy As Double = 0
                                    Dim vz As Double = 0
                            
                            
                                    If IsFlipped = False Then
                                        Dx = EndPt(0) - Stpt(0)
                                        DY = EndPt(1) - Stpt(1)
                                        DZ = EndPt(2) - Stpt(2)
                                        vx = Stpt(0) - EndPt(0)
                                        vy = Stpt(1) - EndPt(1)
                                        vz = Stpt(2) - EndPt(2)
                                    Else
                                        Dx = Stpt(0) - EndPt(0)
                                        DY = Stpt(1) - EndPt(1)
                                        DZ = Stpt(2) - EndPt(2)
                                        vx = EndPt(0) - Stpt(0)
                                        vy = EndPt(1) - Stpt(1)
                                        vz = EndPt(2) - Stpt(2)
                                    End If
                                    Dim az As Double = Math.Atan2(DY, Dx) * RadToDeg
                                    Dim v As Double = Math.Sqrt(vx * vx + vy * vy + vz * vz)
                                    Dim el As Double = Math.Acos(DZ / v) * RadToDeg
                            
                            
                                    Dim rx As Double = -(vy * vz)
                                    Dim ry As Double = +(vx * vz)
                                    Dim ax As Double = 0
                                    If vz = 0 Then
                                        ax = RadToDeg * Math.Acos(vx / v) 'Rotation angle in x-z plane
                                        If vx <= 0 Then ax = -ax
                                        NativeMethods.glRotated(az, 0, 0, 1) 'Rotate and align with X Axis
                                        NativeMethods.glRotated(el, 0, 1, 0) 'Rotate to point 2 in x-y plane
                                    Else
                                        ax = RadToDeg * Math.Acos(vz / v) 'Rotation Angle
                                        If vz <= 0 Then ax = -ax
                                        NativeMethods.glRotated(ax, rx, ry, 0)
                                    End If
                            
                            
                                End Sub
                            

                             

                             Sub SetTranslation(ByRef Stpt() As Double, ByRef EndPt() As Double, ByRef IsFlipped As Boolean)
                                    IsFlipped = False
                                    If IsNothing(Stpt) Then Exit Sub '
                                    If IsNothing(EndPt) Then Exit Sub
                                    If Stpt(0) = EndPt(0) And Stpt(2) = EndPt(2) And Stpt(2) < EndPt(1) Then
                                        NativeMethods.glTranslated(EndPt(0), EndPt(1), EndPt(2))
                                        IsFlipped = True
                                    ElseIf Stpt(0) < EndPt(0) And Stpt(2) = EndPt(2) And Stpt(1) = EndPt(1) Then
                                        NativeMethods.glTranslated(EndPt(0), EndPt(1), EndPt(2))
                                        IsFlipped = True
                                    Else
                                        NativeMethods.glTranslated(Stpt(0), Stpt(1), Stpt(2))
                                    End If
                                End Sub
                            

                             

                              Sub SetRotation(ByVal Stpt() As Double, ByVal EndPt() As Double, ByVal IsFlipped As Boolean)
                                    Dim Dx As Double = 0
                                    Dim DY As Double = 0
                                    Dim DZ As Double = 0
                                    Dim vx As Double = 0
                                    Dim vy As Double = 0
                                    Dim vz As Double = 0
                            
                            
                                    If IsFlipped = False Then
                                        Dx = EndPt(0) - Stpt(0)
                                        DY = EndPt(1) - Stpt(1)
                                        DZ = EndPt(2) - Stpt(2)
                                        vx = Stpt(0) - EndPt(0)
                                        vy = Stpt(1) - EndPt(1)
                                        vz = Stpt(2) - EndPt(2)
                                    Else
                                        Dx = Stpt(0) - EndPt(0)
                                        DY = Stpt(1) - EndPt(1)
                                        DZ = Stpt(2) - EndPt(2)
                                        vx = EndPt(0) - Stpt(0)
                                        vy = EndPt(1) - Stpt(1)
                                        vz = EndPt(2) - Stpt(2)
                                    End If
                                    Dim az As Double = Math.Atan2(DY, Dx) * RadToDeg
                                    Dim v As Double = Math.Sqrt(vx * vx + vy * vy + vz * vz)
                                    Dim el As Double = Math.Acos(DZ / v) * RadToDeg
                            
                            
                                    Dim rx As Double = -(vy * vz)
                                    Dim ry As Double = +(vx * vz)
                                    Dim ax As Double = 0
                                    If vz = 0 Then
                                        ax = RadToDeg * Math.Acos(vx / v) 'Rotation angle in x-z plane
                                        If vx <= 0 Then ax = -ax
                                        NativeMethods.glRotated(az, 0, 0, 1) 'Rotate and align with X Axis
                                        NativeMethods.glRotated(el, 0, 1, 0) 'Rotate to point 2 in x-y plane
                                    Else
                                        ax = RadToDeg * Math.Acos(vz / v) 'Rotation Angle
                                        If vz <= 0 Then ax = -ax
                                        NativeMethods.glRotated(ax, rx, ry, 0)
                                    End If
                            
                            
                                End Sub
                            

                             

                              Friend NotInheritable Class NativeMethods
                              <DllImport("opengl32.dll")>
                                    Public Shared Sub glTranslated(x As Double, y As Double, z As Double)
                                    End Sub
                            
                              <DllImport("opengl32.dll")>
                                    Public Shared Sub glEnable(cap As UInteger)
                                    End Sub
                            
                            <DllImport("opengl32.dll")>
                                    Public Shared Sub glMatrixMode(mode As UInteger)
                                    End Sub
                            
                              <DllImport("opengl32.dll")>
                                    Public Shared Sub glPopMatrix()
                                    End Sub
                            
                                <DllImport("opengl32.dll")>
                                    Public Shared Sub glPushMatrix()
                                    End Sub
                            end class
                            
                            
                            
                            
                            
                            
                            
                            

                             

                            you register to IView::BufferSwapNotify

                            then  you just draw using calls to <DLLImport("GLU32.dll")>

                             

                            here is an example of drawing a cone

                             

                            on bufferswapnotify this is when you execute all open gl drawing

                             

                            this above is custom for my application and hard to explain.

                             

                            all native methods are OPENGL32

                             

                            i think thats all you will need.  values are in meters if i remember correctly but angles are angles.  you will find out.

                             

                            and create cone and create cylinder are the same besides a cylinder has the same radius

                        • Re: (C#) Using OpenGL to render in Solidworks
                          Daniel Mansour

                          Thank you for your reply. The GLContext works outside of SolidWorks. I can render a window with a scene just fine using a standalone OpenTK GL application. I'm not sure why grabbing/releasing a context worked for SolidWorks (and why not using a context causes the program to crash). I'll use it for right now but would like to figure it out at some point!