Integrating Panda3d an OpenGl

I’m new to Panda3d, and I want to integrate a program that i’ve made in OpenGL(in python) with Panda3d , is it possible?

Because when i tried to run OpenGL and Panda3d together , only one of them works

Thanks for the help! :slight_smile:

How tight an integration? You can, in principle, open up a separate window with its own, separate OpenGL context, and render to that window with standard OpenGL calls while Panda renders to its own window with its own OpenGL calls.

But if you want to issue OpenGL calls for the window that Panda is also issuing OpenGL calls, you might have problems. Panda believes it’s the only one issuing OpenGL calls for a particular context, so if you issue any commands that change the graphics state when Panda isn’t looking, it can get screwed up. Also, Panda doesn’t provide any callback hooks up to Python during the middle of a frame render, so if you want to issue your custom OpenGL calls to draw an object in the scene, for instance, it’s just not going to work.

How committed are you to making raw OpenGL calls? Is it possible to convert your application to creating Panda3D constructs instead? This will be far more optimal in the long run anyway.

David

Dpsm i agree with drwr. What is the nature of your openGL calls? If they are dynamic glVertex commands i can help you convert them to panda’s geom writers or my pyro lib (which sort of does dynamic glVertex() calls from python as fast as i can figure out)

The thing i want is, for example to control the character in a Panda3d window and when he do something in the game(in panda3d) it opens a different window with some kind of “challenge” and stops Panda3d while he is doing the challenge, and after this i want to return something to Panda3d(the score of the challenge for example).
But the problem that i’m having is that when i call to open an OpenGl an a panda window in the same program , it opens both windows , but the Panda window doesn’t display anything…

thanks again for the help! :smiley:

Hmm, on reflection, I think Panda is assuming it’s the only one creating any OpenGL contexts, and so it thinks there is only one OpenGL window and therefore no need to call wglMakeCurrent() every frame.

But when you create another OpenGL context in the same process, you introduce the need to call wglMakeCurrent(). One answer is that you are sure to call wglMakeCurrent() yourself when you are done rendering, to restore the current graphics context to the Panda window.

An easier, hackier answer might be to create a second Panda window. This will force Panda to call wglMakeCurrent() to switch the contexts between its two windows.

David

So, treeform, is there a way to transform glVertex’s to something in Panda3d? Because this “challenges” doesn’t have 3d models, but only points and lines(it’s a kind of maths game)

And,drwr, so do you mean after the run() comand of Panda3d?

Thanks again!

There’s the example i’m talking:

#!/usr/bin/env pythonw

This is statement is required by the build system to query build info

if name == ‘build’:
raise Exception

import string
version = string.split(’Revision: 1.8 ’)[1]
date = string.join(string.split(’Date: 2002/12/31 04:13:56 ’)[1:3], ’ ')
author = ‘Tarn Weisner Burton twburton@users.sourceforge.net

import direct.directbase.DirectStart#import the Panda3d library

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import sys

Some api in the chain is translating the keystrokes to this octal string

so instead of saying: ESCAPE = 27, we use the following.

ESCAPE = ‘\033’

Number of the glut window.

window = 0

Rotation angle for the triangle.

rtri = 0.0

Rotation angle for the quadrilateral.

rquad = 0.0

A general OpenGL initialization function. Sets all of the initial parameters.

def InitGL(Width, Height): # We call this right after our OpenGL window is created.
glClearColor(0.0, 0.0, 0.0, 0.0) # This Will Clear The Background Color To Black
glClearDepth(1.0) # Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS) # The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST) # Enables Depth Testing
glShadeModel(GL_SMOOTH) # Enables Smooth Color Shading

glMatrixMode(GL_PROJECTION)
glLoadIdentity()                    # Reset The Projection Matrix
                                    # Calculate The Aspect Ratio Of The Window
gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)

glMatrixMode(GL_MODELVIEW)

The function called when our window is resized (which shouldn’t happen if you enable fullscreen, below)

def ReSizeGLScene(Width, Height):
if Height == 0: # Prevent A Divide By Zero If The Window Is Too Small
Height = 1

glViewport(0, 0, Width, Height)        # Reset The Current Viewport And Perspective Transformation
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)

The main drawing function.

