-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtentacle_sample.py
233 lines (176 loc) · 8.8 KB
/
tentacle_sample.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import sys,os
from CCDIK.ik_chain import IKChain
from CCDIK.ik_actor import IKActor
from CCDIK.utils import *
from direct.actor.Actor import Actor
from panda3d.core import *
if __name__ == "__main__":
from direct.showbase.ShowBase import ShowBase
from CCDIK.camera_control import CameraControl
class MyApp(ShowBase):
def __init__(self):
###########################################
## Basic window setup:
ShowBase.__init__(self)
base.disable_mouse()
base.set_frame_rate_meter(True)
wp = WindowProperties()
wp.set_size(1800, 960)
self.win.request_properties(wp)
base.set_background_color(0,0,0)
###########################################
## Visualize grid:
grid = create_grid( 20, 1 )
render.attach_new_node( grid )
axes = create_axes( 1000, bothways=True, thickness=3 )
render.attach_new_node( axes )
###########################################
## Set up lights:
light = PointLight("PointLight")
light.set_color_temperature( 5000 )
#light.attenuation = (1, 0.5, 0.5)
light.attenuation = (0.75, 0, 0.05)
light_node = render.attach_new_node( light )
light_node.set_pos( 0, 0, 3 )
render.set_light( light_node )
#light.set_shadow_caster(True, 1024, 1024, -2000 ) # low sort value to render early!
alight = AmbientLight('alight')
alight.set_color((0.5, 0.5, 0.5, 1))
alnp = render.attach_new_node(alight)
render.set_light(alnp)
############################################
## Set up model:
self.model = loader.load_model( "Meshes/Tentacle.bam" )
self.root = render.attach_new_node("Root")
self.root.set_pos( 0, 0, 2 )
############################################
## Create an IKActor which will generate control nodes for each bone:
self.ik_actor = IKActor( self.model )
self.ik_actor.reparent_to( self.root )
############################################
## Set up an IK Chain by passing the bone names which should be part of the chain
## to the IKActor:
joint_names = []
joint_names.append( "Bone" )
for i in range(1,8):
joint_names.append( f"Bone.{i:03d}" )
self.ik_chain = self.ik_actor.create_ik_chain( joint_names )
self.ik_chain.set_annealing_exponent( 3 )
# Set constraints:
self.ik_chain.get_ik_joint( "Bone" ).set_ball_constraint( min_ang=-math.pi*0.9, max_ang=math.pi*0.9 )
for i in range(1,8):
# Set X-axis constraint for bones with even index
if i % 2 == 0:
self.ik_chain.get_ik_joint( f"Bone.{i:03d}" ).set_hinge_constraint( LVector3f.unit_x(),
min_ang=-math.pi*0.6, max_ang=math.pi*0.6 )
# Set Z-axis constraint for the others:
else:
self.ik_chain.get_ik_joint( f"Bone.{i:03d}" ).set_hinge_constraint( LVector3f.unit_z(),
min_ang=-math.pi*0.6, max_ang=math.pi*0.6 )
# Visualize the joints:
self.ik_chain.debug_display( line_length=0.5 )
self.racket = None
##################################
## Target point:
point = create_point( thickness=10 )
self.ik_target = render.attach_new_node( point )
self.task_mgr.add( self.move_target, "MoveTarget" )
self.ik_chain.set_target( self.ik_target )
############################################
## Set up camera:
focus_node = render.attach_new_node( "CameraFocusNode" )
self.cam_control = CameraControl( camera, self.mouseWatcherNode )
self.taskMgr.add( self.cam_control.move_camera, "MoveCameraTask")
############################################
## Set up controls:
self.accept( "wheel_down", self.cam_control.wheel_down )
self.accept( "wheel_up", self.cam_control.wheel_up )
self.animate_target = True
self.animation_time = 0
self.accept( "p", self.toggle_animation )
self.accept( "j-repeat", self.move_root_down )
self.accept( "k-repeat", self.move_root_up )
self.accept( "j", self.move_root_down )
self.accept( "k", self.move_root_up )
self.accept( "1", self.set_hinge_constraints )
self.accept( "2", self.set_ball_constraints )
self.accept( "r", self.toggle_racket )
self.accept( "+", self.increase_annealing_exponent )
self.accept( "-", self.decrease_annealing_exponent )
label("[WASD]: Move Camera", 1)
label("[Mouse Wheel]: Zoom Camera", 2)
label("[Middle Mouse]: Rotate Camera", 3)
label("[P]: Pause Animation", 5)
label("[J]: Move Root Down", 6)
label("[K]: Move Root Up", 7)
label("[1]: Use Hinge Constraints", 8)
label("[2]: Use Ball Constraints", 9)
label("[R]: Attach a racket to the end effector bone", 11)
label("[+]: Increase annealing exponent", 13)
label("[-]: Decrease annealing exponent", 14)
self.info_texts = {}
self.update_info()
print("---------------------------------")
print("Full tree:")
render.ls()
print("---------------------------------")
def move_target( self, task ):
if self.animate_target:
speed = 0.4
self.ik_target.set_pos( 2.5*math.sin(speed*self.animation_time),
13*math.sin(speed*self.animation_time*1.6+2),
math.cos(speed*self.animation_time*1.6+2) )
self.animation_time += globalClock.get_dt()
self.ik_chain.update_ik()
return task.cont
def set_hinge_constraints( self ):
# Set constraints:
self.ik_chain.get_ik_joint( "Bone" ).set_hinge_constraint( LVector3f.unit_z(),
min_ang=-math.pi*0.9, max_ang=math.pi*0.9 )
for i in range(1,8):
# Set X-axis constraint for bones with even index
if i % 2 == 0:
self.ik_chain.get_ik_joint( f"Bone.{i:03d}" ).set_hinge_constraint( LVector3f.unit_x(),
min_ang=-math.pi*0.6, max_ang=math.pi*0.6 )
# Set Z-axis constraint for the others:
else:
self.ik_chain.get_ik_joint( f"Bone.{i:03d}" ).set_hinge_constraint( LVector3f.unit_z(),
min_ang=-math.pi*0.6, max_ang=math.pi*0.6 )
self.ik_chain.debug_display( line_length=0.5 )
def set_ball_constraints( self ):
# Set constraints:
self.ik_chain.get_ik_joint( "Bone" ).set_ball_constraint(
min_ang=-math.pi*0.9, max_ang=math.pi*0.9 )
for i in range(1,8):
self.ik_chain.get_ik_joint( f"Bone.{i:03d}" ).set_ball_constraint(
min_ang=-math.pi*0.6, max_ang=math.pi*0.6 )
self.ik_chain.debug_display( line_length=0.5 )
def toggle_racket( self ):
if self.racket:
self.racket.remove_node()
self.racket = None
else:
self.racket = create_racket()
end_effector = self.ik_chain.get_ik_joint( f"Bone.007" )
self.racket.reparent_to( end_effector.control_node )
def increase_annealing_exponent( self ):
cur = self.ik_chain.get_annealing_exponent()
self.ik_chain.set_annealing_exponent( cur + 1 )
self.update_info()
def decrease_annealing_exponent( self ):
cur = self.ik_chain.get_annealing_exponent()
self.ik_chain.set_annealing_exponent( cur - 1 )
self.update_info()
def move_root_up( self ):
self.root.set_pos( self.root.get_pos() + LVector3f.unit_z()*globalClock.get_dt()*3 )
def move_root_down( self ):
self.root.set_pos( self.root.get_pos() - LVector3f.unit_z()*globalClock.get_dt()*3 )
def toggle_animation( self ):
self.animate_target = (self.animate_target == False)
def update_info( self ):
for k, v in self.info_texts.items():
v.remove_node()
self.info_texts["annealing"] = \
info( f"Annealing exponent: {self.ik_chain.get_annealing_exponent()}", 1 )
app = MyApp()
app.run()