parisneo / qpanda3d Goto Github PK
View Code? Open in Web Editor NEWPanda3D wrapper for PyQt5
License: GNU General Public License v3.0
Panda3D wrapper for PyQt5
License: GNU General Public License v3.0
Hi! found that changing the lens to Ortographic, the resize function on QPanda3DWidget does not work, as the self.initial_size is declared as the self.size() value, which is a generic default from QT. Changing that to QSizeF(size.x, size.y) makes the Ortographic and Perspective lens work correctly
Hi,
love the library, but I have encountered the problem if I try to build buttons_example.py to EXE with PyInstaller. Here is Traceback which we got when trying to launch built EXE.
Warning: unable to auto-locate config files in directory named by "<auto>etc".
Known pipe types:
(all display modules loaded.)
Traceback (most recent call last):
File "buttons_example.py", line 74, in <module>
File "buttons_example.py", line 25, in __init__
File "QPanda3D\Panda3DWorld.py", line 51, in __init__
File "direct\showbase\ShowBase.py", line 339, in __init__
File "direct\showbase\ShowBase.py", line 1021, in openDefaultWindow
File "direct\showbase\ShowBase.py", line 1056, in openMainWindow
File "direct\showbase\ShowBase.py", line 766, in openWindow
File "direct\showbase\ShowBase.py", line 752, in <lambda>
File "direct\showbase\ShowBase.py", line 818, in _doOpenWindow
File "direct\showbase\ShowBase.py", line 648, in makeDefaultPipe
File "direct\directnotify\Notifier.py", line 130, in error
Exception: No graphics pipe is available!
Your Config.prc file must name at least one valid panda display
library via load-display or aux-display.
[4484] Failed to execute script buttons_example
Here is my run.spec file:
block_cipher = None
import importlib
from pathlib import Path
package_imports = [['qtmodern', ['resources/frameless.qss', 'resources/style.qss']]]
added_file = []
for package, files in package_imports:
proot = Path(importlib.import_module(package).__file__).parent
added_file.extend((proot / f, package) for f in files)
added_file.append(('D:\\Anaconda\\envs\\python_opengl\\Lib\\site-packages\\PyQt5\\Qt5\\bin\*', 'PyQt5\\Qt\\bin'))
a = Analysis(['buttons_example.py'],
pathex=['D:\\Projektai\\METOD_robotai\\Source\\ProductData\\panda_test',
'D:\\Anaconda\\envs\\python_opengl\\Lib\\site-packages'],
binaries=[],
datas=added_file,
hiddenimports=['panda3d',
'PyQt5',
'numpy',
'QPanda3D',
'openal',
'pygame'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='run',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='run')
Stack:
Hello. The following example works fine under Ubuntu 17.10 (panda3d 1.10.2, Qt 5.12.2, glxGraphicsPipe), but under mac OS Mojave (panda3d 1.10.2, Qt 5.11.1, CocoaGraphicsPipe) the clear color seems not to be active; the background stays black and "older" pixels are not cleared.
#!/usr/bin/env python3
import math
from PyQt5 import QtWidgets
from QPanda3D.QPanda3DWidget import QPanda3DWidget
from QPanda3D.Panda3DWorld import Panda3DWorld
from direct.task import Task
from panda3d.core import VBase4
class World(Panda3DWorld):
def __init__(self):
super().__init__()
self.win.setClearColorActive(True)
self.win.setClearColor(VBase4(0, 0.5, 0, 1))
self.taskMgr.add(self.spinCameraTask, 'SpinCameraTask')
self._model = self.loader.loadModel('models/panda-model')
self._model.reparentTo(self.render)
def spinCameraTask(self, task):
angle = task.time * 6 * math.pi / 180
self.camera.setPos(20 * math.sin(angle), -20 * math.cos(angle), 3)
self.camera.setHpr(angle * 180 / math.pi, 0, 0)
return Task.cont
class TestWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
widget = QPanda3DWidget(World(), self, stretch=True, keep_ratio=True)
self.setCentralWidget(widget)
self.resize(800, 600)
self.show()
self.raise_()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
win = TestWindow()
app.exec_()
Any idea ?
I implemented a small MWE to showcase the issue (see code below).
It creates four cards of random color and places them next to each other (like you would hold them in your hand when playing any kind of card game). Using 8 buttons, you can move the cards forward and backward. I observe the following behaviour: when moving cards from the back to the front, they don't go "through" the adjacent cards. Instead, it seems that the card nearest to the camera on initialization is always rendered on top on the screen, even if it should be behind any of the other cards at some point.
For comparison, you can exchange run_qt()
for run_panda3d()
at the bottom of the MWE script, which shows that when using plain Panda3D, the cards occlude each other as expected.
Tested on Windows 10, GTX 1070 Ti, Python 3.6.
I'd really appreciate if you could have a look since I was hoping to use this module to migrate the GUI for my card game from Panda's DirectGUI to Qt.
# Standard imports
import sys
# External imports
import numpy as np
from panda3d.core import *
def get_card_node_path(parent) -> NodePath:
width = 6.35
height = 8.89
thickness = 0.529
dimensions = [width / 2, height / 2, thickness / 2]
vertex_format = GeomVertexFormat().getV3n3cpt2()
vertex_data = GeomVertexData("vertex_data", vertex_format, Geom.UHStatic)
vertexCount = 0
tris = GeomTriangles(Geom.UHStatic)
vertex_writer = GeomVertexWriter(vertex_data, "vertex")
color_writer = GeomVertexWriter(vertex_data, "color")
normal_writer = GeomVertexWriter(vertex_data, "normal")
texcoord_writer = GeomVertexWriter(vertex_data, "texcoord")
for i in range(3):
for direction in (-1, 1):
normal = VBase3()
normal[i] = direction
if i == 1:
rgb = [1., 1., 1.]
else:
rgb = [np.random.rand(), np.random.rand(), np.random.rand()]
r, g, b = rgb
color = (r, g, b, 1.)
for a, b in ((-1., -1.), (-1., 1.), (1., 1.), (1., -1.)):
vertex = VBase3()
vertex[i] = direction * dimensions[i]
vertex[(i + direction) % 3] = a * dimensions[(i + direction) % 3]
vertex[(i + direction * 2) % 3] = b * dimensions[(i + direction * 2) % 3]
vertex_writer.addData3f(vertex)
color_writer.addData4f(color)
normal_writer.addData3f(normal)
if i == 2:
if direction == -1:
texcoord_writer.addData2f((1 - b) / 4, (a + 1) / 2)
else:
texcoord_writer.addData2f(0.5 + (a + 1) / 4, (b + 1) / 2)
else:
texcoord_writer.addData2f(0, 0)
vertexCount += 4
tris.addVertices(vertexCount - 2, vertexCount - 3, vertexCount - 4)
tris.addVertices(vertexCount - 4, vertexCount - 1, vertexCount - 2)
geom = Geom(vertex_data)
geom.addPrimitive(tris)
node = GeomNode("geom_node")
node.addGeom(geom)
card_np = parent.attachNewNode(node)
card_np.setPos(0, 0, 0)
return card_np
def run_qt():
loadPrcFileData('', 'back-buffers 0')
from PyQt5 import QtWidgets
from QPanda3D.Panda3DWorld import Panda3DWorld
from QPanda3D.QPanda3DWidget import QPanda3DWidget
app = QtWidgets.QApplication(sys.argv)
main_window = QtWidgets.QMainWindow()
main_window.setGeometry(50, 50, 800, 600)
world = Panda3DWorld()
panda_widget = QPanda3DWidget(world)
main_window.setCentralWidget(panda_widget)
main_window.show()
# add lights
ambient_light = AmbientLight('ambient_light')
ambient_light.setColor(VBase4(1, 1, 1, 1))
ambient_light_np = world.render.attachNewNode(ambient_light)
world.render.setLight(ambient_light_np)
directional_light = DirectionalLight('directional_light')
directional_light.setColor(VBase4(1, 1, 1, 1))
directional_light_np = world.camera.attachNewNode(directional_light)
world.render.setLight(directional_light_np)
# position camera
world.camera.setPos(0, -50, 50)
world.camera.lookAt(0, 0, 0)
# add cards
num_cards = 4
cards = [get_card_node_path(world.render) for _ in range(num_cards)]
for i, np in enumerate(cards):
np.setPos(i * 2, 10 - i, -5)
np.lookAt(np, 0, 0, -1)
# add GUI
layout = QtWidgets.QGridLayout()
widget = QtWidgets.QWidget(parent=panda_widget)
def move(index, direction):
np = cards[index]
np.setPos(np, 0, 0, direction)
print("Moved card #{}".format(index))
for index in range(num_cards):
button = QtWidgets.QPushButton("Move #{} forward".format(index))
button.clicked.connect(lambda state, x=index: move(x, -1))
layout.addWidget(button, 1, index)
button = QtWidgets.QPushButton("Move #{} backwards".format(index))
button.clicked.connect(lambda state, x=index: move(x, 1))
layout.addWidget(button, 0, index)
widget.setLayout(layout)
widget.show()
# run
sys.exit(app.exec_())
def run_panda3d():
from direct.showbase.ShowBase import ShowBase
from direct.gui.DirectGui import DirectButton
base = ShowBase()
base.disableMouse()
# add lights
ambient_light = AmbientLight('ambient_light')
ambient_light.setColor(VBase4(1, 1, 1, 1))
ambient_light_np = render.attachNewNode(ambient_light)
render.setLight(ambient_light_np)
directional_light = DirectionalLight('directional_light')
directional_light.setColor(VBase4(1, 1, 1, 1))
directional_light_np = camera.attachNewNode(directional_light)
render.setLight(directional_light_np)
# position camera
camera.setPos(0, -50, 50)
camera.lookAt(0, 0, 0)
# add cards
num_cards = 4
cards = [get_card_node_path(render) for _ in range(num_cards)]
for i, np in enumerate(cards):
np.setPos(i * 2, 10 - i, -5)
np.lookAt(np, 0, 0, -1)
# add GUI
def move(index, direction):
np = cards[index]
np.setPos(np, 0, 0, direction)
print("Moved card #{}".format(index))
# Add button
for index in range(num_cards):
DirectButton(
text=("Move #{} backwards".format(index)),
scale=.05,
command=lambda x=index: move(x, 1),
pos=(-0.9 + 0.6 * index, 0, 0.9)
)
DirectButton(
text=("Move #{} forward".format(index)),
scale=.05,
command=lambda x=index: move(x, -1),
pos=(-0.9 + 0.6 * index, 0, 0.8)
)
# run
base.run()
if __name__ == '__main__':
run_qt()
Hello, I'm struggling to find out how to make a working rectangular selection using QPanda3D, the library is great and I don't wanna abandon my project. Any thoughts would be great
Panda topic
For now, only few keyboard touches are supported and forwarded from Qt to panda3D.
A complete integration is required.
I understand that your README is stating, that mouse stuff isn't supported right now, but i tried it anyway. I'm a bit confused about the error though, because my application (without qt) was inherited by the ShowBase class like your QPanda3DWorld class. I try to access the currents mouse position via the self.win attribute of the ShowBase class, shouldn't that work anyways?
Traceback (most recent call last): ^ File "C:\Users\****\earth_plotting\venv\lib\site-packages\QPanda3D\QPanda3DWidget.py", line 35, in tick taskMgr.step() File "C:\Users\****\earth_plotting\venv\lib\site-packages\direct\task\Task.py", line 495, in step self.mgr.poll() File "EarthPlot.py", line 313, in OrbitCameraTask md = self.win.getPointer(0) AttributeError: 'panda3d.core.GraphicsBuffer' object has no attribute 'getPointer'
The code of the task producing the problem is:
def OrbitCameraTask(self,task):
delta_factor = .01 * self.camLens.getFov()[1]
md = self.win.getPointer(0)
if base.mouseWatcherNode.isButtonDown(MouseButton.one()):
self.props.setCursorHidden(True)
self.win.requestProperties(self.props)
x = md.getX()
y = md.getY()
if self.win.movePointer(0, int(self.x_mouse_position), int(self.y_mouse_position)):
self.heading = self.heading - (x - self.x_mouse_position) * delta_factor
self.pitch = self.pitch - (y - self.y_mouse_position) * delta_factor
if self.pitch > 90:
self.pitch = 90
elif self.pitch <-90:
self.pitch = -90
self.parentnode.setHpr(self.heading, self.pitch,0)
else:
self.props.setCursorHidden(False)
self.win.requestProperties(self.props)
self.x_mouse_position = md.getX()
self.y_mouse_position = md.getY()
return task.cont
Everything else seems to work fine, sadly the orbit camera is an important part of my application
I'd like to propose creating a contributor's/maintainer's guide. It would provide information about:
I can take care of this, however it would be good to discuss the details first
My suggestions:
Then we could develop some automation scripts that would test against lint errors, run unit tests (if implemented) for different Python versions. This could be handled via tox's isolated test environments, both on a local machine and GitHub Actions.
In particular python complains because the base class init expects a self (hidden first param). So I wrapped it in an init() method and it works, except:
adding:
Panda3DWorld.init(self, width=1024, height=768)
The preffered width / height has no effect.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.