blender-geometry-script/api/basics/sockets.html

341 wiersze
20 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="coal" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Sockets - Geometry Script</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../../highlight.css">
<link rel="stylesheet" href="../../tomorrow-night.css">
<link rel="stylesheet" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../style.css">
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "coal" : "coal";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('coal')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../../introduction.html">Introduction</a></li><li class="chapter-item expanded affix "><li class="part-title">Setup</li><li class="chapter-item expanded "><a href="../../setup/installation.html"><strong aria-hidden="true">1.</strong> Installation</a></li><li class="chapter-item expanded "><a href="../../setup/internal-editing-basics.html"><strong aria-hidden="true">2.</strong> Internal Editing Basics</a></li><li class="chapter-item expanded "><a href="../../setup/external-editing.html"><strong aria-hidden="true">3.</strong> External Editing</a></li><li class="chapter-item expanded affix "><li class="part-title">API</li><li class="chapter-item expanded "><a href="../../api/basics.html"><strong aria-hidden="true">4.</strong> Basics</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../api/basics/modules.html"><strong aria-hidden="true">4.1.</strong> Modules</a></li><li class="chapter-item expanded "><a href="../../api/basics/tree-functions.html"><strong aria-hidden="true">4.2.</strong> Tree Functions</a></li><li class="chapter-item expanded "><a href="../../api/basics/sockets.html" class="active"><strong aria-hidden="true">4.3.</strong> Sockets</a></li><li class="chapter-item expanded "><a href="../../api/basics/using-nodes.html"><strong aria-hidden="true">4.4.</strong> Using Nodes</a></li></ol></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting.html"><strong aria-hidden="true">5.</strong> Advanced Scripting</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../api/advanced-scripting/node-groups.html"><strong aria-hidden="true">5.1.</strong> Node Groups</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/generators.html"><strong aria-hidden="true">5.2.</strong> Generators</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/input-groups.html"><strong aria-hidden="true">5.3.</strong> Input Groups</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/attributes.html"><strong aria-hidden="true">5.4.</strong> Attributes</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/boolean-math.html"><strong aria-hidden="true">5.5.</strong> Boolean Math</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/curves.html"><strong aria-hidden="true">5.6.</strong> Curves</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/drivers.html"><strong aria-hidden="true">5.7.</strong> Drivers</a></li><li class="chapter-item expanded "><a href="../../api/advanced-scripting/simulation.html"><strong aria-hidden="true">5.8.</strong> Simulation</a></li></ol></li><li class="chapter-item expanded "><li class="part-title">Tutorials</li><li class="chapter-item expanded "><a href="../../tutorials/voxelize.html"><strong aria-hidden="true">6.</strong> Voxelize</a></li><li class="chapter-item expanded "><a href="../../tutorials/city-builder.html"><strong aria-hidden="true">7.</strong> City Builder</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Geometry Script</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="sockets"><a class="header" href="#sockets">Sockets</a></h1>
<p>Because scripts are converted to Geometry Node trees, you typically cannot use default Python types as arguments. In some cases, they will be automatically converted for you, but in general you will be dealing with socket types.</p>
<h2 id="what-is-a-socket"><a class="header" href="#what-is-a-socket">What is a socket?</a></h2>
<p>A socket is any input or output on a node. Take the <em>Cube</em> node for example:</p>
<p><img src="./cube_node.png" alt="" /></p>
<p>This node has 4 input sockets, and 1 output socket.</p>
<ul>
<li>Input Sockets
<ul>
<li>Size: <code>Vector</code></li>
<li>Vertices X: <code>Int</code></li>
<li>Vertices Y: <code>Int</code></li>
<li>Vertices Z: <code>Int</code></li>
</ul>
</li>
<li>Output Sockets
<ul>
<li>Mesh: <code>Geometry</code></li>
</ul>
</li>
</ul>
<p>A socket does not represent a value itself. For example, the <code>Size</code> socket does not necessarily represent the value <code>(1, 1, 1)</code>. Instead, it can be connected to another node as an input, giving it a dynamic value.</p>
<p>When we write scripts, we typically deal with socket types, not concrete values like <code>(1, 1, 1)</code>. Take this script for example:</p>
<pre><code class="language-python">@tree(&quot;Cube Tree&quot;)
def cube_tree(size: Vector):
return cube(size=size)
</code></pre>
<p>The <code>size</code> argument creates a input socket with the type <code>Vector</code>. This is then connected to the <code>size</code> socket of the <em>Cube</em> node.</p>
<p><img src="./cube_tree_size.png" alt="" /></p>
<p>Our script does not run every time the node tree is evaluated. It only runs once to create the node tree. Therefore, we have no way of knowing what value <code>size</code> has when the script runs, because it is dynamic.</p>
<h2 id="what-sockets-can-do"><a class="header" href="#what-sockets-can-do">What sockets <em>can</em> do</a></h2>
<p>Sockets are great for passing values between nodes. A socket type like <code>Geometry</code> does not represent concrete vertices, edges, and faces. Instead, it represents the input or output socket of a node. This lets us use it to create connections between different nodes, by passing the output of one node to the input of another.</p>
<h2 id="what-sockets-cannot-do"><a class="header" href="#what-sockets-cannot-do">What sockets <em>cannot</em> do</a></h2>
<p>Sockets cannot be read for their concrete value. A <code>Float</code> socket type does not equal <code>5</code> or <code>10</code> or <code>3.14</code> to our script. It only represents the socket of a node. If you try to <code>print(...)</code> a socket, you will receive a generic reference type with no underlying value.</p>
<h2 id="why-use-sockets"><a class="header" href="#why-use-sockets">Why use sockets?</a></h2>
<p>You might be wondering, &quot;if you can't access the value of a socket, what can you do with it?&quot;</p>
<p>Geometry Script provides many helpful additions that make working with sockets about as easy as working with a concrete value.</p>
<h2 id="socket-math"><a class="header" href="#socket-math">Socket Math</a></h2>
<p>Socket types can be used to perform math operations. The proper <em>Math</em> node will be created automatically for you, so you can focus on writing a script and not thinking about sockets. If you use <code>Float</code> or <code>Int</code> it will create a <em>Math</em> node, and if you use a <code>Vector</code> it will create a <em>Vector Math</em> node.</p>
<pre><code class="language-python">@tree(&quot;Cube Tree&quot;)
def cube_tree(size: Vector):
doubled = size * (2, 2, 2) # Multiply each component by 2
return cube(size=doubled)
</code></pre>
<p><img src="./cube_tree_size_double.png" alt="" /></p>
<p>Several common math operations are available, such as:</p>
<ul>
<li>Add (<code>socket + 2</code>)</li>
<li>Subtract (<code>socket - 2</code>)</li>
<li>Multiply (<code>socket * 2</code>)</li>
<li>Divide (<code>socket / 2</code>)</li>
<li>Modulo (<code>socket % 2</code>)</li>
</ul>
<h2 id="socket-comparison"><a class="header" href="#socket-comparison">Socket Comparison</a></h2>
<p>Socket types can be compared with Python comparison operators. A <em>Compare</em> node will be created with the correct inputs and options specified.</p>
<pre><code class="language-python">@tree(&quot;Cube Tree&quot;)
def cube_tree(size: Vector):
show_cube = size &gt; (2, 2, 2) # Check if each component is greater than 2
return cube(size=show_cube)
</code></pre>
<p><img src="./cube_tree_size_compare.png" alt="" /></p>
<p>Several common comparison operators are supported, such as:</p>
<ul>
<li>Equal To (<code>socket == 2</code>)</li>
<li>Not Equal To (<code>socket != 2</code>)</li>
<li>Less Than (<code>socket &lt; 2</code>)</li>
<li>Less Than Or Equal To (<code>socket &lt;= 2</code>)</li>
<li>Greater Than (<code>socket &gt; 2</code>)</li>
<li>Greater Than Or Equal To (<code>socket &gt;= 2</code>)</li>
</ul>
<h2 id="vector-component-properties"><a class="header" href="#vector-component-properties">Vector Component Properties</a></h2>
<p>While the <code>Vector</code> type does not equate to three concrete components, such as <code>(1, 2, 3)</code>, you can still access the <code>x</code>, <code>y</code>, and <code>z</code> components as sockets. A <em>Separate XYZ</em> node will be created with the correct inputs and outputs specified.</p>
<pre><code class="language-python">@tree(&quot;Cube Tree&quot;)
def cube_tree(size: Vector):
height = size.z # Access the Z component
# Multiply the height by 2 but leave the other components unchanged.
return cube(size=combine_xyz(x=size.x, y=size.y, z=height * 2))
</code></pre>
<p>For each component access, a <em>Separate XYZ</em> node is created.</p>
<p><img src="./cube_tree_size_components.png" alt="" /></p>
<h2 id="chained-calls"><a class="header" href="#chained-calls">Chained Calls</a></h2>
<p>Any node function can be called on a socket type. This will automatically connect the socket to the first input of the node.</p>
<pre><code class="language-python">@tree(&quot;Cube Tree&quot;)
def cube_tree(size: Vector):
return cube(size=size).mesh_to_volume()
</code></pre>
<p>The output of the <em>Cube</em> node (a <code>Geometry</code> socket type) is connected to the first input of the <em>Mesh to Volume</em> node.</p>
<p><img src="./cube_tree_mesh_to_volume.png" alt="" /></p>
<p>The same script without chaining calls is written more verbosely as:</p>
<pre><code class="language-python">@tree(&quot;Cube Tree&quot;)
def cube_tree(size: Vector):
return mesh_to_volume(mesh=cube(size=size))
</code></pre>
<h3 id="spanning-multiple-lines"><a class="header" href="#spanning-multiple-lines">Spanning Multiple Lines</a></h3>
<p>Often times you want each chained calls to be on a separate line. There are a few ways to do this in Python:</p>
<ol>
<li>Newlines around arguments</li>
</ol>
<pre><code class="language-python">cube(
size=size
).mesh_to_volume()
</code></pre>
<ol start="2">
<li>Parentheses</li>
</ol>
<pre><code class="language-python">(cube(size=size)
.mesh_to_volume())
</code></pre>
<ol start="3">
<li>Line continuation</li>
</ol>
<pre><code class="language-python">cube(size=size) \
.mesh_to_volume()
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../api/basics/tree-functions.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../api/basics/using-nodes.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../api/basics/tree-functions.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../api/basics/using-nodes.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../../elasticlunr.min.js"></script>
<script src="../../mark.min.js"></script>
<script src="../../searcher.js"></script>
<script src="../../clipboard.min.js"></script>
<script src="../../highlight.js"></script>
<script src="../../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>