aboutsummaryrefslogtreecommitdiff
path: root/docs/build/sections/tech_docs/components/creating_custom_component.html
blob: 3a724e0eaf33de8f0dd774d8fea4bf96b9c286be (plain) (blame)
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Creating Your Own Component &mdash; ARTv2 2.0.1 documentation</title>
  

  
  
  
  

  
  <script type="text/javascript" src="../../../_static/js/modernizr.min.js"></script>
  
    
      <script type="text/javascript" id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
        <script type="text/javascript" src="../../../_static/jquery.js"></script>
        <script type="text/javascript" src="../../../_static/underscore.js"></script>
        <script type="text/javascript" src="../../../_static/doctools.js"></script>
        <script type="text/javascript" src="../../../_static/language_data.js"></script>
    
    <script type="text/javascript" src="../../../_static/js/theme.js"></script>

    

  
  <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
    <link rel="index" title="Index" href="../../../genindex.html" />
    <link rel="search" title="Search" href="../../../search.html" />
    <link rel="next" title="Utilities" href="../utilities/utilities.html" />
    <link rel="prev" title="Camera Component" href="camera.html" /> 
</head>

<body class="wy-body-for-nav">

   
  <div class="wy-grid-for-nav">
    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >
          

          
            <a href="../../../index.html" class="icon icon-home"> ARTv2
          

          
          </a>

          
            
            
              <div class="version">
                2.0
              </div>
            
          

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

          
        </div>

        
        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
              
            
            
              <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../../installing.html">Installing ARTv2</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../using_rigging_tools.html">Using the Rigging Tools</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../using_anim_tools.html">Using the Animation Tools</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../../../technical_documentation.html">Technical Documentation</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../useful_scripting_commands.html">Useful Scripting Commands</a></li>
<li class="toctree-l2 current"><a class="reference internal" href="components.html">Components</a><ul class="current">
<li class="toctree-l3"><a class="reference internal" href="components_overview.html">Components Overview</a></li>
<li class="toctree-l3"><a class="reference internal" href="base_classes.html">Base Classes</a></li>
<li class="toctree-l3"><a class="reference internal" href="component_classes.html">Component Classes</a></li>
<li class="toctree-l3 current"><a class="current reference internal" href="#">Creating Your Own Component</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#creating-the-maya-file">Creating the Maya File</a></li>
<li class="toctree-l4"><a class="reference internal" href="#joint-mover-markup-tool">Joint Mover Markup Tool</a></li>
<li class="toctree-l4"><a class="reference internal" href="#creating-the-python-class">Creating the Python Class</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../utilities/utilities.html">Utilities</a></li>
<li class="toctree-l2"><a class="reference internal" href="../rigging_tools/rigging_tools.html">Rigging Tools</a></li>
<li class="toctree-l2"><a class="reference internal" href="../running_tests.html">Running Tests</a></li>
</ul>
</li>
</ul>

            
          
        </div>
        
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" aria-label="top navigation">
        
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="../../../index.html">ARTv2</a>
        
      </nav>


      <div class="wy-nav-content">
        
        <div class="rst-content">
        
          















<div role="navigation" aria-label="breadcrumbs navigation">

  <ul class="wy-breadcrumbs">
    
      <li><a href="../../../index.html">Docs</a> &raquo;</li>
        
          <li><a href="../../../technical_documentation.html">Technical Documentation</a> &raquo;</li>
        
          <li><a href="components.html">Components</a> &raquo;</li>
        
      <li>Creating Your Own Component</li>
    
    
      <li class="wy-breadcrumbs-aside">
        
            
            <a href="../../../_sources/sections/tech_docs/components/creating_custom_component.rst.txt" rel="nofollow"> View page source</a>
          
        
      </li>
    
  </ul>

  
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
  <div class="section" id="creating-your-own-component">
