forked from jesterKing/rhipy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchange_texture_filepath.html
113 lines (104 loc) · 5.69 KB
/
change_texture_filepath.html
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
<html>
<head>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<h1>Change texture file path</h1>
<p><em>written by Nathan 'jesterKing' Letwory</em></p>
<h2>Introduction</h2>
<p>TLDR; the generated script is
<a href="https://github.com/jesterKing/rhipy/blob/master/change_texture_filepath.py">here</a>.</p>
<p>In this script we'll retarget all image texture paths to a new path. We'll
iterate over all <code>RenderMaterial</code>s and find all the image based textures.</p>
<p>To actually change the file paths we need to use the <code>SetParameter</code> method on
each texture we find.</p>
<p>In this script you'll see how to:</p>
<ul>
<li>Iterate the RenderMaterial table</li>
<li>Use <code>rhinoscriptsyntax</code> to browse for a folder</li>
<li>Use <code>GetParameter</code> in conjunction with <code>System.Convert</code></li>
<li>Use <code>SetParameter</code> to change values on <code>RenderContent</code></li>
<li>Bracket changes properly with <code>BeginChange</code> and <code>EndChange</code></li>
</ul>
<h2>Changing the file path</h2>
<p>We will handle all <code>RenderContent</code> that are image-based. Since a
<code>RenderContent</code>, including <code>RenderTexture</code>s can have child content we need to
recurse through the entire ancestry to ensure we handle all cases.</p>
<p>We start by asking for the first child content of the given <code>RenderContent</code>. It
will be an instance of some <code>RenderContent</code> if there is anything, otherwise
<code>None</code>. For each child content we handle we'll recurse, then when back we make
the change and finally ask for the next sibling.</p>
<p>To make the change we first get the current filename of the child
<code>RenderContent</code>. We need to use the <code>GetParameter</code> method to retrieve the value.
There is one important issue to take note of: <code>GetParameter</code> returns values as
<code>object</code>s. These implement the <code>IConvertible</code> interface. To get to the actual
data we need to somehow convert this. A straight cast is not possible, but we
can use the <code>Convert</code> mechanism. We know we need a string so we can use
<code>System.Convert.ToString</code>.</p>
<p>For changes to stick on <code>RenderContent</code> in Rhino we need to bracket them between
proper <code>BeginChange</code> and <code>EndChange</code> calls on the content. For <code>BeginChange</code> we
give the <code>Program</code> change context, since we are changing the data through the
script.</p>
<div class="codefragment">
<div class="fragmentname"><<method to handle render content>>=</div>
<div class="code">
<pre><code><span class="hljs-keyword">def</span> <span class="hljs-title function_">handle_render_content</span>(<span class="hljs-params">render_content, target</span>):
child = render_content.FirstChild
<span class="hljs-keyword">while</span> child:
handle_render_content(child, target)
<span class="hljs-keyword">if</span> child.IsImageBased():
child.BeginChange(Rhino.Render.RenderContent.ChangeContexts.Program)
source_path = System.Convert.ToString(child.GetParameter(<span class="hljs-string">"filename"</span>))
source_file = os.path.basename(source_path)
child.SetParameter(<span class="hljs-string">"filename"</span>, target + os.sep + source_file)
child.EndChange()
child = child.NextSibling
</code></pre>
</div>
</div><h2>Iterating the render materials</h2>
<p>To iterate over all the <code>RenderMaterial</code>s available in our document we iterate over the <code>RhinoDoc</code> table called <code>RenderMaterials</code>:</p>
<div class="codefragment">
<div class="fragmentname"><<iterate over all rendermaterials>>=</div>
<div class="code">
<pre><code><span class="hljs-keyword">for</span> render_material <span class="hljs-keyword">in</span> scriptcontext.doc.RenderMaterials:
<<handle render content>>
</code></pre>
</div>
</div><h2>Handle each render material</h2>
<div class="codefragment">
<div class="fragmentname"><<handle render content>>=</div>
<div class="code">
<pre><code>handle_render_content(render_material, target)
</code></pre>
</div>
</div><h2>Ask the user for a target path</h2>
<div class="codefragment">
<div class="fragmentname"><<ask for target path>>=</div>
<div class="code">
<pre><code>target = rhinoscriptsyntax.BrowseForFolder()
</code></pre>
</div>
</div><h2>Binding it all together</h2>
<p>Since we need to use <code>GetParameter</code> on a <code>RenderContent</code> it is important that we
convert the data we get to the correct data type. <code>GetParameter</code> returns an
<code>object</code> that implements the <code>IConvertible</code> interface. We can't directly cast
from this object, instead we have to use the <code>Convert</code> mechanism. For this we
import the <code>System.Convert</code>.</p>
<p>For the folder choose dialog we import <code>rhinoscriptsyntax</code>, and to access the
<code>RenderMaterial</code> table of the document we import <code>scriptcontext</code>.</p>
<div class="codefragment">
<div class="fragmentname"><<change texture filepath.*>>=</div>
<div class="code">
<pre><code><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> rhinoscriptsyntax
<span class="hljs-keyword">import</span> scriptcontext
<span class="hljs-keyword">import</span> Rhino.Render
<span class="hljs-keyword">import</span> System.Convert
<<method to handle render content>>
<<ask <span class="hljs-keyword">for</span> target path>>
<<iterate over <span class="hljs-built_in">all</span> rendermaterials>>
</code></pre>
</div>
</div>
</body>
</html>