Skip to content

Commit 7517593

Browse files
committed
added ccd and proximity demos
1 parent 243c4f0 commit 7517593

7 files changed

+141
-13
lines changed

07_direct_manipulation_delta_blendshape.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from PyQt5 import QtWidgets, QtCore
55
from pyrr import Matrix44
66
from util_moderngl_qt import DrawerMesh, QGLWidgetViewer3, DrawerSpheres
7-
from util_moderngl_qt.drawer_transform_multi import DrawerTransformMulti
87
from del_msh import WavefrontObj, TriMesh, PolygonMesh, BlendShape
98

109

@@ -66,9 +65,9 @@ def mouse_press_callback(self, event):
6665
vtx2xyz = self.weights.transpose().dot(self.shape2pos).reshape(-1, 3) # current shape
6766
src, direction = self.glwidget.nav.picking_ray()
6867
self.vtx_pick = TriMesh.pick_vertex(
68+
self.tri2vtx, vtx2xyz.astype(numpy.float32),
6969
numpy.array(src.xyz).astype(numpy.float32),
70-
numpy.array(direction.xyz).astype(numpy.float32),
71-
vtx2xyz.astype(numpy.float32), self.tri2vtx)
70+
numpy.array(direction.xyz).astype(numpy.float32))
7271
if self.vtx_pick == -1:
7372
return
7473
assert self.vtx_pick < self.tri2vtx.shape[0]
@@ -110,9 +109,9 @@ def mouse_doubleclick_callback(self, event):
110109
vtx2xyz = self.weights.transpose().dot(self.shape2pos).reshape(-1, 3) # current shape
111110
src, direction = self.glwidget.nav.picking_ray()
112111
vtx_pick = TriMesh.pick_vertex(
112+
self.tri2vtx, vtx2xyz.astype(numpy.float32),
113113
numpy.array(src.xyz).astype(numpy.float32),
114-
numpy.array(direction.xyz).astype(numpy.float32),
115-
vtx2xyz.astype(numpy.float32), self.tri2vtx)
114+
numpy.array(direction.xyz).astype(numpy.float32))
116115
for vtx in self.markers.copy():
117116
len = numpy.linalg.norm(vtx2xyz[vtx_pick] - vtx2xyz[vtx])
118117
if len < 0.03:

08_direct_manipulation_absolute_blendshape.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ def mouse_press_callback(self, event):
5757
vtx2xyz = self.weights.transpose().dot(self.shape2pos).reshape(-1, 3) # current shape
5858
src, direction = self.glwidget.nav.picking_ray()
5959
self.vtx_pick = TriMesh.pick_vertex(
60+
self.tri2vtx, vtx2xyz.astype(numpy.float32),
6061
numpy.array(src.xyz).astype(numpy.float32),
61-
numpy.array(direction.xyz).astype(numpy.float32),
62-
vtx2xyz.astype(numpy.float32), self.tri2vtx)
62+
numpy.array(direction.xyz).astype(numpy.float32))
6363
print(self.vtx_pick)
6464
if self.vtx_pick == -1:
6565
return

21_bvh.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import pathlib
2+
3+
import numpy
24
import moderngl
35
from PyQt5 import QtWidgets
46

57
from util_moderngl_qt import DrawerMesh, DrawerMeshUnindex, QGLWidgetViewer3
68
from del_msh import BVH, TriMesh
79

810

9-
def main():
11+
def main(is_morton: bool):
1012
path_file = pathlib.Path('.') / 'asset' / 'bunny_1k.obj'
1113
tri2vtx, vtx2xyz = TriMesh.load_wavefront_obj(str(path_file), is_centerize=True, normalized_size=1.)
12-
bvh, aabb = TriMesh.bvh_aabb(tri2vtx, vtx2xyz)
14+
bvhnodes = TriMesh.bvhnodes_tri(tri2vtx, vtx2xyz, is_morton)
15+
aabbs = TriMesh.aabbs_tri(tri2vtx, vtx2xyz, bvhnodes)
1316
#
1417
edge2vtx = TriMesh.edge2vtx(tri2vtx, vtx2xyz.shape[0])
1518
drawer_mesh = DrawerMesh.Drawer(
@@ -20,7 +23,7 @@ def main():
2023
]
2124
)
2225
#
23-
aabb_edges = BVH.edges_of_aabb(aabb)
26+
aabb_edges = BVH.edges_of_aabb(aabbs)
2427
drawer_aabb = DrawerMeshUnindex.Drawer(elem2node2xyz=aabb_edges)
2528
#
2629
with QtWidgets.QApplication([]) as app:
@@ -30,4 +33,5 @@ def main():
3033

