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