<h1>Creating Your Own Component<a class="headerlink" href="#creating-your-own-component" title="Permalink to this headline"></a></h1>
<p><em>Code author: Jeremy Ernst</em></p>
<p>In order to create your own component, there are two things you need: a python file for the class, and a maya ascii
file that defines the joints that component can create.</p>
<div class="section" id="creating-the-maya-file">
<h2>Creating the Maya File<a class="headerlink" href="#creating-the-maya-file" title="Permalink to this headline"></a></h2>
<p>This file is generally referred to as the ‘joint mover file’. In a new Maya scene, simply create the joints you want
your component to create. If your component has options like number of twist joints, create the maximum configuration
in this Maya scene. The exception to this are components where we want to insert joints into the hierarchy, like the
chain and spine components. With these types of components, I create the minimum configuration. Let’s compare what the
joint mover files for a biped leg and a chain look like:</p>
<div class="align-center figure">
<a class="reference internal image-reference" href="../../../_images/joint_mover_compare.png"><img alt="../../../_images/joint_mover_compare.png" src="../../../_images/joint_mover_compare.png" style="width: 404px; height: 256px;" /></a>
</div>
<p>As you can see, the leg has the maximum configuration and the spine has the minimum configuration. How those
configurations change is defined in the properties of the python class. You’ll also notice that some default names
have been given to each joint.
In the leg, for example, I don’t want the twist joints to be available by default (their property will be set to 0),
so I will hide those joints.</p>
<p>Let’s build a component as a demonstration. In a new Maya scene, I will create a basic hinge setup for an arm and name
the joints shoulder, elbow, and wrist. Make sure the rotations are frozen and the joint orients are clean.</p>
<img alt="../../../_images/joint_mover_demo_01.png" src="../../../_images/joint_mover_demo_01.png" />
<p>Now, I will add three twist joints to the shoulder, naming them shoulder_twist_01, shoulder_twist_02, and
shoulder_twist_03. These are parented under the shoulder. Because I don’t want them to be there by default, I will
hide them.</p>
<img alt="../../../_images/joint_mover_demo_01.gif" src="../../../_images/joint_mover_demo_01.gif" />
<p>The last thing we need to do with the maya scene is markup these joints with some attributes for how the joint mover
rig will be created.</p>
</div>
<div class="section" id="joint-mover-markup-tool">
<span id="joint-mover-markup-ref"></span><h2>Joint Mover Markup Tool<a class="headerlink" href="#joint-mover-markup-tool" title="Permalink to this headline"></a></h2>
<p>Under the ART v2 menu, in the Development sub-menu, click on the Joint Mover Markup menu item.</p>
<img alt="../../../_images/joint_mover_markup_01.png" src="../../../_images/joint_mover_markup_01.png" />
<p>Once the interface is displayed, clicking on ‘Markup Joints’ will put attributes on all of the joints in the scene.
Let’s talk about each of these attributes and what they do.</p>
<div class="align-center figure" id="id1">
<a class="reference internal image-reference" href="../../../_images/joint_mover_markup_02.png"><img alt="../../../_images/joint_mover_markup_02.png" src="../../../_images/joint_mover_markup_02.png" style="width: 263px; height: 348px;" /></a>
<p class="caption"><span class="caption-text">The markup attributes that were created can be seen here.</span></p>
</div>
<dl class="glossary docutils">
<dt id="term-can-aim">Can Aim</dt>
<dd>Whether this joint should aim at another joint when aim mode is turned on.</dd>
<dt id="term-aim-joint">Aim Joint</dt>
<dd>Which joint this joint should aim at when aim mode is turned on. (This is ignored if Can Aim is False)</dd>
<dt id="term-aim-axis">Aim Axis</dt>
<dd>Which axis represents the aim axis. (This is ignored if Can Aim is False)</dd>
<dt id="term-invert-aim-axis">Invert Aim Axis</dt>
<dd>If the aim axis should be inverted. (If your aim axis is set to X, but needs to be -X, this would be True)
(This is ignored if Can Aim is False)</dd>
<dt id="term-up-axis">Up Axis</dt>
<dd>The axis of the joint that is closes to the world up axis. (This is ignored if Can Aim is False)</dd>
<dt id="term-maintain-offset">Maintain Offset</dt>
<dd>This will probably not ever need to be used, but in the case of some special circumstance, this will create the
aim constraint while maintaining offsets.
(This is ignored if Can Aim is False)</dd>
<dt id="term-twist-joint">Twist Joint</dt>
<dd>Whether the joint is to be setup as a twist joint. A twist joint gets no global mover control. Instead it
gets an offset mover that is only unlocked along the length axis, and is automatically driven to keep equal
spacing between the start joint and end joint (calf and foot for example).</dd>
<dt id="term-control-type">Control Type</dt>
<dd>The shape that the joint mover control should have. This list is populated by the files located in
/resources/control_shapes.</dd>
<dt id="term-control-size">Control Size</dt>
<dd>The scale factor to create the control at. If you use the “Create Preview Movers” button in the markup tool,
you can then set this value in order to see how the control will be built and at what size.</dd>
<dt id="term-control-offset-x-y-z">Control Offset X, Y, Z</dt>
<dd>When creating the control, the rotational offset to apply on creation. You can use the “Create Preview Movers”
button to see how the control will be created given your offsets.</dd>
</dl>
<p>So in this case, let’s set shoulder and elbow’s “.canAim” to True, then set the shoulder’s aim joint to elbow, and the
elbow’s to wrist. The up axis for both of those will be Z. I’ll set all three of those joints to use a circle shape and
set the size to 10. For the three twist joints, set their “.twistJoint” attribute to True, and let’s put their control
size at 8. You can use the “Create Preview Movers” and “Delete Preview Movers” to see how your controls will be created
given these settings.</p>
<div class="align-center figure" id="id2">
<a class="reference internal image-reference" href="../../../_images/joint_mover_markup_03.png"><img alt="../../../_images/joint_mover_markup_03.png" src="../../../_images/joint_mover_markup_03.png" style="width: 265px; height: 348px;" /></a>
<p class="caption"><span class="caption-text">The shoulder with markup data set.</span></p>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Create Preview Movers works on a selection!</p>
</div>
<p>Make sure any preview movers have been deleted using the “Delete Preview Movers” and save the scene in:
ARTv2/resources/rigging_guides as a maya ascii file.</p>
</div>
<div class="section" id="creating-the-python-class">
<h2>Creating the Python Class<a class="headerlink" href="#creating-the-python-class" title="Permalink to this headline"></a></h2>
<p>Create a new python file in artv2/components. In this file, add an import for the base component:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">artv2.components.base_components.base_component</span> <span class="kn">as</span> <span class="nn">base</span>
</pre></div>
</div>
<p>Now create your class and inherit from base. There are some attributes you need to add to the class (above any
constructor) and fill out their values. These are the attributes and what they do:</p>
<blockquote>
<div><table border="1" class="docutils">
<colgroup>
<col width="11%" />
<col width="21%" />
<col width="68%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Type</th>
<th class="head">Name</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>attribute</td>
<td>nice_name</td>
<td>(string) The nice name of the component (as it will appear in UIs)</td>
</tr>
<tr class="row-odd"><td>attribute</td>
<td>category</td>
<td>(string) The name of the category where this component will show up in the
user interface. For example: “Limbs”, “Primitives”, etc.</td>
</tr>
<tr class="row-even"><td>attribute</td>
<td>base_name</td>
<td>The string base name of the component. This is a simple string used to
identify the component type and append onto nodes created by the component.
For example, on a leg component, the base_name is simply: “leg”</td>
</tr>
<tr class="row-odd"><td>attribute</td>
<td>has_sides</td>
<td>Bool for whether or not the component supports different sides,like a leg
or arm do.</td>
</tr>
<tr class="row-even"><td>attribute</td>
<td>can_overwrite_names</td>
<td>Bool for whether or not the user can overwrite the names of the joints of
this component.</td>
</tr>
<tr class="row-odd"><td>attribute</td>
<td>joint_mover_file</td>
<td>The relative path from the ARTv2 directory to the joint mover file of the
component. For example, self.joint_mover_file =
“resources/rigging_guides/root.ma”</td>
</tr>
<tr class="row-even"><td>attribute</td>
<td>mirror_table</td>
<td>A dictionary of translate and rotate attributes with their multiplier for
mirroring values to mirrored controls.</td>
</tr>
</tbody>
</table>
</div></blockquote>
<p>At this point, your class should look something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">artv2.components.base_components.base_component</span> <span class="kn">as</span> <span class="nn">base</span>