3134

3235
if __name__ == "__main__":
33-
main()
36+
main(False)
37+
main(True)

22_bvh_self_intersection.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ def main():
1212
tri2vtx, vtx2xyz = TriMesh.load_wavefront_obj(str(path_file), is_centerize=True, normalized_size=1.)
1313
vtx2xyz1 = vtx2xyz + numpy.array([0.2, 0.2, 0.2], dtype=numpy.float32)
1414
tri2vtx, vtx2xyz = TriMesh.merge(tri2vtx, vtx2xyz, tri2vtx, vtx2xyz1)
15-
bvh, aabb = TriMesh.bvh_aabb(tri2vtx, vtx2xyz)
16-
edge2node2xyz, edge2tri = BVH.self_intersection_trimesh3(tri2vtx, vtx2xyz, bvh, aabb)
15+
bvhnodes = TriMesh.bvhnodes_tri(tri2vtx, vtx2xyz)
16+
aabbs = TriMesh.aabbs_tri(tri2vtx, vtx2xyz, bvhnodes)
17+
edge2node2xyz, edge2tri = TriMesh.self_intersection(tri2vtx, vtx2xyz, bvhnodes, aabbs)
1718
# print(edge2node2xyz, edge2tri)
1819
#
1920
edge2vtx = TriMesh.edge2vtx(tri2vtx, vtx2xyz.shape[0])

25_bvh_ccd.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import pathlib
2+
import moderngl
3+
from PyQt5 import QtWidgets
4+
import numpy
5+
6+
from util_moderngl_qt import DrawerMesh, DrawerCylinders, QGLWidgetViewer3
7+
from del_msh import BVH, TriMesh
8+
9+
10+
def main():
11+
path_file = pathlib.Path('.') / 'asset' / 'bunny_1k.obj'
12+
tri2vtx, vtx2xyz0 = TriMesh.load_wavefront_obj(str(path_file), is_centerize=True, normalized_size=1.)
13+
edge2vtx = TriMesh.edge2vtx(tri2vtx, vtx2xyz0.shape[0])
14+
# print(edge2vtx)
15+
vtx2uvw = numpy.zeros_like(vtx2xyz0)
16+
vtx2uvw[:, 0] += - 10 * numpy.power(vtx2xyz0[:, 0], 3) \
17+
* numpy.exp(-10 * numpy.power(vtx2xyz0[:, 1], 2)) \
18+
* numpy.exp(-10 * numpy.power(vtx2xyz0[:, 2], 2))
19+
vtx2xyz1 = vtx2xyz0 + 1.0 * vtx2uvw
20+
bvhnodes, roots = TriMesh.bvhnodes_vtxedgetri(edge2vtx, tri2vtx, vtx2xyz0)
21+
aabbs = TriMesh.aabb_vtxedgetri(edge2vtx, tri2vtx, vtx2xyz0, bvhnodes, roots, vtx2xyz1=vtx2xyz1)
22+
pairs, times = TriMesh.ccd_intersection_time(edge2vtx, tri2vtx, vtx2xyz0, vtx2xyz1, bvhnodes, aabbs, roots)
23+
intersecting_time = numpy.min(times)
24+
#
25+
vtx2xyz1 = vtx2xyz0 + intersecting_time * 0.999 * vtx2uvw
26+
edge2node2xyz, edge2tri = TriMesh.self_intersection(tri2vtx, vtx2xyz1, bvhnodes, aabbs, roots[2])
27+
assert edge2node2xyz.shape[0] == 0
28+
#
29+
vtx2xyz1 = vtx2xyz0 + intersecting_time * 1.001 * vtx2uvw
30+
edge2node2xyz, edge2tri = TriMesh.self_intersection(tri2vtx, vtx2xyz1, bvhnodes, aabbs, roots[2])
31+
assert edge2node2xyz.shape[0] != 0
32+
33+
drawer_mesh = DrawerMesh.Drawer(
34+
vtx2xyz=vtx2xyz1,
35+
list_elem2vtx=[
36+
DrawerMesh.ElementInfo(index=edge2vtx, color=(0, 0, 0), mode=moderngl.LINES),
37+
# DrawerMesh.ElementInfo(index=tri2vtx, color=(1, 1, 0), mode=moderngl.TRIANGLES)
38+
]
39+
)
40+
drawer_intersection = DrawerCylinders.Drawer()
41+
drawer_intersection.rad = 0.005
42+
for edge in edge2node2xyz[:]:
43+
drawer_intersection.list_cylinder.append(
44+
DrawerCylinders.CylinderInfo(pos0=edge[0], pos1=edge[1]))
45+
#
46+
47+
with QtWidgets.QApplication([]) as app:
48+
glwidget = QGLWidgetViewer3.QtGLWidget_Viewer3([drawer_mesh, drawer_intersection])
49+
glwidget.show()
50+
app.exec()
51+
52+
53+
if __name__ == "__main__":
54+
main()