def DrawGLScene():
global rtri, rquad

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)    # Clear The Screen And The Depth Buffer
glLoadIdentity()                    # Reset The View
glTranslatef(-1.5,0.0,-6.0)                # Move Left And Into The Screen

glRotatef(rtri,0.0,1.0,0.0)                # Rotate The Pyramid On It's Y Axis

glBegin(GL_TRIANGLES)                    # Start Drawing The Pyramid

glColor3f(1.0,0.0,0.0)            # Red
glVertex3f( 0.0, 1.0, 0.0)        # Top Of Triangle (Front)
glColor3f(0.0,1.0,0.0)            # Green
glVertex3f(-1.0,-1.0, 1.0)        # Left Of Triangle (Front)
glColor3f(0.0,0.0,1.0)            # Blue
glVertex3f( 1.0,-1.0, 1.0)

glColor3f(1.0,0.0,0.0)            # Red
glVertex3f( 0.0, 1.0, 0.0)        # Top Of Triangle (Right)
glColor3f(0.0,0.0,1.0)            # Blue
glVertex3f( 1.0,-1.0, 1.0)        # Left Of Triangle (Right)
glColor3f(0.0,1.0,0.0)            # Green
glVertex3f( 1.0,-1.0, -1.0)        # Right

glColor3f(1.0,0.0,0.0)            # Red
glVertex3f( 0.0, 1.0, 0.0)        # Top Of Triangle (Back)
glColor3f(0.0,1.0,0.0)            # Green
glVertex3f( 1.0,-1.0, -1.0)        # Left Of Triangle (Back)
glColor3f(0.0,0.0,1.0)            # Blue
glVertex3f(-1.0,-1.0, -1.0)        # Right Of


glColor3f(1.0,0.0,0.0)            # Red
glVertex3f( 0.0, 1.0, 0.0)        # Top Of Triangle (Left)
glColor3f(0.0,0.0,1.0)            # Blue
glVertex3f(-1.0,-1.0,-1.0)        # Left Of Triangle (Left)
glColor3f(0.0,1.0,0.0)            # Green
glVertex3f(-1.0,-1.0, 1.0)        # Right Of Triangle (Left)
glEnd()


glLoadIdentity()
glTranslatef(1.5,0.0,-7.0)        # Move Right And Into The Screen
glRotatef(rquad,1.0,1.0,1.0)        # Rotate The Cube On X, Y & Z
glBegin(GL_QUADS)            # Start Drawing The Cube


glColor3f(0.0,1.0,0.0)            # Set The Color To Blue
glVertex3f( 1.0, 1.0,-1.0)        # Top Right Of The Quad (Top)
glVertex3f(-1.0, 1.0,-1.0)        # Top Left Of The Quad (Top)
glVertex3f(-1.0, 1.0, 1.0)        # Bottom Left Of The Quad (Top)
glVertex3f( 1.0, 1.0, 1.0)        # Bottom Right Of The Quad (Top)

glColor3f(1.0,0.5,0.0)            # Set The Color To Orange
glVertex3f( 1.0,-1.0, 1.0)        # Top Right Of The Quad (Bottom)
glVertex3f(-1.0,-1.0, 1.0)        # Top Left Of The Quad (Bottom)
glVertex3f(-1.0,-1.0,-1.0)        # Bottom Left Of The Quad (Bottom)
glVertex3f( 1.0,-1.0,-1.0)        # Bottom Right Of The Quad (Bottom)

glColor3f(1.0,0.0,0.0)            # Set The Color To Red
glVertex3f( 1.0, 1.0, 1.0)        # Top Right Of The Quad (Front)
glVertex3f(-1.0, 1.0, 1.0)        # Top Left Of The Quad (Front)
glVertex3f(-1.0,-1.0, 1.0)        # Bottom Left Of The Quad (Front)
glVertex3f( 1.0,-1.0, 1.0)        # Bottom Right Of The Quad (Front)

glColor3f(1.0,1.0,0.0)            # Set The Color To Yellow
glVertex3f( 1.0,-1.0,-1.0)        # Bottom Left Of The Quad (Back)
glVertex3f(-1.0,-1.0,-1.0)        # Bottom Right Of The Quad (Back)
glVertex3f(-1.0, 1.0,-1.0)        # Top Right Of The Quad (Back)
glVertex3f( 1.0, 1.0,-1.0)        # Top Left Of The Quad (Back)

