rendererNOGLFWexample.py

You can view and download this file on Github: rendererNOGLFWexample.py

  1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2# This is an EXUDYN example
  3#
  4# Details:  An example for offline rendering and merging of images with a ball jumping on ground
  5#
  6# Author:   Johannes Gerstmayr
  7# Date:     2026-02-07
  8#
  9# Copyright:This file is part of Exudyn. Exudyn is free software. You can redistribute it and/or modify it under the terms of the Exudyn license. See 'LICENSE.txt' for more details.
 10#
 11#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12
 13import exudyn as exu
 14#a local run must not open a plot window when windows are suppressed (#2477)
 15if exu.special.userInterface.suppressPlots: import matplotlib; matplotlib.use('Agg')
 16from exudyn.utilities import InertiaSphere, MarkerBodyRigid, SensorBody
 17import exudyn.graphics as graphics
 18import numpy as np
 19
 20useGraphics = False # without test
 21
 22testSolution = 0
 23
 24SC = exu.SystemContainer()
 25mbs = SC.AddSystem()
 26
 27
 28radius=0.06
 29mass = 0.2                              #mass in kg
 30contactStiffness = 2e5*10               #stiffness of spring-damper in N/m
 31contactDamping = 1e-4*contactStiffness  #damping constant in N/(m/s); as we have always contact, we only need some damping for initial effects
 32dynamicFriction = 0.3
 33
 34isExplicitSolver = False
 35tEnd = 2.5     #end time of simulation
 36
 37stepSize = 5e-4 #*10
 38
 39g = 9.81
 40
 41size = 2.5
 42
 43quadEdges = graphics.Lines([[-0.5*size,-0.5*size,0],
 44                           [ 0.5*size,-0.5*size,0],
 45                           [ 0.5*size, 0.5*size,0],
 46                           [-0.5*size, 0.5*size,0],
 47                           [-0.5*size,-0.5*size,0]],color=[0.9,0.9,0.9,1]
 48                           )
 49oGround = mbs.CreateGround(graphicsDataList=[quadEdges,graphics.CheckerBoard(point=[0,0,0],size=size,
 50                                                                   color=graphics.color.lightgrey[0:3]+[graphics.material.indexChrome],
 51                                                                   alternatingColor=graphics.color.lightgrey2[0:3]+[graphics.material.indexChrome],
 52                                                                   ), ])
 53mGround = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround))
 54
 55
 56nSpheres = 5
 57
 58x = -1
 59y = 0
 60z = radius+1
 61vx = 1
 62vy = 0
 63vz = 2
 64
 65oMass = mbs.CreateRigidBody(referencePosition=[x,y,z],
 66                            initialVelocity=[vx,vy,vz],
 67                            initialAngularVelocity=[0,0,0],
 68                            nodeType=exu.NodeType.RotationEulerParameters,
 69                            inertia=InertiaSphere(mass=mass, radius=radius),
 70                            gravity = [0,0,-g],
 71                            graphicsDataList=[graphics.Sphere(radius=radius, 
 72                                                              color=graphics.color.dodgerblue,
 73                                                              nTiles=32)],
 74                            )
 75mMass = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oMass))
 76
 77quadPoints = exu.Vector3DList([[-size,-size,0],[size,-size,0],[size,size,0],[-size,size,0]])
 78oSSC = mbs.CreateSphereQuadContact(itemNumbers=[oMass, oGround],
 79                                   quadPoints=quadPoints,
 80                                   includeEdges=15, #all edges
 81                                   sphereRadius=radius,
 82                                   contactStiffness = contactStiffness,
 83                                   contactDamping = contactDamping,
 84                                   dynamicFriction=dynamicFriction,
 85                                   show = True
 86                                   )
 87sPos=mbs.AddSensor(SensorBody(bodyNumber=oMass, storeInternal=True,
 88                              outputVariableType=exu.OutputVariableType.Position))
 89
 90
 91#exu.Print(mbs)
 92mbs.Assemble()
 93
 94simulationSettings = exu.SimulationSettings()
 95simulationSettings.solution.file.write = True
 96simulationSettings.solution.file.writePeriod = 0.02
 97simulationSettings.solution.sensors.writePeriod = 0.001  #output interval
 98simulationSettings.timeIntegration.numberOfSteps = int(tEnd/stepSize)
 99simulationSettings.timeIntegration.endTime = tEnd