26_bvh_proximity.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import pathlib
2+
import moderngl
3+
from PyQt5 import QtWidgets
4+
import numpy
5+
6+
from util_moderngl_qt import DrawerMesh, DrawerCylinders, QGLWidgetViewer3
7+
from del_msh import BVH, TriMesh
8+
9+
10+
def main():
11+
tri2vtx, vtx2xyz0 = TriMesh.sphere(1., ndiv_latitude=32, ndiv_longtitude=32)
12+
edge2vtx = TriMesh.edge2vtx(tri2vtx, vtx2xyz0.shape[0])
13+
# print(edge2vtx)
14+
vtx2uvw = numpy.zeros_like(vtx2xyz0)
15+
vtx2uvw[:, 0] += -numpy.power(vtx2xyz0[:, 0], 3)
16+
vtx2xyz1 = vtx2xyz0 + 0.995 * vtx2uvw
17+
18+
contacting_pair, contacting_coord = TriMesh.contacting_pair(tri2vtx, vtx2xyz1, edge2vtx, 0.01)
19+
print(contacting_pair, contacting_coord)
20+
print(contacting_pair.shape, contacting_coord.shape)
21+
22+
drawer_mesh = DrawerMesh.Drawer(
23+
vtx2xyz=vtx2xyz1,
24+
list_elem2vtx=[
25+
DrawerMesh.ElementInfo(index=edge2vtx, color=(0, 0, 0), mode=moderngl.LINES),
26+
# DrawerMesh.ElementInfo(index=tri2vtx, color=(1, 1, 0), mode=moderngl.TRIANGLES)
27+
]
28+
)
29+
#
30+
drawer_intersection = DrawerCylinders.Drawer()
31+
drawer_intersection.rad = 0.003
32+
for ic in range(len(contacting_pair)):
33+
if contacting_pair[ic, 2] == 1: # triangle - vertex pair
34+
it = contacting_pair[ic, 0]
35+
iv = contacting_pair[ic, 1]
36+
ap = vtx2xyz1[tri2vtx[it, :], :]
37+
p = contacting_coord[ic, :3].dot(ap)
38+
q = vtx2xyz1[iv, :]
39+
drawer_intersection.list_cylinder.append(
40+
DrawerCylinders.CylinderInfo(pos0=p, pos1=q))
41+
elif contacting_pair[ic, 2] == 0: # edge - edge pair
42+
ie0 = contacting_pair[ic, 0]
43+
ie1 = contacting_pair[ic, 1]
44+
ap0 = vtx2xyz1[edge2vtx[ie0, :], :]
45+
ap1 = vtx2xyz1[edge2vtx[ie1, :], :]
46+
p0 = contacting_coord[ic, 0:2].dot(ap0)
47+
p1 = contacting_coord[ic, 2:4].dot(ap1)
48+
drawer_intersection.list_cylinder.append(
49+
DrawerCylinders.CylinderInfo(pos0=ap0[0], pos1=ap0[1], color=(0., 1., 0.)))
50+
drawer_intersection.list_cylinder.append(
51+
DrawerCylinders.CylinderInfo(pos0=ap1[0], pos1=ap1[1]))
52+
53+
with QtWidgets.QApplication([]) as app:
54+
glwidget = QGLWidgetViewer3.QtGLWidget_Viewer3([drawer_mesh, drawer_intersection])
55+
glwidget.show()
56+
app.exec()
57+
58+
59+
if __name__ == "__main__":
60+
main()

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,13 @@ user interface for selecting/unselecting triangles
9292
## [24_deform_mls_ui.py](24_deform_mls_ui.py)
9393
<img src="https://raw.githubusercontent.com/nobuyuki83/demos_py_qt_mdngl/doc/24_thumbnail.png" width=320>
9494

95+
## [25_bvh_ccd.py](25_bvh_ccd.py)
96+
Continuous collision detection
97+
98+
<img src="https://raw.githubusercontent.com/nobuyuki83/demos_py_qt_mdngl/doc/25_thumbnail.png" width=320>
99+
100+
## [26_bvh_proximity.py](26_bvh_proximity.py)
101+
Detect near face-vertex and edge-edge pairs
102+
103+
<img src="https://raw.githubusercontent.com/nobuyuki83/demos_py_qt_mdngl/doc/26_thumbnail.png" width=320>
104+

0 commit comments

Comments
 (0)