glColor3f(0.0,0.0,1.0)            # Set The Color To Blue
glVertex3f(-1.0, 1.0, 1.0)        # Top Right Of The Quad (Left)
glVertex3f(-1.0, 1.0,-1.0)        # Top Left Of The Quad (Left)
glVertex3f(-1.0,-1.0,-1.0)        # Bottom Left Of The Quad (Left)
glVertex3f(-1.0,-1.0, 1.0)        # Bottom Right Of The Quad (Left)

glColor3f(1.0,0.0,1.0)            # Set The Color To Violet
glVertex3f( 1.0, 1.0,-1.0)        # Top Right Of The Quad (Right)
glVertex3f( 1.0, 1.0, 1.0)        # Top Left Of The Quad (Right)
glVertex3f( 1.0,-1.0, 1.0)        # Bottom Left Of The Quad (Right)
glVertex3f( 1.0,-1.0,-1.0)        # Bottom Right Of The Quad (Right)
glEnd()                # Done Drawing The Quad


rtri  = rtri + 0.2                  # Increase The Rotation Variable For The Triangle
rquad = rquad - 0.15                 # Decrease The Rotation Variable For The Quad


#  since this is double buffered, swap the buffers to display what just got drawn.
glutSwapBuffers()

The function called whenever a key is pressed. Note the use of Python tuples to pass in: (key, x, y)

def keyPressed(*args):
# If escape is pressed, kill everything.
if args[0] == ESCAPE:
sys.exit()

def main():
global window
glutInit(sys.argv)

# Select type of Display mode:
#  Double buffer
#  RGBA color
# Alpha components supported
# Depth buffer
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)

# get a 640 x 480 window
glutInitWindowSize(640, 480)

# the window starts at the upper left corner of the screen
glutInitWindowPosition(0, 0)


window = glutCreateWindow("Jeff Molofee's GL Code Tutorial ... NeHe '99")

 
glutDisplayFunc(DrawGLScene)


# When we are doing nothing, redraw the scene.
glutIdleFunc(DrawGLScene)

# Register the function called when our window is resized.
glutReshapeFunc(ReSizeGLScene)

# Register the function called when the keyboard is pressed.
glutKeyboardFunc(keyPressed)

# Initialize our window.
InitGL(640, 480)

# Start Event Processing Engine
glutMainLoop()
#run()
#wglMakeCurrent()

Print message to console, and kick off the main to get it rolling.

print “Hit ESC key to quit.”
#run()#roda o Panda3d
#wglMakeCurrent()
main()#roda o Opengl
run()
#wglMakeCurrent()

it displays the opengl window and open the panda3d too, but it display nothing, but if i call first Panda3d, it don’t display the Opengl window…

You have bigger problems than the OpenGL context. glutMainLoop() doesn’t return. Neither does Panda’s run(). Both of these want to be the main loop of your application.

In order to integrate two different libraries that want to be the main loop, you have to choose just one of them to be the main loop, and arrange it to make callbacks into the other one. This is probably possible for both GLUT and for Panda.

But, your example is really pretty trivial. Assuming you don’t have thousands of lines of OpenGL code somewhere else, anything simple like this is probably just worth recoding in Panda instead of using raw OpenGL.

David

So, how i do to open a second Panda3d window? just type another run() command?

Thanks everybody for the help! :smiley:

Nop, the run() command is blocking.
Try base.openWindow instead.

ok, it opened the window… but the second one do everything that the main window does, if my object moves on the main window it does the same on the second one, there is a way to separate it, defining a completely different one?

base.openWindow()
newCamera = base.camList[-1]
newRender = NodePath('newRender')
newCamera.reparentTo(newRender)

Now newRender is your new scene graph, and newCamera is the camera that views it. You can put new geometry in your new scene graph and position your camera in a place to view it, and it will be drawn in the second window.

But, are you sure you really want to open a second window? That’s kind on an unusual thing for a game to do. Wouldn’t it make more sense to pop up your math game within the original window?

David

I did what you said , it worked, but there’s a little problem… when i try to create something to put on the second window , it changes the first window, and the second one remains the default grey one, take a look at the code:

 from pandac.PandaModules import Point3#importa um pacote necessário para a movimenta�o da bolinha