100#simulationSettings.timeIntegration.realtime.active = True
101simulationSettings.timeIntegration.newton.absoluteTolerance = 1e-6
102simulationSettings.timeIntegration.newton.relativeTolerance = 1e-6
103
104simulationSettings.timeIntegration.stepInformation = 3 #remove flag 64 which shows step reduction warnings
105
106
107simulationSettings.timeIntegration.newton.useModifiedNewton = True
108simulationSettings.linearSolver.solverType = exu.LinearSolverType.EigenSparse
109
110simulationSettings.show.statistics = True
111simulationSettings.timeIntegration.verboseMode = 1
112SC.visualizationSettings.openGL.lineWidth = 2
113SC.visualizationSettings.view0.scene.drawCoordinateSystem = False
114SC.visualizationSettings.general.showSolverInformation = False
115SC.visualizationSettings.connectors.showContact = False
116SC.visualizationSettings.nodes.showBasis = True
117SC.visualizationSettings.nodes.basisSize = 1.25*radius
118
119SC.visualizationSettings.loads.show = False
120
121SC.visualizationSettings.view0.window.showComputationInfo = False
122SC.visualizationSettings.general.backgroundColor = [0,0,0,1]
123
124SC.visualizationSettings.openGL.multiSampling = 2
125SC.visualizationSettings.view0.window.renderWindowSize = [700*3,400*3]
126SC.visualizationSettings.raytracer.numberOfThreads = 16
127SC.visualizationSettings.raytracer.maxReflectionDepth = 0
128SC.visualizationSettings.raytracer.maxTransparencyDepth = 0
129
130if useGraphics:
131    SC.renderer.Start()              #start graphics visualization
132
133SC.renderer.ZoomAll() #before first call to RedrawAndGetImage
134SC.renderer.SetModelView(zoom=0.85763,
135                         rotationVector=[-1.570796,0,0],
136                         centerPoint=[-0.1946863,0.7006764,0.6388125])
137
138if useGraphics:
139    SC.renderer.DoIdleTasks()    #wait for pressing SPACE bar to continue
140
141mbs.variables['dt'] = 0.075
142mbs.variables['lastRedraw'] = -mbs.variables['dt']
143mbs.variables['listImages'] = []
144def PreStepUserFunction(mbs, t):
145    """User function to store images."""
146    dt = mbs.variables['dt']
147    if t - mbs.variables['lastRedraw'] >= dt-1e-6:
148        mbs.variables['lastRedraw'] += dt
149        image = SC.renderer.RedrawAndGetImage(True)
150        mbs.variables['listImages'].append(image)
151        print('get image:', t)
152    
153    return True
154
155if not useGraphics:
156    mbs.SetPreStepUserFunction(PreStepUserFunction)
157
158
159mbs.SolveDynamic(simulationSettings)
160
161if useGraphics:
162    SC.renderer.Stop()               #safely close rendering window!
163else:
164    import matplotlib.pyplot as plt
165    if False:
166        for image in mbs.variables['listImages']:
167            plt.imshow(image)
168            plt.show(block=True)
169
170    def merge_images(image_list):
171        """Merges a list of RGB images by treating black (0,0,0) as transparent."""
172        if not image_list:
173            return None
174            
175        # Initialize the canvas with the first image
176        merged = image_list[0].astype(np.uint8)
177        
178        for i in range(1, len(image_list)):
179            # Element-wise maximum retains the non-black pixels
180            merged = np.maximum(merged, image_list[i])
181            
182        return merged
183    
184    image = merge_images(mbs.variables['listImages'])
185    plt.imshow(image)
186    plt.axis('off')
187    plt.show()
188    #make sure that directory exists:
189    plt.imsave("images/mergedImageBallContact.jpg", image)
190
191mbs.PlotSensor(sPos, components=[2])
192    
193#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
194
195mbs.SolutionViewer()