是否可以在没有“渲染”对象的情况下创建物理模拟(使用 Bullet Physics Engine 和 Panda3D)
Is it possible to create physics simulation (with Bullet Physics Engine and Panda3D) without the `render` object
是否可以在没有 render
对象的情况下创建物理模拟?
我试过了,但它打印了单位矩阵:
from panda3d.bullet import BulletWorld
from panda3d.core import Vec3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
world = BulletWorld()
world.setGravity(Vec3(0, 0, -9.81))
shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
node = BulletRigidBodyNode('Box')
node.setMass(1.0)
node.addShape(shape)
world.attachRigidBody(node)
for i in range(10):
world.doPhysics(0.016)
print(node.getShapeTransform(0))
解决方案:
from panda3d.bullet import BulletWorld
from panda3d.core import TransformState, Vec3, Quat, Point3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
world = BulletWorld()
world.setGravity(Vec3(0, 0, -9.81))
shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
node = BulletRigidBodyNode('Box')
node.setMass(1.0)
p = Point3(1, 0, 0)
q = Quat.identQuat()
s = Vec3(2, 2, 2)
transform = TransformState.make_pos_quat_scale(p, q, s)
node.setTransform(transform)
node.addShape(shape)
world.attachRigidBody(node)
for i in range(10):
world.doPhysics(0.016)
print(node.getTransform())
输出:
T:(pos 1 0 0 scale 2)
T:(pos 1 0 -0.002507 scale 2)
T:(pos 1 0 -0.007521 scale 2)
T:(pos 1 0 -0.015042 scale 2)
T:(pos 1 0 -0.02507 scale 2)
T:(pos 1 0 -0.037605 scale 2)
T:(pos 1 0 -0.052647 scale 2)
T:(pos 1 0 -0.070196 scale 2)
T:(pos 1 0 -0.090252 scale 2)
T:(pos 1 0 -0.112815 scale 2)
我写了一个有趣的例子。我使用:
- 用于物理的 Panda3D Bullet 包装器
- PyQt5(和 PySide2)用于创建 window
- 用于渲染的 OpenGL 3.3
我用 Blender 和 GIMP 创建了一个带纹理的立方体。我将立方体导出到 dae (COLLADA) 并使用内置 Qt XML 解析器将其导入到我的程序中。
来源:
- PyQt5: https://rextester.com/MKV35748
- PySide2: https://rextester.com/RAHNB58294
PyQt5:
import sys
import numpy as np
from OpenGL import GL as gl
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
from PyQt5.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
from PyQt5.QtGui import QOpenGLTexture, QImage
from PyQt5.QtGui import QMatrix4x4, QVector3D, QQuaternion
from PyQt5.QtXml import QDomDocument, QDomElement
from PyQt5.QtCore import Qt, QFile, QIODevice
from PyQt5.QtCore import QTimer, QElapsedTimer
from panda3d.bullet import BulletWorld
from panda3d.core import TransformState, Vec3, Quat, Point3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
# Assets:
# Cube Texture: https://dl.dropboxusercontent.com/s/tply9ubx3n3ycvv/cube.png
# Cube Model: https://dl.dropboxusercontent.com/s/0aktc37c3nx9iq3/cube.dae
# Plane Texture: https://dl.dropboxusercontent.com/s/3iibsnvyw0vupby/plane.png
# Plane Model: https://dl.dropboxusercontent.com/s/e0wktg69ec3w8pq/plane.dae
class VertexBuffers:
vertex_pos_buffer = None
normal_buffer = None
tex_coord_buffer = None
amount_of_vertices = None
class Locations:
mvp_matrix_location = None
model_matrix_location = None
normal_matrix_location = None
class Object3D:
position = QVector3D(0, 0, 0)
rotation = QVector3D(0, 0, 0)
scale = QVector3D(1, 1, 1)
mvp_matrix = QMatrix4x4()
model_matrix = QMatrix4x4()
normal_matrix = QMatrix4x4()
def __init__(self, vert_buffers, locations, texture, world, mass, pos):
self.vert_pos_buffer = vert_buffers.vert_pos_buffer
self.normal_buffer = vert_buffers.normal_buffer
self.tex_coord_buffer = vert_buffers.tex_coord_buffer
self.amount_of_vertices = vert_buffers.amount_of_vertices
self.mvp_matrix_location = locations.mvp_matrix_location
self.model_matrix_location = locations.model_matrix_location
self.normal_matrix_location = locations.normal_matrix_location
self.texture = texture
self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
self.node = BulletRigidBodyNode('Box')
self.position = pos
self.mass = mass
self.node.setMass(self.mass)
p = Point3(self.position.x(), self.position.y(), self.position.z())
q = Quat.identQuat()
s = Vec3(1, 1, 1)
self.transform = TransformState.make_pos_quat_scale(p, q, s)
self.node.setTransform(self.transform)
self.node.addShape(self.shape)
self.world = world
self.world.attachRigidBody(self.node)
def draw(self, program, proj_view_matrix):
program.bind()
self.vert_pos_buffer.bind()
program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(0)
self.normal_buffer.bind()
program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(1)
self.tex_coord_buffer.bind()
program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
program.enableAttributeArray(2)
self.position.setX(self.node.getTransform().pos.x)
self.position.setY(self.node.getTransform().pos.y)
self.position.setZ(self.node.getTransform().pos.z)
hpr = self.node.getTransform().getHpr()
pandaQuat = Quat()
pandaQuat.setHpr(hpr)
quat = QQuaternion(pandaQuat.getX(), pandaQuat.getY(), pandaQuat.getZ(), pandaQuat.getW())
self.model_matrix.setToIdentity()
self.model_matrix.translate(self.position)
self.model_matrix.rotate(quat)
self.model_matrix.scale(self.scale)
self.mvp_matrix = proj_view_matrix * self.model_matrix
self.normal_matrix = self.model_matrix.inverted()
self.normal_matrix = self.normal_matrix[0].transposed()
program.bind()
program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
program.setUniformValue(self.model_matrix_location, self.model_matrix)
program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
self.texture.bind()
gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
class Window(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Bullet Physics")
self.resize(268, 268)
def initializeGL(self):
gl.glClearColor(0.2, 0.2, 0.2, 1)
gl.glEnable(gl.GL_DEPTH_TEST)
vertShaderSrc = """
#version 330 core
in vec4 aPosition;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;
void main()
{
gl_Position = uMvpMatrix * aPosition;
vPosition = vec3(uModelMatrix * aPosition);
vNormal = normalize(vec3(uNormalMatrix * aNormal));
vTexCoord = aTexCoord;
}
"""
fragShaderSrc = """
#version 330 core
const vec3 lightColor = vec3(0.8, 0.8, 0.8);
const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
uniform sampler2D uSampler;
in vec3 vPosition;
in vec3 vNormal;
in vec2 vTexCoord;
void main()
{
vec4 color = texture2D(uSampler, vTexCoord);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(lightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}
"""
self.program = QOpenGLShaderProgram()
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
self.program.link()
self.program.bind()
self.program.bindAttributeLocation("aPosition", 0)
self.program.bindAttributeLocation("aNormal", 1)
self.program.bindAttributeLocation("aTexCoord", 2)
locations = Locations()
self.program.bind()
locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix")
locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
self.proj_view_matrix = QMatrix4x4()
self.proj_matrix = QMatrix4x4()
self.view_matrix = QMatrix4x4()
self.view_matrix.lookAt(
QVector3D(2, 3, 5),
QVector3D(0, 0, 0),
QVector3D(0, 1, 0))
self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
self.texture.create()
self.texture.setData(QImage("assets/cube.png"))
self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
self.world = BulletWorld()
self.world.setGravity(Vec3(0, -9.81, 0))
self.obj = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=0, pos=QVector3D(0, -3, 0))
self.obj2 = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=1, pos=QVector3D(0.8, 3, 0))
#self.move_dir = 1 # move direction: 1 - up, -1 - down
#self.move_speed = 0.002
self.timer = QTimer()
self.timer.timeout.connect(self.animationLoop)
self.elapsed_timer = QElapsedTimer()
self.elapsed_timer.start()
self.delta_time = 0
self.timer.start(1000/60)
def animationLoop(self):
self.delta_time = self.elapsed_timer.elapsed()
self.elapsed_timer.restart()
self.world.doPhysics(self.delta_time / 1000)
self.update()
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.proj_view_matrix = self.proj_matrix * self.view_matrix
self.obj.draw(self.program, self.proj_view_matrix)
self.obj2.draw(self.program, self.proj_view_matrix)
def resizeGL(self, w, h):
gl.glViewport(0, 0, w, h)
self.proj_matrix.setToIdentity()
self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
def initVertexBuffers(self, path):
xml_doc = QDomDocument()
file = QFile(path)
if not file.open(QIODevice.ReadOnly):
print("Failed to open the file: " + path)
xml_doc.setContent(file)
file.close()
vert_pos_array = []
normal_array = []
tex_coord_array = []
index_array = []
root = xml_doc.documentElement()
dae_elem = root.firstChildElement()
while not dae_elem.isNull():
if dae_elem.tagName() == "library_geometries":
geom_elem = dae_elem.firstChildElement()
if geom_elem.tagName() == "geometry":
mesh_elem = geom_elem.firstChildElement()
if mesh_elem.tagName() == "mesh":
mesh_child_elem = mesh_elem.firstChildElement()
while not mesh_child_elem.isNull():
float_array_elem = mesh_child_elem.firstChildElement()
str_array = float_array_elem.firstChild().toText().data().split(" ")
if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
vert_pos_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
normal_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
tex_coord_array = list(map(float, str_array))
if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
p_child_elem = mesh_child_elem.firstChildElement()
while not p_child_elem.isNull():
if p_child_elem.tagName() == "p":
str_indices = p_child_elem.firstChild().toText().data().split(" ")
index_array = list(map(int, str_indices))
p_child_elem = p_child_elem.nextSiblingElement()
mesh_child_elem = mesh_child_elem.nextSiblingElement()
dae_elem = dae_elem.nextSiblingElement()
# print(vert_pos_array)
# print(normal_array)
# print(tex_coord_array)
# print(index_array)
num_of_attributes = 3
vert_positions = []
normals = []
tex_coords = []
for i in range(0, len(index_array), num_of_attributes):
vert_pos_index = index_array[i + 0]
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
normal_index = index_array[i + 1]
normals.append(normal_array[normal_index * 3 + 0])
normals.append(normal_array[normal_index * 3 + 1])
normals.append(normal_array[normal_index * 3 + 2])
tex_coord_index = index_array[i + 2]
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
# print(vert_positions)
# print(normals)
# print(tex_coords)
output = {}
vert_positions = np.array(vert_positions, dtype=np.float32)
vert_pos_buffer = QOpenGLBuffer()
vert_pos_buffer.create()
vert_pos_buffer.bind()
vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
normals = np.array(normals, dtype=np.float32)
normal_buffer = QOpenGLBuffer()
normal_buffer.create()
normal_buffer.bind()
normal_buffer.allocate(normals, len(normals) * 4)
tex_coords = np.array(tex_coords, dtype=np.float32)
tex_coord_buffer = QOpenGLBuffer()
tex_coord_buffer.create()
tex_coord_buffer.bind()
tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
vert_buffers = VertexBuffers()
vert_buffers.vert_pos_buffer = vert_pos_buffer
vert_buffers.normal_buffer = normal_buffer
vert_buffers.tex_coord_buffer = tex_coord_buffer
vert_buffers.amount_of_vertices = int(len(index_array) / 3)
return vert_buffers
def main():
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
PySide2:
import sys
import numpy as np
from OpenGL import GL as gl
from PySide2.QtWidgets import QApplication, QOpenGLWidget
from PySide2.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
from PySide2.QtGui import QOpenGLTexture, QImage
from PySide2.QtGui import QMatrix4x4, QVector3D, QQuaternion
from PySide2.QtXml import QDomDocument, QDomElement
from PySide2.QtCore import Qt, QFile, QIODevice
from PySide2.QtCore import QTimer, QElapsedTimer
from panda3d.bullet import BulletWorld
from panda3d.core import TransformState, Vec3, Quat, Point3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
# Assets:
# Cube Texture: https://dl.dropboxusercontent.com/s/tply9ubx3n3ycvv/cube.png
# Cube Model: https://dl.dropboxusercontent.com/s/0aktc37c3nx9iq3/cube.dae
# Plane Texture: https://dl.dropboxusercontent.com/s/3iibsnvyw0vupby/plane.png
# Plane Model: https://dl.dropboxusercontent.com/s/e0wktg69ec3w8pq/plane.dae
class VertexBuffers:
vertex_pos_buffer = None
normal_buffer = None
tex_coord_buffer = None
amount_of_vertices = None
class Locations:
mvp_matrix_location = None
model_matrix_location = None
normal_matrix_location = None
class Object3D:
position = QVector3D(0, 0, 0)
rotation = QVector3D(0, 0, 0)
scale = QVector3D(1, 1, 1)
mvp_matrix = QMatrix4x4()
model_matrix = QMatrix4x4()
normal_matrix = QMatrix4x4()
def __init__(self, vert_buffers, locations, texture, world, mass, pos):
self.vert_pos_buffer = vert_buffers.vert_pos_buffer
self.normal_buffer = vert_buffers.normal_buffer
self.tex_coord_buffer = vert_buffers.tex_coord_buffer
self.amount_of_vertices = vert_buffers.amount_of_vertices
self.mvp_matrix_location = locations.mvp_matrix_location
self.model_matrix_location = locations.model_matrix_location
self.normal_matrix_location = locations.normal_matrix_location
self.texture = texture
self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
self.node = BulletRigidBodyNode('Box')
self.position = pos
self.mass = mass
self.node.setMass(self.mass)
p = Point3(self.position.x(), self.position.y(), self.position.z())
q = Quat.identQuat()
s = Vec3(1, 1, 1)
self.transform = TransformState.make_pos_quat_scale(p, q, s)
self.node.setTransform(self.transform)
self.node.addShape(self.shape)
self.world = world
self.world.attachRigidBody(self.node)
def draw(self, program, proj_view_matrix):
program.bind()
self.vert_pos_buffer.bind()
program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(0)
self.normal_buffer.bind()
program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(1)
self.tex_coord_buffer.bind()
program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
program.enableAttributeArray(2)
self.position.setX(self.node.getTransform().pos.x)
self.position.setY(self.node.getTransform().pos.y)
self.position.setZ(self.node.getTransform().pos.z)
hpr = self.node.getTransform().getHpr()
pandaQuat = Quat()
pandaQuat.setHpr(hpr)
quat = QQuaternion(pandaQuat.getX(), pandaQuat.getY(), pandaQuat.getZ(), pandaQuat.getW())
self.model_matrix.setToIdentity()
self.model_matrix.translate(self.position)
self.model_matrix.rotate(quat)
self.model_matrix.scale(self.scale)
self.mvp_matrix = proj_view_matrix * self.model_matrix
self.normal_matrix = self.model_matrix.inverted()
self.normal_matrix = self.normal_matrix[0].transposed()
program.bind()
program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
program.setUniformValue(self.model_matrix_location, self.model_matrix)
program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
self.texture.bind()
gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
class Window(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Bullet Physics")
self.resize(268, 268)
def initializeGL(self):
gl.glClearColor(0.2, 0.2, 0.2, 1)
gl.glEnable(gl.GL_DEPTH_TEST)
vertShaderSrc = """
#version 330 core
in vec4 aPosition;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;
void main()
{
gl_Position = uMvpMatrix * aPosition;
vPosition = vec3(uModelMatrix * aPosition);
vNormal = normalize(vec3(uNormalMatrix * aNormal));
vTexCoord = aTexCoord;
}
"""
fragShaderSrc = """
#version 330 core
const vec3 lightColor = vec3(0.8, 0.8, 0.8);
const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
uniform sampler2D uSampler;
in vec3 vPosition;
in vec3 vNormal;
in vec2 vTexCoord;
void main()
{
vec4 color = texture2D(uSampler, vTexCoord);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(lightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}
"""
self.program = QOpenGLShaderProgram()
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
self.program.link()
self.program.bind()
self.program.bindAttributeLocation("aPosition", 0)
self.program.bindAttributeLocation("aNormal", 1)
self.program.bindAttributeLocation("aTexCoord", 2)
locations = Locations()
self.program.bind()
locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix")
locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
self.proj_view_matrix = QMatrix4x4()
self.proj_matrix = QMatrix4x4()
self.view_matrix = QMatrix4x4()
self.view_matrix.lookAt(
QVector3D(2, 3, 5),
QVector3D(0, 0, 0),
QVector3D(0, 1, 0))
self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
self.texture.create()
self.texture.setData(QImage("assets/cube.png"))
self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
self.world = BulletWorld()
self.world.setGravity(Vec3(0, -9.81, 0))
self.obj = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=0, pos=QVector3D(0, -3, 0))
self.obj2 = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=1, pos=QVector3D(0.8, 3, 0))
#self.move_dir = 1 # move direction: 1 - up, -1 - down
#self.move_speed = 0.002
self.timer = QTimer()
self.timer.timeout.connect(self.animationLoop)
self.elapsed_timer = QElapsedTimer()
self.elapsed_timer.start()
self.delta_time = 0
self.timer.start(1000/60)
def animationLoop(self):
self.delta_time = self.elapsed_timer.elapsed()
self.elapsed_timer.restart()
self.world.doPhysics(self.delta_time / 1000)
self.update()
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.proj_view_matrix = self.proj_matrix * self.view_matrix
self.obj.draw(self.program, self.proj_view_matrix)
self.obj2.draw(self.program, self.proj_view_matrix)
def resizeGL(self, w, h):
gl.glViewport(0, 0, w, h)
self.proj_matrix.setToIdentity()
self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
def initVertexBuffers(self, path):
xml_doc = QDomDocument()
file = QFile(path)
if not file.open(QIODevice.ReadOnly):
print("Failed to open the file: " + path)
xml_doc.setContent(file)
file.close()
vert_pos_array = []
normal_array = []
tex_coord_array = []
index_array = []
root = xml_doc.documentElement()
dae_elem = root.firstChildElement()
while not dae_elem.isNull():
if dae_elem.tagName() == "library_geometries":
geom_elem = dae_elem.firstChildElement()
if geom_elem.tagName() == "geometry":
mesh_elem = geom_elem.firstChildElement()
if mesh_elem.tagName() == "mesh":
mesh_child_elem = mesh_elem.firstChildElement()
while not mesh_child_elem.isNull():
float_array_elem = mesh_child_elem.firstChildElement()
str_array = float_array_elem.firstChild().toText().data().split(" ")
if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
vert_pos_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
normal_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
tex_coord_array = list(map(float, str_array))
if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
p_child_elem = mesh_child_elem.firstChildElement()
while not p_child_elem.isNull():
if p_child_elem.tagName() == "p":
str_indices = p_child_elem.firstChild().toText().data().split(" ")
index_array = list(map(int, str_indices))
p_child_elem = p_child_elem.nextSiblingElement()
mesh_child_elem = mesh_child_elem.nextSiblingElement()
dae_elem = dae_elem.nextSiblingElement()
# print(vert_pos_array)
# print(normal_array)
# print(tex_coord_array)
# print(index_array)
num_of_attributes = 3
vert_positions = []
normals = []
tex_coords = []
for i in range(0, len(index_array), num_of_attributes):
vert_pos_index = index_array[i + 0]
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
normal_index = index_array[i + 1]
normals.append(normal_array[normal_index * 3 + 0])
normals.append(normal_array[normal_index * 3 + 1])
normals.append(normal_array[normal_index * 3 + 2])
tex_coord_index = index_array[i + 2]
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
# print(vert_positions)
# print(normals)
# print(tex_coords)
output = {}
vert_positions = np.array(vert_positions, dtype=np.float32)
vert_pos_buffer = QOpenGLBuffer()
vert_pos_buffer.create()
vert_pos_buffer.bind()
vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
normals = np.array(normals, dtype=np.float32)
normal_buffer = QOpenGLBuffer()
normal_buffer.create()
normal_buffer.bind()
normal_buffer.allocate(normals, len(normals) * 4)
tex_coords = np.array(tex_coords, dtype=np.float32)
tex_coord_buffer = QOpenGLBuffer()
tex_coord_buffer.create()
tex_coord_buffer.bind()
tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
vert_buffers = VertexBuffers()
vert_buffers.vert_pos_buffer = vert_pos_buffer
vert_buffers.normal_buffer = normal_buffer
vert_buffers.tex_coord_buffer = tex_coord_buffer
vert_buffers.amount_of_vertices = int(len(index_array) / 3)
return vert_buffers
def main():
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
是否可以在没有 render
对象的情况下创建物理模拟?
我试过了,但它打印了单位矩阵:
from panda3d.bullet import BulletWorld
from panda3d.core import Vec3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
world = BulletWorld()
world.setGravity(Vec3(0, 0, -9.81))
shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
node = BulletRigidBodyNode('Box')
node.setMass(1.0)
node.addShape(shape)
world.attachRigidBody(node)
for i in range(10):
world.doPhysics(0.016)
print(node.getShapeTransform(0))
解决方案:
from panda3d.bullet import BulletWorld
from panda3d.core import TransformState, Vec3, Quat, Point3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
world = BulletWorld()
world.setGravity(Vec3(0, 0, -9.81))
shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
node = BulletRigidBodyNode('Box')
node.setMass(1.0)
p = Point3(1, 0, 0)
q = Quat.identQuat()
s = Vec3(2, 2, 2)
transform = TransformState.make_pos_quat_scale(p, q, s)
node.setTransform(transform)
node.addShape(shape)
world.attachRigidBody(node)
for i in range(10):
world.doPhysics(0.016)
print(node.getTransform())
输出:
T:(pos 1 0 0 scale 2)
T:(pos 1 0 -0.002507 scale 2)
T:(pos 1 0 -0.007521 scale 2)
T:(pos 1 0 -0.015042 scale 2)
T:(pos 1 0 -0.02507 scale 2)
T:(pos 1 0 -0.037605 scale 2)
T:(pos 1 0 -0.052647 scale 2)
T:(pos 1 0 -0.070196 scale 2)
T:(pos 1 0 -0.090252 scale 2)
T:(pos 1 0 -0.112815 scale 2)
我写了一个有趣的例子。我使用:
- 用于物理的 Panda3D Bullet 包装器
- PyQt5(和 PySide2)用于创建 window
- 用于渲染的 OpenGL 3.3
我用 Blender 和 GIMP 创建了一个带纹理的立方体。我将立方体导出到 dae (COLLADA) 并使用内置 Qt XML 解析器将其导入到我的程序中。
来源:
- PyQt5: https://rextester.com/MKV35748
- PySide2: https://rextester.com/RAHNB58294
PyQt5:
import sys
import numpy as np
from OpenGL import GL as gl
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
from PyQt5.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
from PyQt5.QtGui import QOpenGLTexture, QImage
from PyQt5.QtGui import QMatrix4x4, QVector3D, QQuaternion
from PyQt5.QtXml import QDomDocument, QDomElement
from PyQt5.QtCore import Qt, QFile, QIODevice
from PyQt5.QtCore import QTimer, QElapsedTimer
from panda3d.bullet import BulletWorld
from panda3d.core import TransformState, Vec3, Quat, Point3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
# Assets:
# Cube Texture: https://dl.dropboxusercontent.com/s/tply9ubx3n3ycvv/cube.png
# Cube Model: https://dl.dropboxusercontent.com/s/0aktc37c3nx9iq3/cube.dae
# Plane Texture: https://dl.dropboxusercontent.com/s/3iibsnvyw0vupby/plane.png
# Plane Model: https://dl.dropboxusercontent.com/s/e0wktg69ec3w8pq/plane.dae
class VertexBuffers:
vertex_pos_buffer = None
normal_buffer = None
tex_coord_buffer = None
amount_of_vertices = None
class Locations:
mvp_matrix_location = None
model_matrix_location = None
normal_matrix_location = None
class Object3D:
position = QVector3D(0, 0, 0)
rotation = QVector3D(0, 0, 0)
scale = QVector3D(1, 1, 1)
mvp_matrix = QMatrix4x4()
model_matrix = QMatrix4x4()
normal_matrix = QMatrix4x4()
def __init__(self, vert_buffers, locations, texture, world, mass, pos):
self.vert_pos_buffer = vert_buffers.vert_pos_buffer
self.normal_buffer = vert_buffers.normal_buffer
self.tex_coord_buffer = vert_buffers.tex_coord_buffer
self.amount_of_vertices = vert_buffers.amount_of_vertices
self.mvp_matrix_location = locations.mvp_matrix_location
self.model_matrix_location = locations.model_matrix_location
self.normal_matrix_location = locations.normal_matrix_location
self.texture = texture
self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
self.node = BulletRigidBodyNode('Box')
self.position = pos
self.mass = mass
self.node.setMass(self.mass)
p = Point3(self.position.x(), self.position.y(), self.position.z())
q = Quat.identQuat()
s = Vec3(1, 1, 1)
self.transform = TransformState.make_pos_quat_scale(p, q, s)
self.node.setTransform(self.transform)
self.node.addShape(self.shape)
self.world = world
self.world.attachRigidBody(self.node)
def draw(self, program, proj_view_matrix):
program.bind()
self.vert_pos_buffer.bind()
program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(0)
self.normal_buffer.bind()
program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(1)
self.tex_coord_buffer.bind()
program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
program.enableAttributeArray(2)
self.position.setX(self.node.getTransform().pos.x)
self.position.setY(self.node.getTransform().pos.y)
self.position.setZ(self.node.getTransform().pos.z)
hpr = self.node.getTransform().getHpr()
pandaQuat = Quat()
pandaQuat.setHpr(hpr)
quat = QQuaternion(pandaQuat.getX(), pandaQuat.getY(), pandaQuat.getZ(), pandaQuat.getW())
self.model_matrix.setToIdentity()
self.model_matrix.translate(self.position)
self.model_matrix.rotate(quat)
self.model_matrix.scale(self.scale)
self.mvp_matrix = proj_view_matrix * self.model_matrix
self.normal_matrix = self.model_matrix.inverted()
self.normal_matrix = self.normal_matrix[0].transposed()
program.bind()
program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
program.setUniformValue(self.model_matrix_location, self.model_matrix)
program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
self.texture.bind()
gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
class Window(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Bullet Physics")
self.resize(268, 268)
def initializeGL(self):
gl.glClearColor(0.2, 0.2, 0.2, 1)
gl.glEnable(gl.GL_DEPTH_TEST)
vertShaderSrc = """
#version 330 core
in vec4 aPosition;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;
void main()
{
gl_Position = uMvpMatrix * aPosition;
vPosition = vec3(uModelMatrix * aPosition);
vNormal = normalize(vec3(uNormalMatrix * aNormal));
vTexCoord = aTexCoord;
}
"""
fragShaderSrc = """
#version 330 core
const vec3 lightColor = vec3(0.8, 0.8, 0.8);
const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
uniform sampler2D uSampler;
in vec3 vPosition;
in vec3 vNormal;
in vec2 vTexCoord;
void main()
{
vec4 color = texture2D(uSampler, vTexCoord);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(lightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}
"""
self.program = QOpenGLShaderProgram()
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
self.program.link()
self.program.bind()
self.program.bindAttributeLocation("aPosition", 0)
self.program.bindAttributeLocation("aNormal", 1)
self.program.bindAttributeLocation("aTexCoord", 2)
locations = Locations()
self.program.bind()
locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix")
locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
self.proj_view_matrix = QMatrix4x4()
self.proj_matrix = QMatrix4x4()
self.view_matrix = QMatrix4x4()
self.view_matrix.lookAt(
QVector3D(2, 3, 5),
QVector3D(0, 0, 0),
QVector3D(0, 1, 0))
self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
self.texture.create()
self.texture.setData(QImage("assets/cube.png"))
self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
self.world = BulletWorld()
self.world.setGravity(Vec3(0, -9.81, 0))
self.obj = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=0, pos=QVector3D(0, -3, 0))
self.obj2 = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=1, pos=QVector3D(0.8, 3, 0))
#self.move_dir = 1 # move direction: 1 - up, -1 - down
#self.move_speed = 0.002
self.timer = QTimer()
self.timer.timeout.connect(self.animationLoop)
self.elapsed_timer = QElapsedTimer()
self.elapsed_timer.start()
self.delta_time = 0
self.timer.start(1000/60)
def animationLoop(self):
self.delta_time = self.elapsed_timer.elapsed()
self.elapsed_timer.restart()
self.world.doPhysics(self.delta_time / 1000)
self.update()
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.proj_view_matrix = self.proj_matrix * self.view_matrix
self.obj.draw(self.program, self.proj_view_matrix)
self.obj2.draw(self.program, self.proj_view_matrix)
def resizeGL(self, w, h):
gl.glViewport(0, 0, w, h)
self.proj_matrix.setToIdentity()
self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
def initVertexBuffers(self, path):
xml_doc = QDomDocument()
file = QFile(path)
if not file.open(QIODevice.ReadOnly):
print("Failed to open the file: " + path)
xml_doc.setContent(file)
file.close()
vert_pos_array = []
normal_array = []
tex_coord_array = []
index_array = []
root = xml_doc.documentElement()
dae_elem = root.firstChildElement()
while not dae_elem.isNull():
if dae_elem.tagName() == "library_geometries":
geom_elem = dae_elem.firstChildElement()
if geom_elem.tagName() == "geometry":
mesh_elem = geom_elem.firstChildElement()
if mesh_elem.tagName() == "mesh":
mesh_child_elem = mesh_elem.firstChildElement()
while not mesh_child_elem.isNull():
float_array_elem = mesh_child_elem.firstChildElement()
str_array = float_array_elem.firstChild().toText().data().split(" ")
if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
vert_pos_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
normal_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
tex_coord_array = list(map(float, str_array))
if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
p_child_elem = mesh_child_elem.firstChildElement()
while not p_child_elem.isNull():
if p_child_elem.tagName() == "p":
str_indices = p_child_elem.firstChild().toText().data().split(" ")
index_array = list(map(int, str_indices))
p_child_elem = p_child_elem.nextSiblingElement()
mesh_child_elem = mesh_child_elem.nextSiblingElement()
dae_elem = dae_elem.nextSiblingElement()
# print(vert_pos_array)
# print(normal_array)
# print(tex_coord_array)
# print(index_array)
num_of_attributes = 3
vert_positions = []
normals = []
tex_coords = []
for i in range(0, len(index_array), num_of_attributes):
vert_pos_index = index_array[i + 0]
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
normal_index = index_array[i + 1]
normals.append(normal_array[normal_index * 3 + 0])
normals.append(normal_array[normal_index * 3 + 1])
normals.append(normal_array[normal_index * 3 + 2])
tex_coord_index = index_array[i + 2]
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
# print(vert_positions)
# print(normals)
# print(tex_coords)
output = {}
vert_positions = np.array(vert_positions, dtype=np.float32)
vert_pos_buffer = QOpenGLBuffer()
vert_pos_buffer.create()
vert_pos_buffer.bind()
vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
normals = np.array(normals, dtype=np.float32)
normal_buffer = QOpenGLBuffer()
normal_buffer.create()
normal_buffer.bind()
normal_buffer.allocate(normals, len(normals) * 4)
tex_coords = np.array(tex_coords, dtype=np.float32)
tex_coord_buffer = QOpenGLBuffer()
tex_coord_buffer.create()
tex_coord_buffer.bind()
tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
vert_buffers = VertexBuffers()
vert_buffers.vert_pos_buffer = vert_pos_buffer
vert_buffers.normal_buffer = normal_buffer
vert_buffers.tex_coord_buffer = tex_coord_buffer
vert_buffers.amount_of_vertices = int(len(index_array) / 3)
return vert_buffers
def main():
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
PySide2:
import sys
import numpy as np
from OpenGL import GL as gl
from PySide2.QtWidgets import QApplication, QOpenGLWidget
from PySide2.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
from PySide2.QtGui import QOpenGLTexture, QImage
from PySide2.QtGui import QMatrix4x4, QVector3D, QQuaternion
from PySide2.QtXml import QDomDocument, QDomElement
from PySide2.QtCore import Qt, QFile, QIODevice
from PySide2.QtCore import QTimer, QElapsedTimer
from panda3d.bullet import BulletWorld
from panda3d.core import TransformState, Vec3, Quat, Point3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletRigidBodyNode
# Assets:
# Cube Texture: https://dl.dropboxusercontent.com/s/tply9ubx3n3ycvv/cube.png
# Cube Model: https://dl.dropboxusercontent.com/s/0aktc37c3nx9iq3/cube.dae
# Plane Texture: https://dl.dropboxusercontent.com/s/3iibsnvyw0vupby/plane.png
# Plane Model: https://dl.dropboxusercontent.com/s/e0wktg69ec3w8pq/plane.dae
class VertexBuffers:
vertex_pos_buffer = None
normal_buffer = None
tex_coord_buffer = None
amount_of_vertices = None
class Locations:
mvp_matrix_location = None
model_matrix_location = None
normal_matrix_location = None
class Object3D:
position = QVector3D(0, 0, 0)
rotation = QVector3D(0, 0, 0)
scale = QVector3D(1, 1, 1)
mvp_matrix = QMatrix4x4()
model_matrix = QMatrix4x4()
normal_matrix = QMatrix4x4()
def __init__(self, vert_buffers, locations, texture, world, mass, pos):
self.vert_pos_buffer = vert_buffers.vert_pos_buffer
self.normal_buffer = vert_buffers.normal_buffer
self.tex_coord_buffer = vert_buffers.tex_coord_buffer
self.amount_of_vertices = vert_buffers.amount_of_vertices
self.mvp_matrix_location = locations.mvp_matrix_location
self.model_matrix_location = locations.model_matrix_location
self.normal_matrix_location = locations.normal_matrix_location
self.texture = texture
self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
self.node = BulletRigidBodyNode('Box')
self.position = pos
self.mass = mass
self.node.setMass(self.mass)
p = Point3(self.position.x(), self.position.y(), self.position.z())
q = Quat.identQuat()
s = Vec3(1, 1, 1)
self.transform = TransformState.make_pos_quat_scale(p, q, s)
self.node.setTransform(self.transform)
self.node.addShape(self.shape)
self.world = world
self.world.attachRigidBody(self.node)
def draw(self, program, proj_view_matrix):
program.bind()
self.vert_pos_buffer.bind()
program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(0)
self.normal_buffer.bind()
program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
program.enableAttributeArray(1)
self.tex_coord_buffer.bind()
program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
program.enableAttributeArray(2)
self.position.setX(self.node.getTransform().pos.x)
self.position.setY(self.node.getTransform().pos.y)
self.position.setZ(self.node.getTransform().pos.z)
hpr = self.node.getTransform().getHpr()
pandaQuat = Quat()
pandaQuat.setHpr(hpr)
quat = QQuaternion(pandaQuat.getX(), pandaQuat.getY(), pandaQuat.getZ(), pandaQuat.getW())
self.model_matrix.setToIdentity()
self.model_matrix.translate(self.position)
self.model_matrix.rotate(quat)
self.model_matrix.scale(self.scale)
self.mvp_matrix = proj_view_matrix * self.model_matrix
self.normal_matrix = self.model_matrix.inverted()
self.normal_matrix = self.normal_matrix[0].transposed()
program.bind()
program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
program.setUniformValue(self.model_matrix_location, self.model_matrix)
program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
self.texture.bind()
gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
class Window(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Bullet Physics")
self.resize(268, 268)
def initializeGL(self):
gl.glClearColor(0.2, 0.2, 0.2, 1)
gl.glEnable(gl.GL_DEPTH_TEST)
vertShaderSrc = """
#version 330 core
in vec4 aPosition;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
out vec3 vPosition;
out vec3 vNormal;
out vec2 vTexCoord;
void main()
{
gl_Position = uMvpMatrix * aPosition;
vPosition = vec3(uModelMatrix * aPosition);
vNormal = normalize(vec3(uNormalMatrix * aNormal));
vTexCoord = aTexCoord;
}
"""
fragShaderSrc = """
#version 330 core
const vec3 lightColor = vec3(0.8, 0.8, 0.8);
const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
uniform sampler2D uSampler;
in vec3 vPosition;
in vec3 vNormal;
in vec2 vTexCoord;
void main()
{
vec4 color = texture2D(uSampler, vTexCoord);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(lightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}
"""
self.program = QOpenGLShaderProgram()
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
self.program.link()
self.program.bind()
self.program.bindAttributeLocation("aPosition", 0)
self.program.bindAttributeLocation("aNormal", 1)
self.program.bindAttributeLocation("aTexCoord", 2)
locations = Locations()
self.program.bind()
locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix")
locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
self.proj_view_matrix = QMatrix4x4()
self.proj_matrix = QMatrix4x4()
self.view_matrix = QMatrix4x4()
self.view_matrix.lookAt(
QVector3D(2, 3, 5),
QVector3D(0, 0, 0),
QVector3D(0, 1, 0))
self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
self.texture.create()
self.texture.setData(QImage("assets/cube.png"))
self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
self.world = BulletWorld()
self.world.setGravity(Vec3(0, -9.81, 0))
self.obj = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=0, pos=QVector3D(0, -3, 0))
self.obj2 = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=1, pos=QVector3D(0.8, 3, 0))
#self.move_dir = 1 # move direction: 1 - up, -1 - down
#self.move_speed = 0.002
self.timer = QTimer()
self.timer.timeout.connect(self.animationLoop)
self.elapsed_timer = QElapsedTimer()
self.elapsed_timer.start()
self.delta_time = 0
self.timer.start(1000/60)
def animationLoop(self):
self.delta_time = self.elapsed_timer.elapsed()
self.elapsed_timer.restart()
self.world.doPhysics(self.delta_time / 1000)
self.update()
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.proj_view_matrix = self.proj_matrix * self.view_matrix
self.obj.draw(self.program, self.proj_view_matrix)
self.obj2.draw(self.program, self.proj_view_matrix)
def resizeGL(self, w, h):
gl.glViewport(0, 0, w, h)
self.proj_matrix.setToIdentity()
self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
def initVertexBuffers(self, path):
xml_doc = QDomDocument()
file = QFile(path)
if not file.open(QIODevice.ReadOnly):
print("Failed to open the file: " + path)
xml_doc.setContent(file)
file.close()
vert_pos_array = []
normal_array = []
tex_coord_array = []
index_array = []
root = xml_doc.documentElement()
dae_elem = root.firstChildElement()
while not dae_elem.isNull():
if dae_elem.tagName() == "library_geometries":
geom_elem = dae_elem.firstChildElement()
if geom_elem.tagName() == "geometry":
mesh_elem = geom_elem.firstChildElement()
if mesh_elem.tagName() == "mesh":
mesh_child_elem = mesh_elem.firstChildElement()
while not mesh_child_elem.isNull():
float_array_elem = mesh_child_elem.firstChildElement()
str_array = float_array_elem.firstChild().toText().data().split(" ")
if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
vert_pos_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
normal_array = list(map(float, str_array))
if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
tex_coord_array = list(map(float, str_array))
if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
p_child_elem = mesh_child_elem.firstChildElement()
while not p_child_elem.isNull():
if p_child_elem.tagName() == "p":
str_indices = p_child_elem.firstChild().toText().data().split(" ")
index_array = list(map(int, str_indices))
p_child_elem = p_child_elem.nextSiblingElement()
mesh_child_elem = mesh_child_elem.nextSiblingElement()
dae_elem = dae_elem.nextSiblingElement()
# print(vert_pos_array)
# print(normal_array)
# print(tex_coord_array)
# print(index_array)
num_of_attributes = 3
vert_positions = []
normals = []
tex_coords = []
for i in range(0, len(index_array), num_of_attributes):
vert_pos_index = index_array[i + 0]
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
normal_index = index_array[i + 1]
normals.append(normal_array[normal_index * 3 + 0])
normals.append(normal_array[normal_index * 3 + 1])
normals.append(normal_array[normal_index * 3 + 2])
tex_coord_index = index_array[i + 2]
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
# print(vert_positions)
# print(normals)
# print(tex_coords)
output = {}
vert_positions = np.array(vert_positions, dtype=np.float32)
vert_pos_buffer = QOpenGLBuffer()
vert_pos_buffer.create()
vert_pos_buffer.bind()
vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
normals = np.array(normals, dtype=np.float32)
normal_buffer = QOpenGLBuffer()
normal_buffer.create()
normal_buffer.bind()
normal_buffer.allocate(normals, len(normals) * 4)
tex_coords = np.array(tex_coords, dtype=np.float32)
tex_coord_buffer = QOpenGLBuffer()
tex_coord_buffer.create()
tex_coord_buffer.bind()
tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
vert_buffers = VertexBuffers()
vert_buffers.vert_pos_buffer = vert_pos_buffer
vert_buffers.normal_buffer = normal_buffer
vert_buffers.tex_coord_buffer = tex_coord_buffer
vert_buffers.amount_of_vertices = int(len(index_array) / 3)
return vert_buffers
def main():
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()