Yet to be born CAD software using Ogre3d and G+Smo

A place for users of OGRE to discuss ideas and experiences of utilitising OGRE in their games / demos / applications.
andrecaldas
Halfling
Posts: 55
Joined: Mon May 06, 2024 1:06 am
x 4

Yet to be born CAD software using Ogre3d and G+Smo

Post by andrecaldas »

Fellow Ogres,

I am writing a CAD software that uses Ogre3d, G+Smo and pybind11. It is multithreaded and Ogre3d rendering occurs in a dedicated thread.

https://github.com/andre-caldas/ParaCADis/

The CAD data is kept in a very parametric data structure. The parameters are the essential parameters for each structure type. Because of multithreading, in order for these parameters to be accessed, a "lock" must be acquired. I call it a "gate". And you use this gate to access the data. There are gates for reading and gates for writing.

Changes to this structure are propagated, via a messaging system, to a thread (or some threads) that constructs G+Smo objects. Those objects can be used, in the near future, to do IgA (isogeometric analysis)... it is some sort of more efficient FEM (finite element method).

Changes to this other structure are propagated, via a messaging system, to the Ogre3d thread. Between the renderings, a hook is called to pull those messages and update the Ogre Scene.

Here are two very very non-exciting videos:

The script I used is here:

Code: Select all

import Ogre
import Ogre.Bites
import Ogre.RTShader

import threading

class KeyListener(Ogre.Bites.InputListener):
    def keyPressed(self, evt):
        if evt.keysym.sym == Ogre.Bites.SDLK_ESCAPE:
            Ogre.Root.getSingleton().queueEndRendering()
        return True

class App(threading.Thread):
    def run(self):
        ctx = Ogre.Bites.ApplicationContext("PySample")

        ctx.initApp()

        root = ctx.getRoot()
        self.root = root
        scn_mgr = root.createSceneManager()
        self.scn_mgr = scn_mgr

        # register for input events
        klistener = KeyListener() # must keep a reference around
        ctx.addInputListener(klistener)

        shadergen = Ogre.RTShader.ShaderGenerator.getSingleton()
        shadergen.addSceneManager(scn_mgr)  # must be done before we do anything with the scene

        # without light we would just get a black screen
        scn_mgr.setAmbientLight((.1, .1, .1))

        light = scn_mgr.createLight("MainLight")
        lightnode = scn_mgr.getRootSceneNode().createChildSceneNode()
        lightnode.setPosition(0, 10, 15)
        lightnode.attachObject(light)

        # create the camera
        cam = scn_mgr.createCamera("myCam")
        cam.setNearClipDistance(5)
        cam.setAutoAspectRatio(True)
        camnode = scn_mgr.getRootSceneNode().createChildSceneNode()
        camnode.attachObject(cam)

        # map input events to camera controls
        camman = Ogre.Bites.CameraMan(camnode)
        camman.setStyle(Ogre.Bites.CS_ORBIT)
        camman.setYawPitchDist(0, 0.3, 15)
        ctx.addInputListener(camman)
        self.camman = camman

        # and tell it to render into the main window
        vp = ctx.getRenderWindow().addViewport(cam)
        vp.setBackgroundColour((.3, .3, .3))

        # finally something to render
        ent = scn_mgr.createEntity("Sinbad.mesh")
        self.sinbad = ent
        node = scn_mgr.getRootSceneNode().createChildSceneNode()
        node.attachObject(ent)

        root.startRendering()
        ctx.closeApp()

app = App()
app.start()


import paracadis as pc
import paracadis.geometric_primitives as geo
import paracadis_scene_graph as sg


try:
  doc = pc.document.Document()
  circle = geo.CirclePointRadius2Normal([0,0,0], 25, [0,0,1])
  sphere = geo.SphereCenterSurfacePoint([0,0,0], [2,2,2])
#  doc.add_element(circle)
#  doc.add_element(sphere)

  scene = sg.Scene(app.scn_mgr)
  scene.populate(doc)
#  input('paused... press <enter>... ')
#  print('pressed enter... continuing')

  circle = geo.CirclePointRadius2Normal([0,0,1], 25, [0,0,1])
#  sphere = geo.SphereCenterSurfacePoint([1,1,1], [3,3,3])
  sphere = geo.SphereCenterRadius2([1,1,1], 25)
#  doc.add_element(sphere)

  cont_a = pc.document.Container()
  cont_a.add_element(circle)
#  cont_a.add_element(sphere)
#  pos = geo.DeferenceableCoordinatePointsXY([1,2,3])
#  cont_a.set_coordinates(pos)
  doc.add_container(cont_a)

  import time
  import math

  ref = geo.ReferenceToReal(circle, "radius2")
#  ref = geo.ReferenceToReal(sphere, "radius2")
  res = ref.resolve()
  delta = 1/10
  for x in range(100):
    print(x)
    wl = res.wgate()
    wl.access().set((4 + 3 * math.sin(time.time()))**2)
    wl = None # Release the lock
    time.sleep(delta)
except Exception as e:
  print('Exception', e)

print('End!')

For Ogre multithreading, I do not use "allowPyThread()". Instead, I have patched the Ogre SWIG configuration in order to make ogre calls in python to be thread safe without the rendering thread needing to holding the GIL lock for so long. I call "startRendering()" in a new thread, and Ogre rendering loop occurs in this thread. There is no "rendering one single frame" in the python code. Changes to the Ogre Scene (or any code to be executed between frames) are sent via messaging system. This is my Ogre3d branch:
https://github.com/andre-caldas/ogre/tr ... ringThread

In order to have a GUI, it would be nice to know how to get Ogre to render to a "canvas" inside the main window. Then the GUI could call python code and display the results, like FreeCAD does. See: viewtopic.php?t=97359