<span class="k">class</span> <span class="nc">MyComponent</span><span class="p">(</span><span class="n">base</span><span class="o">.</span><span class="n">ART_Component</span><span class="p">):</span>

    <span class="n">nice_name</span> <span class="o">=</span> <span class="s2">&quot;Test&quot;</span>
    <span class="n">category</span> <span class="o">=</span> <span class="s2">&quot;Primitives&quot;</span>
    <span class="n">base_name</span> <span class="o">=</span> <span class="s2">&quot;test&quot;</span>
    <span class="n">has_sides</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="n">can_overwrite_names</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="n">joint_mover_file</span> <span class="o">=</span> <span class="s2">&quot;resources</span><span class="se">\\</span><span class="s2">rigging_guides</span><span class="se">\\</span><span class="s2">test.ma&quot;</span>
    <span class="n">mirror_table</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;translateX&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;translateY&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;translateZ&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;rotateX&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;rotateY&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;rotateZ&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span>
</pre></div>
</div>
<p>Usually, you will not need to implement an __init__ method, since the base class should take care of anything you need
there, but if not, you would want to implement that, and make sure you call on the base class’s constructor as well.</p>
<p>The main method you need to implement is _add_metadata. This method adds attributes to the network node of the component
that coincide with properties on the class. For example, in our test, we had three twist joints, so I could add a
property called num_twist_joints. There are already some methods in the base class that will help with the property
setter implementation ( we’ll go over that in a minute). Because we will be adding this property, we also want to add
an attribute on the network node for num_twist_joints. So in this example, here is what our _add_metadata method would
look like:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">_add_metadata</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">network_node</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">suffix</span><span class="p">):</span>

    <span class="c1"># call on the base class&#39;s method to get the default attributes first, then unlock the network node and add our</span>
    <span class="c1"># own. Remember to re-lock the network node after!</span>
    <span class="nb">super</span><span class="p">(</span><span class="n">MyComponent</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_add_metadata</span><span class="p">(</span><span class="n">network_node</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">suffix</span><span class="p">)</span>

    <span class="n">network_node</span><span class="o">.</span><span class="n">unlock</span><span class="p">()</span>

    <span class="c1"># notice how the minimum and maximum are set to match our configuration on the maya file. Since our twist joints</span>
    <span class="c1"># are hidden by default, the default value is 0.</span>
    <span class="n">network_node</span><span class="o">.</span><span class="n">addAttr</span><span class="p">(</span><span class="s2">&quot;num_twist_joints&quot;</span><span class="p">,</span> <span class="nb">min</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">dv</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">keyable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
    <span class="n">network_node</span><span class="o">.</span><span class="n">num_upperarm_twists</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">lock</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

    <span class="n">network_node</span><span class="o">.</span><span class="n">lock</span><span class="p">()</span>
</pre></div>
</div>
<p>Now let’s define that property that coincides with our attribute.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@property</span>
<span class="k">def</span> <span class="nf">num_twist_joints</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>

    <span class="c1"># the getter of our property will just read the value on the network node of the same attribute!</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">network_node</span><span class="o">.</span><span class="n">num_twist_joints</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
</pre></div>
</div>
<p>Our property setter is where the implementation of any configuration changes happens. The base class already has a
method for dealing with this situation, so our setter is pretty simple here:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@num_upperarm_twists.setter</span>
<span class="k">def</span> <span class="nf">num_upperarm_twists</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_number</span><span class="p">):</span>
    <span class="c1"># here we pass in the attribute, the new number, the min and max, and a keyword to search for on the joints.</span>
    <span class="c1"># because our joints are named shoulder_twist_01, etc, we can pass in the key _shoulder_twist_0 to find any</span>
    <span class="c1"># relevant twist joints.</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">set_twist_joints</span><span class="p">(</span><span class="s2">&quot;num_twist_joints&quot;</span><span class="p">,</span> <span class="n">new_number</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&quot;_shoulder_twist_0&quot;</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">To see a more complex implementation of a property setter, check out the chain component’s num_joints
property.</p>
</div>
<p>At this point, you should be able to reload the scripts (or restart Maya) and your component should be in the UI, and
properly load into the scene, creating a joint mover rig, and a widget for changing your properties.</p>
</div>
</div>


           </div>
           
          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="../utilities/utilities.html" class="btn btn-neutral float-right" title="Utilities" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="camera.html" class="btn btn-neutral float-left" title="Camera Component" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 2018, Jeremy Ernst

    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. 

</footer>

        </div>
      </div>

    </section>

  </div>
  


  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script>

  
  
    
   

</body>
</html>