import direct.directbase.DirectStart # inicializa o panda3d, sem isso n� abre a janela do panda3d
from direct.gui.OnscreenText import OnscreenText # pacote que imprime texto na tela
from pandac.PandaModules import TextNode,PandaNode,NodePath 
from pandac.PandaModules import Filename
from direct.actor import Actor # pacote que cuida dos atores, ou seja objetos que tem movimento
#from direct.task.Task import Task #importa o pacote de tarefas
from direct.showbase.DirectObject import DirectObject #  �importante
#pois passa algum tipo de referencia para a classe principal(World)
import sys # fun�o aqui usada para sair com sys.exit()



class World(DirectObject):
	def __init__(self):
		#base.openWindow()
		self.newCamera = base.camList[0]
		newRender = NodePath('newRender')
		self.newCamera.reparentTo(newRender) 
		OnscreenText("World",style=1,fg=(1,1,1,1),pos=(1.3,-0.95),
                        align=TextNode.ARight,scale=.07)
		self.environ3= loader.loadModel("plano.x")
		self.environ3.reparentTo(newRender)
		base.setBackgroundColor(1.0,0.0,0.0,1.0)
		self.environ3.setScale(1,1,1)
		#base.openWindow()


class Main(DirectObject):
	def __init__(self):
		base.openWindow()
		self.newCamera = base.camList[-1]
		newRender = NodePath('newRender')
		self.newCamera.reparentTo(newRender) 
		OnscreenText("Main",style=1,fg=(1,1,1,1),pos=(1.3,-0.95),
                        align=TextNode.ARight,scale=.07)
		self.environ3= loader.loadModel("plano.x")
		self.environ3.reparentTo(newRender)
		base.setBackgroundColor(1.0,0.0,0.0,1.0)
		self.environ3.setScale(1,1,1)
		#base.openWindow()

w=World()#cria objeto da classe
#base.openWindow()
m=Main()



run()#roda o programa

is really panda creating an indepent scene graph and rendering it?

and david, the thing is that’s not me who is gonna make the math game , my part is to create an world with characters and rules and integrate that thing with my code , and making it a little bit “independent” and not having to rewrite nothing

You need to keep a pointer to newRender, e.g. call it self.newRender. Otherwise the node will go away as soon as the function ends.

Panda doesn’t create any scene graphs, per se. You create a “scene graph” by virtue of creating a node (“newRender” in this case) and using it as if it were the root of a scene graph.

Note that the normal “render” node created by default is just an ordinary node like anything else. The only reason things that are parented to render get drawn is because the camera, base.cam, is also parented to render. When you take your camera and parent it to a different node, it will render that instead. But if the node goes away, then your camera no longer has a parent and will render nothing.

Note also that the onscreen text is attached to render2d by default. This is yet another scene graph, and it is associated with the original window. If you want your onscreen text to show up on the new window, you will need to create a new render2d node also. You can use base.makeCamera2d() to create a camera suitable for rendering this render2d scene graph. Then you can pass parent = newRender2d to your OnscreenText object.

With regards to creating a new window in the first place, doing it this way doesn’t particularly achieve any code isolation or make it any easier to integrate with code another person is writing. If that other person is writing pure OpenGL code, you will still have some difficulties ahead of you in integrating it with Panda. If the other person is willing to write Panda code, then you might as well put it in the same window.

David


from pandac.PandaModules import Point3#importa um pacote necessário para a movimenta�o da bolinha
import direct.directbase.DirectStart # inicializa o panda3d, sem isso n� abre a janela do panda3d
from direct.gui.OnscreenText import OnscreenText # pacote que imprime texto na tela
from pandac.PandaModules import TextNode,PandaNode,NodePath 
from pandac.PandaModules import Filename
from direct.actor import Actor # pacote que cuida dos atores, ou seja objetos que tem movimento
#from direct.task.Task import Task #importa o pacote de tarefas
from direct.showbase.DirectObject import DirectObject #  �importante
#pois passa algum tipo de referencia para a classe principal(World)
import sys # fun�o aqui usada para sair com sys.exit()



class World(DirectObject):
	def __init__(self):
		#base.openWindow()
		#self.newCamera = base.camList[0]
		#newRender = NodePath('newRender')
		#self.newCamera.reparentTo(newRender) 
		OnscreenText("World",style=1,fg=(1,1,1,1),pos=(1.3,-0.95),
                        align=TextNode.ARight,scale=.07)
		self.environ3= loader.loadModel("plano.x")
		self.environ3.reparentTo(render)#faz com que o nó pai seja o render
		#base.setBackgroundColor(1.0,0.0,0.0,1.0)
		self.environ3.setScale(1,1,1)#define escala do objeto
		self.environ3.setPos(0,42,0)#define posicao
		self.environ3.setHpr(180,0,180)#define angulacao
		base.disableMouse()#desativa mouse p/ mexer na camera
		camera.setPosHpr(0, -15, 8, 0, 0,0)#define a posicao da camera
		self.accept("b",self.move,[1,0,0])
	
		#base.openWindow()
	def move(self,x,y,z):
		self.environ3.setPos(self.environ3.getPos()+Point3(x,y,z))


class Main(DirectObject):
	def __init__(self):
		base.openWindow()#abre uma nova janela
		self.newCamera = base.camList[-1]#cria uma camera
		self.newRender = NodePath('newRender')#cria um NodePath
		self.newCamera.reparentTo(self.newRender)#faz a camera ser filha de newRender
		#self.newCamera.reparentTo(self.newRender)
		self.newRender2d = NodePath('newRender2d')
		self.camera2d = base.makeCamera2d(base.win)
		self.camera2d.reparentTo(self.newRender2d)
		#self.newCamera2d.reparentTo(self.newRender2d)
		#parent = self.newRender2d
		OnscreenText("Main",style=1,fg=(1,1,1,1),pos=(1.3,-0.95),
                        align=TextNode.ARight,scale=.07,parent = self.newRender2d)
		#parent.reparentTo(self.newRender2d)
		self.environ4= loader.loadModel("plano.x")
		self.environ4.reparentTo(self.newRender)
		#base.setBackgroundColor(1.0,0.0,0.0,1.0)
		self.environ4.setScale(2,2,2)
		self.environ4.setPos(0,42,0)
		self.environ4.setHpr(180,0,180)
		self.newCamera.setPosHpr(0,-15,8,0,0,0)
		self.accept("a",self.Move,[1,0,0])
		
		#base.openWindow()
	def Move(self,x,y,z):
		self.environ4.setPos(self.environ4.getPos() + Point3(x,y,z) )
w=World()#cria objeto da classe
#base.openWindow()
m=Main()



run()#roda o programa

two more things…

  1. i defined a move() method that makes the object move in the two classes but when i switch to the second window and type the key on the keyboard that had to make the object move , it doesn’t move…

  2. i tried to parent the onscreentext with the newRender2d node that i’ve created , but nothing happened… there is any mistake in the code?

  1. In order to handle keyboard events that are generated through the second window, you will need to set up a buttonThrower for that window, the same way that one has already been set up on the main window. See https://discourse.panda3d.org/viewtopic.php?t=3139 for more discussion about handling mouse events in multiple windows.

  2. I think the text is there, but because the window’s coordinate system is scaled differently, it happens to be offscreen. The reason it is scaled differently is because we haven’t set up an aspect2d for the new window; you are using render2d instead. To make the scales the same, it will be necessary to create your own aspect2d node, set the appropriate scales on it, and use that as the parent for your OnscreenText.

In general, when you open a second window, you become responsible for doing all of the low-level setup that ShowBase.py did for you automatically on the main window. This is perfectly doable, but you will have to learn a lot about what Panda is doing for you automatically. Other people have done variants of this before. Try searching the forums for things like “openWindow”.

Again, I ask you: are you really sure you want a second window? Not just that it’s inconvenient to use it in Panda, but because it’s inconvenient to the user as well, and inconvenient to the developer. Not to mention that it may be more difficult for your graphics card to drive two windows (i.e. your frame rate will suffer).

David

drwr, sorry for the long time…

i wanted to do in a second window just because i was asked to do so, but i convinced the other person that was better to do it with a single window, because the game we are developing is for use in slow pc’s

so i ask you , how i do to make different things in the same window, e.g. i click in something and it changes to another scene (or send some link that helps)

Thanks for the great support!
:smiley:

You just take out the nodes that represent the previous scene, for instance by calling oldModel.removeNode() or oldModel.detachNode(), and add in the nodes that represent the new scene, for instance newModel.reparentTo(render).

The logistics of keeping track of your old models and your new models is up to your and your coding design.

David